问题
在公司的一个项目开发时,遇到了一个类的属性无法注入的问题
public class DemoController extends BaseController implements BussinessProcessHandler {
@Autowired
DemoApi demoApi;
public void demo() {
demoApi.DemoService();
}
如上代码运行中报空指针异常,demoApi
的实例为null
,spring
容器没有注入Bean
。
原因
起先认为是spring没有扫描到组件。spring boot的注解@SpringBootApplication
继承了扫描注解@ComponentScan
,默认扫描是当前包及其子包下的所有目录,查看目录结构是没有问题的。所以不是扫描的问题。
后来发现这个类DemoController
的实例是反射生成的,并不由spring容器管理。
spring自动注入对象是通过创建一个BeanFactory
并传入applicationContext
配置文件对象,然后调用BeanFactory
的getBean
方法来实现相互依赖的对象获取和装配的。如果被注入的容器没有在spring bean
中配置,而是通过反射途径生成,不能获取BeanFactory,就意味着不能进行自动注入。
解决办法
自己创建一个SpringUtil
工具类组件,实现BeanFactoryAware
或者ApplicationContextAware
等spring
提供的接口,并通过实例手动获取Spring
管理的bean
。
@Component
public class SpringUtil implements ApplicationContextAware {
//ApplicationContext对象是Spring开源框架的上下文对象实例,在项目运行时自动装载Handler内的所有信息到内存。
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
if (SpringUtil.applicationContext == null) {
SpringUtil.applicationContext = applicationContext;
}
}
//获取applicationContext
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
//通过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);
}
}
手动获取bean实例
public class DemoController extends BaseController implements BussinessProcessHandler {
//@Autowired
//DemoApi demoApi;
public void demo() {
//通过class获取bean
DemoApi demoApi=SpringUtil.getBean(DemoApi.class);
demoApi.DemoService();
}
这样再运行demoApi
就不为null
了。