How to inject dependencies into a self-instantiated object in Spring?
Solution 1
You can do this using the autowireBean()
method of AutowireCapableBeanFactory
. You pass it an arbitrary object, and Spring will treat it like something it created itself, and will apply the various autowiring bits and pieces.
To get hold of the AutowireCapableBeanFactory
, just autowire that:
private @Autowired AutowireCapableBeanFactory beanFactory;
public void doStuff() {
MyBean obj = new MyBean();
beanFactory.autowireBean(obj);
// obj will now have its dependencies autowired.
}
Solution 2
You can also mark your MyClass with @Configurable annotation:
@Configurable
public class MyClass {
@Autowired private AnotherClass instance
}
Then at creation time it will automatically inject its dependencies. You also should have <context:spring-configured/>
in your application context xml.
Solution 3
Just got the same need and in my case it was already the logic inside non Spring manageable java class which had access to ApplicationContext
. Inspired by scaffman.
Solved by:
AutowireCapableBeanFactory factory = applicationContext.getAutowireCapableBeanFactory();
factory.autowireBean(manuallyCreatedInstance);
Solution 4
I wanted to share my solution that follows the @Configurable
approach as briefly
mentioned in @glaz666 answer because
- The answer by @skaffman is nearly 10 years old, and that does not mean not good enough or does not work
- The answer by @glaz666 is brief and didn't really help me solve my problem but, did point me in the right direction
My setup
- Spring Boot 2.0.3 with
Spring Neo4j & Aop starts
(which is irrelevant anyway) - Instantiate a bean when
Spring Boot
is ready using@Configurable
approach (usingApplicationRunner
) - Gradle & Eclipse
Steps
I needed to follow the steps below in order to get it working
- The
@Configurable(preConstruction = true, autowire = Autowire.BY_TYPE, dependencyCheck = false)
to be placed on top of yourBean
that is to be manually instantiated. In my case theBean
that is to be manually instantiated have@Autowired
services hence, the props to above annotation. - Annotate the Spring Boot's main
XXXApplicaiton.java
(or the file that is annotated with@SpringBootApplication
) with the@EnableSpringConfigured
and@EnableLoadTimeWeaving(aspectjWeaving=AspectJWeaving.ENABLED)
- Add the dependencies in your build file (i.e. build.gradle or pom.xml depending on which one you use)
compile('org.springframework.boot:spring-boot-starter-aop')
andcompile('org.springframework:spring-aspects:5.0.7.RELEASE')
- New+up your
Bean
that is annotated with@Configurable
anywhere and its dependencies should be autowired.
*In regards to point #3 above, I am aware that the org.springframework.boot:spring-boot-starter-aop
transitively pulls the spring-aop
(as shown here mavencentral) but, in my case the Eclipse failed to resolve the @EnableSpringConfigured
annotations hence, why I explicitly added the spring-aop
dependency in addition to the starter. Should you face the same issue, just declare the dependency or go on adventure of figuring out
- Is there a version conflict
- Why the
org.springframework.context.annotation.aspect.*
is not available - Is your IDE setup properly
- Etc etc.
Solution 5
I used a different approach. I had spring loaded beans that I wanted to call from my extended classes of a third-party library that created its own threads.
I used approach I found here https://confluence.jaytaala.com/display/TKB/Super+simple+approach+to+accessing+Spring+beans+from+non-Spring+managed+classes+and+POJOs
In the non-managed class:
{
[...]
SomeBean bc = (SomeBean) SpringContext.getBean(SomeBean.class);
[...]
bc.someMethod(...)
}
And then as a helper class in the main application:
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component
public class SpringContext implements ApplicationContextAware
{
private static ApplicationContext context;
public static <T extends Object> T getBean(Class<T> beanClass)
{
return context.getBean(beanClass);
}
@Override
public void setApplicationContext(ApplicationContext context) throws BeansException
{
SpringContext.context = context;
}
}
Related videos on Youtube
Igor Mukhin
Updated on February 07, 2021Comments
-
Igor Mukhin about 3 years
Let's say we have a class:
public class MyClass { @Autowired private AnotherBean anotherBean; }
Then we created an object of this class (or some other framework have created the instance of this class).
MyClass obj = new MyClass();
Is it possible to still inject the dependencies? Something like:
applicationContext.injectDependencies(obj);
(I think Google Guice has something like this)
-
Sean Patrick Floyd over 13 yearsGood answer (+1). There's also a second method where you can influence how the autowiring happens: static.springsource.org/spring/docs/3.0.x/javadoc-api/org/…
-
Vadim Kirilchuk over 10 yearsBut what if I have two objects, and first autowires second. How autowire bean factory deals with dependencies in the case?
-
Denis about 10 yearsThis is actually a bad pattern. If this is how you really use MyBean why not just have constructor with AnotherBean as parameter. Something like:
code
private @Autowired AnotherBean bean; public void doStuff() { MyBean obj = new MyBean(bean); }code
. Seems to be like with all these annotations people get really confused and just don't use the basic pattern that were in java SDK since day 1. :( -
troymass over 9 yearsGalz666, your method looks much cleaner for what I want to do. However I cannot get it to work. I have no xml file and am using entirely Java config. Is there an equivalent to
<context:spring-configured/>
? -
jsosnowski over 8 yearsThis is clean solution, but requires a little more effort: You should either use load-time weaving as iimuhin shows above or add AspectJ compiler to project. Load-time as the name suggest will cause additional cost at run-time.
-
Rodney P. Barbati over 8 yearsI agree - Spring has redefined the entire language. Now we use interfaces as concrete classes, methods as class instances and all manner of complicated and code heavy methods of doing what you used to do with new and a decent design.
-
Dalton about 8 years@Denis if MyBean has dependencies that the actual class don't need, you're registering dependencies that doesn't actually exist, just to instance a class, so there's really no difference.
-
Rogério over 7 yearsI think the answer by @glaz666 is much cleaner/better than this. The only disadvantage of using
@Configurable
I can see is that it requires Spring to use AspectJ under the covers. -
Alireza Fattahi over 7 yearsIt is a very useful capability and the answer is quite correct. Some frameworks , like struts 2, use this feature to
autowire
their beans. See stackoverflow.com/questions/39706221/… -
http8086 over 4 yearsactually there has nothing mentioned about this in spring framework reference documentation, why is that
-
leonidos79 about 4 yearsThere is also another very helpful
BeanFactory
method that does NOT autowire the bean as such (i.e. it does not inject dependencies by means of setter or field injection), but it does make the bean aware of its surroundings by injecting application context, reference to a bean factory, invoking post-initialization callbacks, and assigning bean a name. And it does not require aBeanDefinition
to be present (something that autowire() method expects):initializeBean(Object existingBean, String beanName)
-
veritas over 2 yearsThis worked for me after going to the confluence link. Have upvoted it.