开发者

Spring Dependency Injection beyond the basic tutorials

开发者 https://www.devze.com 2023-03-24 03:36 出处:网络
In my main() method I create a PersonCollection Object using Spring and then I start to load different Persons objects.

In my main() method I create a PersonCollection Object using Spring and then I start to load different Persons objects.

BeanFactory appContext = new ClassPathXmlApplicationContext("cp-beans.xml");
PersonCollection pc = appContext.getBean(PersonCollection.class);
Person aPerson = pc.loadById(1); 
aPerson.doSomething();
aPerson.loadById(1067);
aPerson.doSomething();

In turn PersonCollection.loadById() can load the object from memcached or from Amazon SimpleDB:

public Person loadById(int id) throws ConnectException, NoSuchElementException {
    String memCacheKey = "Person-" + id;
    Person aPerson = (Person) cache.get(memCacheKey);
    if (aPerson != null) {
        return aPerson; //cache hit
    }
    aPerson = loadByIdFromSdb(id); //cache miss, read it from SimpleDB
    cache.set(memCacheKey, aPerson);
    return aPerson;
}

So there are two ways to create a Person, the first is deserializing from m开发者_C百科emcached, the second will call new Person() and assign all data.

Person has two @Autowired properties and is declared as a @Service and the package is in context:component-scan, however the dependencies are not passed, because the bean is created with new or from the cache and not with the Spring framework.

I could use appContext.getBean() to create the Person Object, however, it would mean to pass around the applicationContext and use getBean() inside the application, which doesn't feel right.

How to solve the problem?

UPDATE: I read the documentation and tried the suggestion of Ryan Stewart and wrote a small example project to try it. It works great, thank you!

https://github.com/stivlo/spring-di

Ultimately, I've refactored my original project, in a way that I don't need this feature anymore, but is a good tool to have in my arsenal.


  1. Yes, avoid ApplicationContext.getBean() in your (non-infrastructure) code like the plague.
  2. Option one: Don't autowire your POJO-like classes. Pull that out into a "service" object that is tightly coupled to the Person. This is more or less the current mainstream approach, and I hope it goes away because it gets messy.
  3. Option two: Use AspectJ weaving with the @Configurable annotation to make Person autowirable regardless of where it's instantiated. I really like this option, though I haven't used it in a production project yet.


You may also want to look into a little oddball utility class called ObjectFactoryCreatingFactoryBean, which is a way of "reusing" the capabilities of the BeanFactory without unduly contaminating your business code with worrying about bean names.

<beans>
   <bean id="PersonCollection " class="com.example.PersonCollection">
       <property name="personMaker" ref="PersonMaker"/>
   </bean>

   <bean id="personPrototype" class="com.example.Person" scope="prototype">
       <!-- Things to inject onto a newly-made person -->
   </bean>

   <bean id="PersonMaker" class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean">
     <property name="targetBeanName"><idref local="personPrototype"/></property>
   </bean>
</beans>

In this way, your PersonCollection instance doesn't need to know any bean names, but can get a fresh Person (with the specified dependencies injected) via:

Person p = (Person) this.personMaker.getObject();

IMO there are some ways it could be made much more convenient (such as working with an inner bean rather than idref) but that would require some Spring-guru and a custom XML namespace.

0

精彩评论

暂无评论...
验证码 换一张
取 消