通过依赖注入访问Spring bean *而不是*

时间:2009-11-28 22:40:06

标签: java spring dependency-injection

我们有一些在运行时创建的域对象 - 而不是Spring。这些域对象需要访问由Spring管理的某些服务类型bean。如何在运行时创建的域对象动态访问Spring bean(而不是通过DI)?

8 个答案:

答案 0 :(得分:8)

@ duffymo的回答是这个问题的最常见解决方案,也是你应该遵循的问题。

但是,如果你感觉很好,如果你的情况支持它,那么你可以考虑使用Spring的AspectJ支持autowire your non-spring-managed domain objects使用spring bean:

  

[...]包含注释驱动   利用此功能的方面   允许依赖注入任何   宾语。该支持旨在   用于外部创建的对象   控制任何容器。域   对象通常属于这一类   因为它们经常被创造出来   以编程方式使用新的   运算符,或作为一个ORM工具   数据库查询的结果。

它正在接近伏都教,这个东西,它只适用于某些appservers,但它可能是你的工具。

答案 1 :(得分:7)

您必须向他们提供对ApplicationContext或BeanFactory的引用,以便他们可以获得Spring管理的bean。

答案 2 :(得分:3)

Spring有一个名为SingletonBeanFactoryLocator的机制,您可以在某些地方使用它,例如EJB 2.0应用程序,以便在不能使用依赖项注入的地方获取bean工厂/应用程序上下文。现有的Spring ContextLoader中有一个钩子,你已经用它来利用这个功能,虽然设置起来有些棘手。

您需要将应用程序上下文分离为父/子关系。父级将包含服务层对象,而子级由特定于Web层的东西组成。

然后你必须向你的web.xml添加几个上下文参数(就像你对配置位置所做的那样)来告诉它初始化父文件:

<context-param>
    <param-name>locatorFactorySelector</param-name>
    <param-value>classpath:beanRefFactory.xml</param-value>
</context-param>

<context-param>
    <param-name>parentContextKey</param-name>
    <param-value>beanRefFactory</param-value>
</context-param>

locatorFactorySelector是对xml文件的引用,但是(这是我总是感到困惑的地方)这并不是指向定义服务的xml。它是一个bean定义xml,它创建一个应用程序上下文bean。然后,您使用parentContextKey属性引用此bean。

因此,例如,beanRefFactory.xml将包含:

<beans>
    <bean id="beanRefFactory"
         class="org.springframework.context.support.ClassPathXmlApplicationContext">
        <constructor-arg>
           <list>
                <value>service-context.xml</value>
           </list>
        </constructor-arg>
    </bean>
</beans>

在非DIed域对象中,您可以使用以下代码访问应用程序上下文:

   BeanFactoryLocator locator = ContextSingletonBeanFactoryLocator.getInstance(locatorFactorySelector);
   BeanFactoryReference contextRef= locator.useBeanFactory(parentContextKey);
   ApplicatonContext context = (ApplicationContext) contextRef.getFactory();

您可以在this blog post中找到有关ContextSingletonBeanFactoryLocator的更多信息。在Java Development with the Spring Framework中的EJB章节中也有一个很好的描述使用这种方法。

答案 3 :(得分:3)

创建工厂并使用spring注册它,使用工厂创建域对象而不是使用'new'

在这种情况下,您拥有DomainObjFactory

可用的所有好东西

答案 4 :(得分:1)

略有关联question

您可以采用与Hibernate类似的策略,为您的域实例工厂中的拦截器创建工具。您可以将所需的服务注入到弹簧管理的拦截器中,这些拦截器将注入您的域工厂

这将从Spring特定接口解开您的应用程序。以下示例可以使用泛型进行简化,但您应该明白这一点。

public interface Interceptor {
  public void onCreate(Object entity);
}

public class DomainFactory {
  public void setInterceptors(List<Interceptor> interceptors) { ... }
  public Object createInstance() {
    // iterate interceptors, call onCreate
  }
}

public interface MyServiceAware {
  public void setMyService(MyService service);
}

public class MyServiceInjector implements Interceptor {
  private MyService myService;
  public void onCreate(Object entity) {
    if (entity instanceof MyServiceAware)
      ((MyServiceAware) entity).setMyService(myService);
  }
}

然后你会配置它像

<bean id="myServiceInjector" class="MyServiceInjector">
  <property name="myService" ref="someServiceBean" />
</bean>

<bean class="DomainFactory">
  <property name="interceptors">
    <list>
      <ref bean="myServiceInjector"/>
    </list>
  </property>
</bean>

答案 5 :(得分:0)

您可以使用@duffymo建议的方法,但如果您没有将Spring作为Web应用程序运行,则应该查看此SO entry。在最流行的答案中看到实用程序类是线程安全的。通过OP和答案,您应该得到所需的一切,然后您可以使用此实用程序类来获取对Spring托管bean的引用。

答案 6 :(得分:0)

一种解决方案是使用全局static方法返回Spring应用程序竞赛(请参阅BeanLocator。)

其他选项可能是让您的业务对象实现ApplicationContextAware接口。在实例化时,您的“集成”代码必须将Spring ApplicationContext注入到动态创建的bean中(可能通过检查类是否实现ApplicationContextAware。)这当然会将您的业务代码与Spring绑定,但第一种选择是相同的。

变体是不直接注入ApplicationContext,而是重用Spring @Autowired注释。然后,“集成”代码将仅注入带注释的字段。

答案 7 :(得分:0)

您可以使依赖对象成为具有静态getInstance()方法的单例,该方法可由非Spring托管域对象使用。然后,您可以通过org.springframework.beans.factory.config.MethodInvokingFactoryBean将其提供给Spring,如:

<bean id="myObject"
    class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
    <property name="staticMethod">
        <value>com.example.MyObject.getInstance</value>
    </property>
</bean>