Spring 依赖注入超越基础教程

发布于 2024-11-27 03:40:32 字数 1410 浏览 1 评论 0原文

在我的 main() 方法中,我使用 Spring 创建一个 PersonCollection 对象,然后开始加载不同的 Persons 对象。

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();

反过来,PersonCollection.loadById() 可以从 memcached 或 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;
}

因此有两种方法创建 Person,第一种是从 memcached 反序列化,第二种将调用 new Person() 并分配所有数据。

Person 有两个 @Autowired 属性,并被声明为 @Service,并且包位于 context:component-scan 中,但是依赖项不会传递,因为 bean 是使用 new 或从缓存创建的,而不是使用 Spring 框架创建的。

我可以使用 appContext.getBean() 创建 Person 对象,但是,这意味着传递 applicationContext 并在应用程序内部使用 getBean() ,这感觉不对。

如何解决问题?

更新:我阅读了文档并尝试了 Ryan Stewart 的建议,并编写了一个小示例项目来尝试。效果很好,谢谢!

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

最终,我重构了我原来的项目,在某种程度上我不再需要这个功能,但它是我的武器库中的一个很好的工具。

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 memcached, 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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

梨涡少年 2024-12-04 03:40:32
  1. 是的,像瘟疫一样避免在您的(非基础设施)代码中使用 ApplicationContext.getBean()
  2. 选项一:不要自动装配类似 POJO 的类。将其拉出到与人员紧密耦合的“服务”对象中。这或多或少是当前的主流方法,我希望它消失,因为它会变得混乱。
  3. 选项二:使用 AspectJ使用 @Configurable 注解 进行编织,使 Person 可自动装配,无论它在何处实例化。我真的很喜欢这个选项,尽管我还没有在生产项目中使用过它。
  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.
难如初 2024-12-04 03:40:32

您可能还想研究一个名为 ObjectFactoryCreatingFactoryBean,这是一种“重用”BeanFactory 功能而不会过度污染的方法您的业​​务代码无需担心 bean 名称。

<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>

这样,您的 PersonCollection 实例不需要知道任何 bean 名称,但可以通过以下方式获取新的 Person (注入指定的依赖项):

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

IMO 有一些它可以变得更加方便(例如使用内部 bean 而不是 idref),但这需要一些 Spring-guru 和自定义 XML 命名空间。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文