How to Inject Dependencies into a Self-Instantiated Object in Spring

How to inject dependencies into a self-instantiated object in Spring?

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

How to inject dependencies when doing Object object = new Object()

Is the spring engine that creates an object and put the created instance in a field annotated with @Autowired.

If an object is not under the control of the spring engine no @Autowired field is instantied.

So you can't have a field correctly initialized if you create the container object explicitly with a new (so if it is not under the control of spring engine).

Spring @Autowired on a class new instance

Spring itself offers some functionality for doing auto-wiring in your objects
which you created by new or newInstance() or whatever.

To use it you need an AutowireCapableBeanFactory
which you get by Spring's normal dependency injection with @Autowired.

@Autowired
private AutowireCapableBeanFactory autowireCapableBeanFactory;

Then you use its autowireBean(Object) method
to inject the @Autowired properties into your bean.

Object myBean = map.get(className).newInstance();
autowireCapableBeanFactory.autowireBean(myBean);

Design note:

Think well if you really need the approach above.
The javadoc of AutowireCapableBeanFactory advises against using this interface for most use-cases:

This subinterface of BeanFactory is not meant to be used in normal application code: stick to BeanFactory or ListableBeanFactory for typical use cases.

Integration code for other frameworks can leverage this interface to wire and populate existing bean instances that Spring does not control the lifecycle of. This is particularly useful for WebWork Actions and Tapestry Page objects, for example.

How should I inject dependencies to immutable domain objects instantiated by Mybatis?

If you are fine with the current design and you are focused on testing, then PowerMockit should attend your needs as it is capable to "set/mock" private members.

Example:

@Component
public class DomainA {
@Autowired
private ApplicationContext context;
public boolean isContextInitilized() {
return context != null;
}
}

import org.powermock.api.support.membermodification.MemberModifier;
...
@RunWith(SpringRunner.class)
@SpringBootTest
public class DemoApplicationTests {
@Autowired
ApplicationContext contextToInject;
@Autowired
DomainA domainAAutowired;

@Test
public void contextLoads() throws IllegalArgumentException, IllegalAccessException {
// Autowired spring beans work fine
assertTrue(domainAAutowired.isContextInitilized());
// Class out of spring context won't initialize dependencies
DomainA domainOutOfSpringContext = new DomainA();
assertFalse(domainOutOfSpringContext.isContextInitilized());
// We can 'set' private members using PowerMock
MemberModifier.field(DomainA.class, "context").set(domainOutOfSpringContext, contextToInject);
assertTrue(domainOutOfSpringContext.isContextInitilized());
}
}

On a side note, MyBatis classes are supposed to be simple POJOs. Having spring dependencies in MyBatis may be an indicator of poor separation of concerns as they should be only concerned with the persistence layer.

Can I inject dependencies inside a custom Spring TestExecutionListener?

I'd better configure this common object as a bean in some context configuration class and then make it available for test classes using @ContextConfiguration(classes = TestConfig.class)

Otherwise, if you really need to configure this object in your TestExecutionListener, you can register this bean anywhere in your context configuration, then autowire it in your TestExecutionListener and change its state here. But it seems to be more a hack than a solution.

Failed to get access of a spring container object using @Autowired annotation

Spring can only autowire beans into others spring-managed beans. Species object here is unmanaged so it can't work.

If you really want to keep the control on species instances (I mean control the construction by yourself) you have to inject dependency by yourself.
So recover the planet object up-front and then inject it into the constructor

Planet p = // Planet injection ;
new Species(planet);

You can also give up control and simply annotate Species with @Component (or a specialized version of it).

Last way via a config type.

@Configuration
public class Config {

@Autowired
private Planet p;

@Bean
public getSpecies() {
return new Species(p);
}
}


Related Topics



Leave a reply



Submit