问题描述:

My issue is how to implement selectively loading spring beans at the start of an web application.

Background

Our application is based on J2EE and Spring. We run the same web application on different managed servers. On some of these managed servers, we only run web service but on others, we also need to run services such as reporting, scheduler and etc. All these services are configured as spring bean in spring configuration xml files. So we'd like to disable some unused beans when start servers with web service.

Problems,

I tried to override method of customizeContext in org.springframework.web.context.ContextLoaderListener to remove those unused beans from context. (I know this is not a good idea to remove loaded beans instead of stopping them being loaded at the first place. that's because I couldn't figure out how to implement that as well) However, I got java.lang.IllegalStateException: BeanFactory not initialized or already closed - call 'refresh' before accessing beans via the ApplicationContext.

After some investigation, I get that BeanFactory can't be used here but I'm kind of stuck and don't know how to implement this function. Can anyone help me out of this please? Either stopping loading beans into Spring at start time or removing beans from Spring when it is just started would work for me.

The following is my code to override Method customizeContext.

@Override

protected void customizeContext(ServletContext servletContext, ConfigurableWebApplicationContext applicationContext) {

super.customizeContext(servletContext, applicationContext);

ConfigurableListableBeanFactory configurableListableBeanFactory = applicationContext.getBeanFactory();

BeanDefinitionRegistry beanDefinitionRegistry = (BeanDefinitionRegistry) configurableListableBeanFactory;

beanDefinitionRegistry.removeBeanDefinition("testBean");

}

网友答案:

Instead of trying to configure the BeanFactory after loading all the beans, you should have groups of beans and load only the groups related to actual running services.

The legacy method was to have intermediate XML files containing imports for other files containing what I called above groups of beans, and in main XML file, import the correct one. Extract from Spring Reference Manual : relying on a combination of system environment variables and XML statements containing ${placeholder} tokens that resolve to the correct configuration file path depending on the value of an environment variable

But now the tool of choice should be the profiles. You put the beans in different profiles corresponding to your services

@Bean
@Profile("production")
public DataSource productionDataSource() throws Exception {

or in XML

<beans profile="production">
    <jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/datasource"/>
</beans>

You have just to enable relevant profiles, either programmaticaly :

AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.getEnvironment().setActiveProfiles("dev");

or even as JVM properties :

-Dspring.profiles.active="profile1,profile2"

References : Chapter Environment Abstraction in Spring Reference Manual.

网友答案:

Thanks for the suggestions from Serge and the other guys. We are currently using 3.0.5 so can't really use the 3.1 profiles feature in our project.

We figured out a way to do it by adding a BeanFactoryPostProcessor to the ConfigurableWebApplicationContext in the method customizeContext. It seems to have solved our problems.

Code changes are:

protected void customizeContext(ServletContext servletContext, ConfigurableWebApplicationContext applicationContext) {
    super.customizeContext(servletContext, applicationContext);
    applicationContext.addBeanFactoryPostProcessor(new BootProcessor());

}

class BootProcessor implements BeanFactoryPostProcessor{

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory clbf) throws BeansException {
        BeanDefinitionRegistry beanDefinitionRegistry = (BeanDefinitionRegistry) clbf;
        beanDefinitionRegistry.removeBeanDefinition("testerBean");


    }

}
相关阅读:
Top