4

I want to use Spring inside a legacy application.

The core piece is a class, let's call it LegacyPlugin, that represents a sort of pluggable piece in the application. The problem is that this class is also the database connector, and is used to create lots of other objects, often via constructor injection...

I want to launch an ApplicationContext from the LegacyPlugin, and inject it into the ApplicationContext, via a BeanFactory for example, to create the other objects. The code will then be rewritten, to use setter injection & so on.

I would like to know what is the best way to achieve this. So far, I have a working version using a BeanFactory that uses a ThreadLocal to hold a static reference to the plugin currently executed, but it seems ugly to me...

Below is the code I would like to end up with :

public class MyPlugin extends LegacyPlugin {

    public void execute() {
        ApplicationContext ctx = new ClassPathXmlApplicationContext();
        // Do something here with this, but what ?
        ctx.setConfigLocation("context.xml");
        ctx.refresh();
    }

 }

<!-- This should return the object that launched the context -->
<bean id="plugin" class="my.package.LegacyPluginFactoryBean" />

<bean id="someBean" class="my.package.SomeClass">
    <constructor-arg><ref bean="plugin"/></constructor-arg>
</bean>

<bean id="someOtherBean" class="my.package.SomeOtherClass">
    <constructor-arg><ref bean="plugin"/></constructor-arg>
</bean>
mexique1
  • 1,682
  • 11
  • 18
  • If you've got access to the classes into which you'd like to inject the application context? I'm not sure I understand the rationale behind each class holding onto the application context? – Fil Mar 29 '11 at 20:35
  • Basically, I want to get rid of lots of initialization code inside the plugin. – mexique1 Mar 30 '11 at 09:13

2 Answers2

4

The SingletonBeanRegistry interface allows you to manually inject a pre-configured singleton into the context via its registerSingleton method, like this:

ApplicationContext ctx = new ClassPathXmlApplicationContext();
ctx.setConfigLocation("context.xml");

SingletonBeanRegistry beanRegistry = ctx.getBeanFactory();
beanRegistry.registerSingleton("plugin", this);

ctx.refresh();

This adds the plugin bean to the context. You don't need to declare it in the context.xml file.

skaffman
  • 398,947
  • 96
  • 818
  • 769
  • Hmmm, useful, I didn't know BeanRegistry... But I would prefer to have it explicitly in the spring context file. – mexique1 Mar 30 '11 at 09:12
  • @mexique1: Why? What difference does it make? – skaffman Mar 30 '11 at 09:20
  • Hmmm... Sorry for the late acceptance. After all, I'm using @Service/@Component annotations on several projects, and this is more or less the same : you don't know how, but the bean is there. Thanks for your response. – mexique1 Apr 01 '11 at 15:01
0

Actually, this doesn't work... It causes the following error :

BeanFactory not initialized or already closed
call 'refresh' before accessing beans via the ApplicationContext

The final solution is to use GenericApplicationContext :

GenericApplicationContext ctx = new GenericApplicationContext();
ctx.getBeanFactory().registerSingleton("plugin", this);
new XmlBeanDefinitionReader(ctx).loadBeanDefinitions(
    new ClassPathResource("context.xml"));
ctx.refresh();
mexique1
  • 1,682
  • 11
  • 18