前言
我发现当前类含有@Autowired注入Spring Bean的成员对象时候,则当前类必须也是Spring Bean才能调用它,也就是说该类必须写上注解@Component、@Configuration加入Spring Bean管理该类。然后运用时候通过@Resource或者@Autowired来注入Bean,这样才能调用该类的某bean成员对象的方法,不能用new xxx()来获得对象,这种方式获得的对象无法调用@Autowired注入的Bean成员对象的方法。
例子
@Component
public class Children {
public void test(){
System.out.println("test for get Bean Children");
}
}
//加入Spring Pool
注解效果如下:
<bean id=“children” class=“com.machome.testtip.impl.Children” >
</bean>
@Component
public class Parent {
@Resource
Children children;
public void testParent(){
System.out.println("test Parent");
children.test();
}
}
//加入Spring Pool
注解效果如下:
<bean id=“parent” class=“com.machome.testtip.impl.Parent” >
</bean>
@Resource注入bean正常调用
@RunWith(SpringRunner.class)
@SpringBootTest
public class TokenApplicationTests {
@Resource
Parent parent;
@Test
public void contextLoads() {
parent.testParent();
}
}
结果:
new对象调用Spring Bean的成员对象空指针异常
@RunWith(SpringRunner.class)
@SpringBootTest
public class TokenApplicationTests {
// @Resource
// Parent parent;
@Test
public void contextLoads() {
Parent parent = new Parent();
parent.testParent();
}
}
结果:
使用new创建的对象,该对象中@Autowired注入的成员对象为null。
所以如果一个类中有spring容器注入的对象,则不能使用new来创建对象,最好使用@Autowired、@Resource来创建该对象。那么还有其他方法吗?
解决方法一:手动注入的Spring Bean
ApplicationContextUtil手动注入的Spring Bean
ApplicationContextUtil代码如下:
package com.example.token.kit;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/**
* 手动注入bean
* @author andrew
*
*/
@Component
public class ApplicationContextUtil implements ApplicationContextAware {
@Autowired
private static ApplicationContext context;
/**
* 插入ApplicationContext
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}
/**
* 获取ApplicationContext
*/
public static ApplicationContext getApplicationContext() {
return context;
}
/**
* 通过name获取 Bean
*/
public static Object getBean(String name) {
return getApplicationContext().getBean(name);
}
/**
* 通过class获取Bean.
*/
public static <T> T getBean(Class<T> clazz) {
return getApplicationContext().getBean(clazz);
}
/**
*通过name,以及Clazz返回指定的Bean
*/
public static <T> T getBean(String name, Class<T> clazz) {
return getApplicationContext().getBean(name, clazz);
}
}
测试代码:
@RunWith(SpringRunner.class)
@SpringBootTest
public class TokenApplicationTests {
// @Resource
// Parent parent;
@Test
public void contextLoads() {
Parent parent = (Parent) ApplicationContextUtil.getBean("parent");
parent.testParent();
}
结果正常:
解决方法二:取消注解注入Bean成员对象,通过new对象调用方法
修改Parent代码,让Parent的成员对象children不通过@Resource注入,而是通过ApplicationContextUtil手动注入,这样Parent就不含有通过注解注入Bean的成员对象,从而可以Parent可以通过new的形式调用该成员对象的方法。不需要将自己加入到Spring Bean管理,也就是可以把Parent类的注解@Component去掉。
public class Parent {
// @Resource
// Children children;
public void testParent(){
System.out.println("test Parent");
Children children = (Children) ApplicationContextUtil.getBean("children");
children.test();
}
}
@RunWith(SpringRunner.class)
@SpringBootTest
public class TokenApplicationTests {
// @Resource
// Parent parent;
@Test
public void contextLoads() {
Parent parent = new Parent();
parent.testParent();
}
}