Access to Spring bean * not * by dependency injection

We have some domain objects created at runtime, not Spring. These domain objects need access to some type of beans service, which is managed by Spring. How do domain objects created at runtime access Spring beans dynamically (rather than by DI)?

+6
java spring dependency-injection
source share
8 answers

You will need to give them a link to ApplicationContext or BeanFactory so that they can get Spring -managed beans.

+7
source share

@duffymo's answer is the most common solution to this problem, and one that you probably should follow.

However, if you feel bold, and if your situation supports it, then you can use Spring AspectJ support to autowire your non spring managed domain objects with Spring beans:

[...] contains an annotation of an aspect that takes this opportunity to allow dependency injection of any object. Support should be used for objects created outside the control of any container. Domain objects often fall into this category because they are often created programmatically using a new statement or the ORM tool as the result of a database query.

This is verging on voodoo, this stuff, and it only works on some application servers, but it may be a tool for you.

+8
source share

Spring has a mechanism called SingletonBeanFactoryLocator that can be used in places like EJB 2.0 to get the bean factory / application context in places where you cannot use dependency injection. There is a hook in the existing Spring ContextLoader that you are already using to take advantage of this functionality, although it is somewhat difficult to configure.

You need to share the contexts of your application with the parent / child relationship. The parent will contain the service level objects, and the child element consists of the specific material of the web layer.

Then you will need to add a couple of context parameters to your web.xml (for example, for the configuration location) to tell it to initialize the parent:

 <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 is a link to an xml file, BUT (I always confuse this), this will not point to the xml that defines your services. This is a bean xml definition that creates a bean application context. Then you reference this bean with the parentContextKey attribute.

So, for example, beanRefFactory.xml will contain:

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

In non-DIed related domain objects, you can go to the application context with this code:

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

More information about ContextSingletonBeanFactoryLocator can be found in this blog post . There is also a good description of using this approach in the EJB chapter in Java Development with the Spring Framework .

+3
source share

Create a Factory and register it with spring, use Factory to create a domain object instead of using 'new'

in this case, you have all the goodies available for your DomainObjFactory

+3
source share

Slightly related question

You can adopt a similar strategy for Hibernate by creating objects for interceptors in your factory domain instance. You can enter the necessary services in spring-driven interceptors that are introduced into your domain factories

This will disconnect your application from spring specific interfaces. The example below can be simplified with generics, but you should get this idea.

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

Then you configure it something like

 <bean id="myServiceInjector" class="MyServiceInjector"> <property name="myService" ref="someServiceBean" /> </bean> <bean class="DomainFactory"> <property name="interceptors"> <list> <ref bean="myServiceInjector"/> </list> </property> </bean> 
+1
source share

You can use the approach suggested by @duffymo, but in case you are not using Spring as a web application, you should look at this SO entry. See that the utility class is streamed in the most popular answer. Btw OP and the answer you should get everything you need, and then you can use this utility class to get a link to Spring beans.

0
source share

One solution is to use the global static method, which returns the Spring application contest (see BeanLocator .)

Other options may be for your business objects to implement the ApplicationContextAware interface. When creating the instance, your integration code should embed the Spring ApplicationContext into the dynamically created bean (perhaps by checking to see if the ApplicationContextAware class implements.) This, of course, will link your business code with Spring, but the first option will be the same.

The change would be to not inject ApplicationContext directly, but reuse Spring @Autowired annotation. Then the "integration" code enters only the annotated fields.

0
source share

You can make the dependent object a singleton with the static getInstance () method, which can be used by objects without the Spring domain name. You will then make it available to Spring through org.springframework.beans.factory.config.MethodInvokingFactoryBean, for example:

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

All Articles