[英]Spring add some beans to service context in Runtime
I am creating spring dispatcherServlet and set his servlet context this way: 我正在创建spring dispatcherServlet并以这种方式设置他的servlet上下文:
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import java.io.IOException;
import java.util.*;
public class MyDispatcherBean implements InitializingBean {
@Autowired
private ApplicationContext applicationContext;
private DispatcherServlet dispatcherServlet;
private final String someContext = "some.xml";
private ServletContext servletContext;
public void execute(/* Do some code..*/) throws IOException {
/*
Do some code..
*/
try {
dispatcherServlet.service(/* ...*/);
} catch (ServletException e) {
}
}
public WebApplicationContext getServiceContext() {
return dispatcherServlet.getWebApplicationContext();
}
public void afterPropertiesSet() throws Exception {
dispatcherServlet = new DispatcherServlet() {
private static final long serialVersionUID = -7492692694742330997L;
@Override
protected WebApplicationContext initWebApplicationContext() {
WebApplicationContext wac = createWebApplicationContext(applicationContext);
if (wac == null) {
wac = super.initWebApplicationContext();
}
return wac;
}
};
dispatcherServlet.setContextConfigLocation(someContext);
dispatcherServlet.init(new DelegatingServletConfig());
}
private class DelegatingServletConfig implements ServletConfig {
public String getServletName() {
return "myDispatcher";
}
public ServletContext getServletContext() {
return MyDispatcherBean.this.servletContext;
}
public String getInitParameter(String paramName) {
return null;
}
public Enumeration<String> getInitParameterNames() {
return Collections.enumeration(new HashSet<String>());
}
}
}
And i create that bean this way: 然后我以这种方式创建该bean:
<bean id="myDispatcher" class="some.package.MyDispatcherBean " />
Then in any place in my code can exist any numbers of beans with code that get "myDispatcher" bean and add some beans in Runtime to servlet context of DispatcherServlet: 然后,在我的代码中的任何地方都可以存在任意数量的具有通过代码获取“ myDispatcher” bean并将其在运行时中添加到DispatcherServlet servlet上下文中的bean的bean:
public class ContextAdder implements InitializingBean {
@Autowired
private ApplicationContext applicationContext;
public String classPathToContext;
public void afterPropertiesSet() throws Exception {
DispatcherServlet dispatcherServlet = applicationContext.getBean("myDispatcher",DispatcherServlet.class);
XmlWebApplicationContext webApplicationContext = (XmlWebApplicationContext) dispatcherServlet.getWebApplicationContext();
XmlBeanDefinitionReader xmlReader = new XmlBeanDefinitionReader((DefaultListableBeanFactory) webApplicationContext.getBeanFactory());
xmlReader.loadBeanDefinitions(new ClassPathResource(classPathToContext));
}
public ApplicationContext getApplicationContext() {
return applicationContext;
}
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
public String getClassPathToContext() {
return classPathToContext;
}
public void setClassPathToContext(String classPathToContext) {
this.classPathToContext = classPathToContext;
}
}
These beans are created this way: 这些bean是通过以下方式创建的:
<bean id="adder1" class="stargate.sg_1.ContextAdder" depends-on="myDispatcher">
<property name="classPathToContext" value="Optimus.xml" />
</bean>
<bean id="adder2" class="stargate.atlantida.ContextAdder" depends-on="myDispatcher">
<property name="classPathToContext" value="StarShip.xml" />
</bean>
In finally I expect behaviour: each ContextAdder bean add new beans to servlet context of dispatcherServlet in myDispatcher bean. 最后,我期望有这样的行为:每个ContextAdder bean在myDispatcher bean中将新的bean添加到dispatcherServlet的servlet上下文中。
But i am afraid of some moments: 但是我害怕一些时刻:
I believe there is a better approach, but will leave it to you to decide. 我相信有更好的方法,但是由您自己决定。
With your approach (implements InitializingBean) you are invoking your bean creation code after the bean definitions phase has completed and after the beans are being constructed. 使用您的方法(实现InitializingBean),您将在Bean定义阶段完成之后以及在构建Bean之后调用Bean创建代码。 Your bean definition phase is very simple (just create "myDispatcher").
您的bean定义阶段非常简单(只需创建“ myDispatcher”)。
I would recommend that you create/load all your bean definitions during the bean definition phase. 我建议您在Bean定义阶段创建/加载所有Bean定义。 One way to achieve this is to instead hook into the BeanFactory post processor (implements BeanFactoryPostProcessor).
实现此目的的一种方法是挂接到BeanFactory后处理器(实现BeanFactoryPostProcessor)。 At this phase Spring lets you modify existing bean definitions and more importantly for you add further bean definitions.
在此阶段,Spring允许您修改现有的Bean定义,更重要的是,您可以添加更多的Bean定义。 Now when you leave this phase, all beans will then be created in one phase.
现在,当您离开此阶段时,将在一个阶段中创建所有bean。 The approach is very natural: bean definitions are created => beans are created and wired => Done.
这种方法很自然:创建bean定义=>创建并连接bean =>完成。
public class ContextAdder implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory factory)
throws BeansException {
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader((BeanDefinitionRegistry)factory);
// I) LOAD BY PATTERN MATCHING
//PathMatchingResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver(factory.getBeanClassLoader());
//for (Resource resource : resourceResolver.getResources("com/.../*.xml"))
//reader.loadBeanDefinitions(resource);
// II) LOAD A SINGLE FILE AT A TIME
reader.loadBeanDefinitions(new ClassPathResource("com/../Optimus.xml""));
.....
}
Perhaps you can adopt this concept to your unique requirement. 也许您可以按照自己的独特要求采用此概念。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.