66

I'm an end-user of one of my company's products. It is not very suitable for integration into Spring, however I am able to get a handle on the context and retrieve the required bean by name. However, I would still like to know if it was possible to inject a bean into this class, even though the class is not managed by Spring itself.

Clarification: The same application which is managing the lifecycle of some class MyClass, is also managing the lifecycle of the Spring context. Spring does not have any knowledge of the instance of MyClass, and I would like to some how provide the instance to the context, but cannot create the instance in the context itself.

Spencer Kormos
  • 8,381
  • 3
  • 28
  • 45
  • Please clarify: You want to inject the bean via Spring Configuration, Spring dynamically at runtime, or programmatically via a setter? – Ken Gentle Nov 21 '08 at 21:45
  • Any method is fine. The point is that the application has created the object into which I want to inject a bean, so the original object is not managed by the Spring context. – Spencer Kormos Nov 21 '08 at 22:01
  • Also, consider using a factory method so you can put the class into the application context and configure it as per a normal Spring bean. Look at the Spring reference docs regarding bean factories. – cletus Nov 22 '08 at 00:54
  • I'm not sure how a factory method would have anymore access to a bean not managed by the Spring context, which is the point of the question. – Spencer Kormos Nov 22 '08 at 05:50

8 Answers8

66

You can do this:

ApplicationContext ctx = ...
YourClass someBeanNotCreatedBySpring = ...
ctx.getAutowireCapableBeanFactory().autowireBeanProperties(
    someBeanNotCreatedBySpring,
    AutowireCapableBeanFactory.AUTOWIRE_AUTODETECT, true);

You can use @Autowired and so on within YourClass to specify fields to be injected etc.

David Tinker
  • 9,383
  • 9
  • 66
  • 98
  • I never got a chance to try this, but it does seem to come the closest to what I was looking for. It would be nice to give it a whirl. – Spencer Kormos Feb 03 '10 at 21:04
  • This [answer](http://stackoverflow.com/a/129999/1370556) explains how to get the `ApplicationContext` – lebolo Mar 03 '16 at 16:42
3

One way to bring a bean into Spring despite its manufacture being external is to use a helper class marked as a @Configuration bean that has a method (marked with @Bean) that actually makes the instance and hands it back through Spring (which does its property injection and proxy generation at that point).

I'm not quite sure what scope you need; with prototype, you'll get a fresh bean in each place.

@Configuration
public class FooBarMaker {
    @Bean(autowire = Autowire.BY_TYPE)
    @Scope("prototype")
    public FooBar makeAFooBar() {
        // You probably need to do some more work in here, I imagine
        return new FooBar();
    }
}

You can inject properties required for manufacture into the @Configuration bean. (I use this to create instances of an interface where the name of the class to instantiate is defined at runtime.)

Donal Fellows
  • 133,037
  • 18
  • 149
  • 215
3

suppose that u have the following dependency chain:

A --> B --> C --> x --> y -- > Z

A, B, C are spring managed beans (constructed and manged by spring framework) x, y are really simple POJOs that constructed by your application, without spring assistance

now if you want that y will get a reference to Z using spring that you need to have a 'handle' to the spring ApplicationContext

one way to do it is to implement ApplicationContextAware interface . In this case I would suggest that either A, B or C will implement this interface and will store the applicationContext reference in a static member.

so lets take Class C for example:

class C implmenets ApplicationContextAware{
    public static ApplicationContex ac;
     void setApplicationContext(ApplicationContext applicationContext)  {
               ac = applicationContext;
     }
 .............
}

now, in class y you should have:

(Z)(C.ac.getBean("classZ")).doSomething()

HTH -- Yonatan

alexbt
  • 16,415
  • 6
  • 78
  • 87
Yonatan Maman
  • 2,428
  • 1
  • 24
  • 34
  • How about: x and y has no dependency on C, and I wish to inject Z into x or y? It seems I would have to use the @Comparable tag in spring-context, then do some runtime weaving after the fact. So far I have not managed to get this working, and adds extra work. Looking for an easier way. – Spencer Kormos Nov 24 '08 at 02:38
  • You are setting the 'ac' (which is static) from 'setApplicationContext' method which is non-static. Ideally, static fields are only updated from synchronized static methods. Otherwise this could easily lead to bugs if there are multiple class instances and/or multiple threads in play. – vadim Mar 16 '17 at 09:20
2

Another way to do this is to us use AspectJ. This is the recommended way of injection Spring beans into non-managed objects that are created with the new operator. See this for details:

http://www.javacodegeeks.com/2011/02/domain-driven-design-spring-aspectj.html

Dave
  • 21,524
  • 28
  • 141
  • 221
1

Searching endless combos of autowire inject spring bean into pojo applicationcontextaware beanaware etc circled me back here but this didnt provide a complete enough solution for me.

This is a much better implementation/tutorial of this IMO: I hope it helps everyone like it finally helped me.

Accessing Spring Beans from outside Spring Context

keyser
  • 18,829
  • 16
  • 59
  • 101
user1204808
  • 29
  • 1
  • 3
0

If you want to create an object outside the Spring context, and make that object available for injection into other beans that are in the Spring context, you can follow the steps in this article.

Basically, you create a parent application context and push your external object into this parent context as a singleton. Then you create you main application context (for example, from xml files), with the parent application context as its parent.

Object externalObject = ...
GenericApplicationContext parent = new StaticApplicationContext();
parent.getBeanFactory().registerSingleton( "externalObject", externalObject );
parent.refresh();
ApplicationContext appContext = new ClassPathXmlApplicationContext( ... , parent);
GreenGiant
  • 4,930
  • 1
  • 46
  • 76
0

Be careful that in oldest version of Spring, there is thread-safe problem with bean factory http://jira.springframework.org/browse/SPR-4672

0

From a Spring configuration class, set a static field on the non-Spring class that needs the beans.

I have an example in my answer to a Liquibase question: https://stackoverflow.com/a/71191546/5499391

mouse_8b
  • 514
  • 5
  • 8