views:

69

answers:

3

I have a singleton that has a spring injected Dao (simplified below):

public class MyService<T> implements Service<T> {
    private final Map<String, T> objects;
    private static MyService instance;

    MyDao myDao;

    public void set MyDao(MyDao myDao) {
        this. myDao = myDao;
    }

    private MyService() {
        this.objects = Collections.synchronizedMap(new HashMap<String, T>());
        // start a background thread that runs for ever
    }

    public static synchronized MyService getInstance() {
        if(instance == null) {
            instance = new MyService();
        }
        return instance;
    }

    public void doSomething() {
        myDao.persist(objects);
    }
}

My spring config will probably look like this:

 <bean id="service" class="MyService" factory-method="getInstance"/>

But this will instantiate the MyService during startup.

Is there a programmatic way to do a dependency injection of MyDao into MyService, but not have spring manage the MyService?

Basically I want to be able to do this from my code:

MyService.getInstance().doSomething();

while having spring inject the MyDao for me.

A: 

If you want a singleton, why not just define that one class in the Spring configs, and it's automatically a singleton (by default).

To avoid initialising at start up, have you looked at Spring lazy initialisation ? Basically you need:

lazy-init="true"

in your bean definition.

Brian Agnew
And you have to get the bean using ApplicationContext where you need?
Langali
I would *normally* get my one top-level bean at initialisation and then reference further beans as required from that top-level bean. But you could do what you're suggesting.
Brian Agnew
A: 

As mentioned by others, you should let spring manage your singletons, but if you want to manage them yourself and just let spring inject dependencies, do this:

applicationContext.getAutowireCapableBeanFactory().autowireBean(yourService);
seanizer
A: 

I believe the FactoryBean interface is a good alternative for you. It's a very good choice when you need to execute some initialization logic. For example to start an in memory database or some background processes in separate threads.

You can read more about it in the reference documentation.

An example that demonstrates how I instantiate a database and return a datasource everytime someone wants a bean from the FactoryBean implementation.

@PostConstruct
void init() {
    embeddedDatabase = new EmbeddedDatabaseBuilder().addScript(schemaPath)
         .addScript(dataPath).setType(embeddedDatabaseType).build();
}


public DataSource getObject() throws Exception {
    return embeddedDatabase;
}

This enables loose coupling between the factory logic and the returned object. It's heavily used by the Spring framework internally.

If you want it to be initialized the first time you use it, then set lazy-initialization to true.

Another alternative if you want your code to interact with the Spring container is to create a factory that implements the ApplicationContextAware interface. Then you can do something like this:

myDao = context.getBean(MyDao.class);
Espen