简体   繁体   中英

Spring add external spring context at runtime

We have a homepage that contains multiple components (widgets), kinda like a portal containing portlets. Some of these widgets will be delivered ad jars from other teams and some of those will require some custom beans to be managed by Spring. One solution might be to import spring contexts using the import statement with I wildcard (eg import all contexts in the classpath matching context-widget-*.xml).

However, I prefer a more programmatic solution where I check for each widget which context they need loaded (from the classpath). I did not find any blog or such that explains this but did find some posts on forums that explain that this would be a parent-child context and this will only be unidirectional; unfortunately in my case it needs to be bidirectional.

So after some browsing in the API I managed to come up with something working but I am not confident it is a good solution or it there are any pitfalls I did not think about. Perhaps there is another (better) solution for this scenario?

public class WidgetManager implements ApplicationContextAware
{

    @Autowired
    private WidgetService widgetService;

    @Override
    public void setApplicationContext(ApplicationContext parentApplicationContext) throws BeansException {
        //I do need the parent context to have finished initializing beans
        List<WidgetTO> widgets = widgetService.findAllWidgets();

        List<String> contexts = newArrayListWithCapacity(widgets.size());
        for (WidgetTO widget : widgets) {
            if (isNotBlank(widget.getSpringContext())) {
                contexts.add(widget.getSpringContext());
            }
        }

        AbstractRefreshableWebApplicationContext parentContext = (AbstractRefreshableWebApplicationContext) parentApplicationContext;

        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(contexts.toArray(new String[] {}), parentApplicationContext);
        String[] singletonNames = context.getBeanFactory().getSingletonNames();
        for (String s : singletonNames) {
            //copy all singletons that don't already exist from child to parent
            if (!parentContext.getBeanFactory().containsSingleton(s)) {
                parentContext.getBeanFactory().registerSingleton(s, context.getBeanFactory().getSingleton(s));
            }
        }

    }
}

This is actually exactly how I did it. We have been using this fashion for over 3 years and never had issues.

You might be able to use AutowireCapableBeanFactory. This class lets you add beans to your existing Spring context. It will instantiate beans and inject their dependencies.

http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/beans/factory/config/AutowireCapableBeanFactory.html

I'm not sure I understand the "bidirectional" context thing you're talking about. Do you need your primary context beans to have dependencies on beans from the "child"/additional contexts? If so, wildcard imports are probably your best bet, even if you don't prefer that solution.

It might be helpful if you explained in a little more detail your overall application lifecycle, describing the stages for your "parent"/primary context and your "child"/additional contexts.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM