How to inject spring injection manually if not done automatically
My spring dependencies are working fine but there one class
CustomUserDetaisls
where i need the Autowired dependency called
@Autowired Private UserDAO userDAO
to match with username and password
But my spring injection is not working here as this class implements the userDetailsSerivce
. However injection works if i remove the implements.
I have submitted the question to ask why in this question, but no one gave me answer so i decided to use the DAO with new operator
private UserDAO userDAO = new UserDAO();
But that userDAO
in turn depends on session Factory which is a spring bean.
Then i again decided to get sessionfactory from java code rather than spring using following code
SessionFactory sessionFactory = new AnnotationConfiguration()
.configure("com/vaannila/service/hibernate.cfg.xml")
.buildSessionFactory();
But again i have several bean in hibernate-context like datasource , properties file and i am finding it very hard to re-write all the things.
Is there any way that I can manually inject userDAO
so that all the related spring injection like sessionFact开发者_开发问答ories works
If you have access to the spring context, you can retrieve an AutowireCapableBeanFactory which you can then use on any bean like this:
ApplicationContext springContext = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContextEvent.getServletContext());
AutowireCapableBeanFactory factory = springContext.get(AutowireCapableBeanFactory.class);
// this would instantiate and autowire a bean:
UserDAO userDAO = factory.createBean(UserDAO.class);
// this will autowire an already existing bean:
UserDAO manualUserDAO = new UserDAO();
factory.initializeBean(manualUserDAO, "beanNameIfNeeded");
However, if a bean requires that it be autowired before it can be used, I prefer to use the first mechanism and mark the constructor as private/protected to make sure that it cannot be created via 'new' and force it to be created via a factory like above.
UPDATE 11/27/17
I personally didn't like to have to use the factory every time I wanted to create an autowired instance. Particularly if some other process was creating the instance, such as deserializing from a database, etc.
I ended up creating a aspect to automatically handle the autowiring.
First, I created an annotation to flag classes that I wanted automatically autowired:
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface AutowireAfterCreation {
}
Then I created an aspect that uses an 'after construction' point cut to do the autowiring. Unfortunately, I was unable to figure out a point cut that was only called after the 'last' constructor was finished, but it doesn't seem to hurt to autowire multiple times, at least in my case.
public aspect AutowiringAfterCreation {
@Autowired
private AutowireCapableBeanFactory beanFactory;
/**
* After construction, autowire the instance.
* @param o Newly created object to be autowired.
*/
after(Object o) returning : target(o) && initialization((@AutowireAfterCreation *).new(..)) {
// this aspect will actually autowire the instance multiple times if the class is part of an inheritance
// Hierarchy. This is not optimal, but it should not hurt anything to autowire more than once.
// FUTURE: modify the aspect so it only runs once, regardless of how many constructor calls are necessary.
beanFactory.autowireBeanProperties(o, AutowireCapableBeanFactory.AUTOWIRE_NO, false);
beanFactory.initializeBean(o, "unused");
}
}
Then I had to tell Spring about the aspect so the factoryBean is autowired into the aspect itself:
<bean class="AutowiringOnDemand" factory-method="aspectOf"/>
Now I can create any instance and have it automatically autowired simply by attaching the annotation:
@AutowireAfterCreation
public class TestEntity {
@Value("${some.config.value}")
private String value;
@Autowired
private TestRepository repository;
}
Finally, all you have to do is create an instance, and it is automatically autowired after the completion of the constructors:
TestEntity entity = new TestEntity();
UPDATE 1/2/2018
The interface ApplicationContext has changed, and get() has been removed, but you can still use the first mechanism, but you need to call getAutowireCapableBeanFactory() instead.
So the first two lines in the example at the top for this answer would now look like:
ApplicationContext springContext = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContextEvent.getServletContext());
AutowireCapableBeanFactory factory = springContext.getAutowireCapableBeanFactory();
You can take a look at spring java configuration. http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/beans.html#beans-java
In example below all dependencies of UserDAO will be automatically set by spring. It should be something like this:
@Configuration
@PropertySource("classpath:configuration.properties")
public class ApplicationConfig {
@Bean
public UserDAO userDAO() {
return new UserDAO();
}
@Bean
public CustomUserDetails customUserDetails (UserDAO userDAO) {
CustomUserDetails customUserDetails = new CustomUserDetails ();
customUserDetails.setUserDAO(userDAO());
return customUserDetails;
}
}
精彩评论