代码之家  ›  专栏  ›  技术社区  ›  Иван Волынчук

Spring在Runtime中向服务上下文添加一些bean

  •  0
  • Иван Волынчук  · 技术社区  · 9 年前

    我正在创建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 " />
    

    然后,在我的代码中的任何位置都可以存在任意数量的bean,这些bean的代码可以获取“myDispatcher”bean,并在Runtime中将一些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>
    

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

    但我害怕一些时刻:

    1. 这只是这个问题的一个决定吗?
    2. 这是最好的吗?
    3. 每次我向DispatcherServlet的servletContext添加新bean时,它会调用servletContext甚至ApplicationContext的刷新吗?如果是真的,它会影响性能吗?
    4. 所有生命周期都正确吗?
    1 回复  |  直到 9 年前
        1
  •  1
  •   Ian Mc    9 年前

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

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

    我建议您在bean定义阶段创建/加载所有bean定义。实现这一点的一种方法是挂接到BeanFactory后处理器(实现BeanFacctoryPostProcessor)。在这个阶段,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""));
        .....
    }
    

    也许你可以根据你的独特需求采用这个概念。