【问题标题】:Spring add some beans to service context in RuntimeSpring在运行时向服务上下文添加一些bean
【发布时间】:2016-04-18 23:53:09
【问题描述】:

我正在创建 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>());
        }
    }

}

我用这种方式创建了那个 bean:

<bean id="myDispatcher" class="some.package.MyDispatcherBean " />

然后在我的代码中的任何地方都可以存在任意数量的带有获取“myDispatcher”bean的代码的bean,并在运行时将一些bean添加到DispatcherServlet的servlet上下文中:

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;
    }
}

这些 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>

最后,我期望行为:每个 ContextAdder bean 将新 bean 添加到 myDispatcher bean 中 dispatcherServlet 的 servlet 上下文中。

但我害怕某些时刻:

  1. 这个问题只有一个决定吗?
  2. 这是最好的吗?
  3. 每次我向 DispatcherServlet 的 servletContext 添加新 bean 时,它会调用 ServletContext 甚至 ApplicationContext 的刷新吗?如果是真的 - 它对性能有影响吗?
  4. 所有生命周期都正确吗?

【问题讨论】:

    标签: java spring servlets initialization javabeans


    【解决方案1】:

    我相信有更好的方法,但由您决定。

    使用您的方法(实现 InitializingBean),您将在 bean 定义阶段完成并且 构建 bean 之后调用 bean 创建代码。您的 bean 定义阶段非常简单(只需创建“myDispatcher”)。

    我建议您在 bean 定义阶段创建/加载所有 bean 定义。实现此目的的一种方法是挂钩到 BeanFactory 后处理器(实现 BeanFactoryPostProcessor)。在这个阶段,Spring 允许您修改现有的 bean 定义,更重要的是,您可以添加更多的 bean 定义。现在,当您离开此阶段时,所有 bean 都将在一个阶段中创建。该方法非常自然:创建 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""));
        .....
    }
    

    也许您可以将此概念用于您的独特需求。

    【讨论】:

    • 如果我在 postProcessBeanFactory 中将 bean 添加到 servlet 上下文(不在应用程序上下文中),它会处于一个阶段吗?
    • 是的。每个上下文都有机会在定义阶段参与 BeanFactoryPostProcessor。
    • 当我在 ApplicationContext 中创建 ContextAdder bean - ServletContext 未初始化。我应该在启动的 servlet 上下文(调度程序 servlet 的 servlet 上下文)中创建 ContextAdder bean吗?
    • 你使用web.xml,还是新方法:实现WebApplicationInitializer? servlet 上下文应该以这两种方式之一启动,然后使用 loadBeanDefinitions。
    • 我无法访问 web.xml.... :( 我以编程方式创建 Dispatcher。那么是否可以通过这种方式将 bean 添加到 servlet 上下文中?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-11
    • 2017-08-20
    • 1970-01-01
    • 1970-01-01
    • 2013-04-12
    相关资源
    最近更新 更多