前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >多线程@Autowire注入null的解决方案

多线程@Autowire注入null的解决方案

作者头像
Remember_Ray
发布2020-03-09 13:34:57
1.9K0
发布2020-03-09 13:34:57
举报
文章被收录于专栏:Ray学习笔记Ray学习笔记

参考: 多线程时Autowired自动注入问题 spring项目中多线程@Autowire注入null的解决方案

首先需要知道的是,容器中的组件,也就是你添加了诸如 @Component@Service@Controller 以及 @Repository 等等注解,在容器启动的时候是会扫描标注这些注解的类创建 Bean 并放入容器中。

如果该类中的成员变量上使用了诸如 @Autowired@Resource 注解时,容器将会找对应的 Bean 并注入,又叫依赖注入

而在多线程实例中使用 @Autowired 注解得不到对象,又叫 Null,为什么呢?

这是因为多线程是防注入的,所以只是在多线程实现类中简单的使用 @Autowired 方法注入自己的 service,会在程序运行到此类调用 service 方法的时候提示注入的 service 为 null。

所以这里给出两种解决方案:

  1. 将需要使用的 service 当做多线程实现类的一个属性参数(也就是构造的时候当做参数或者没有构造的话使用set方法),然后在调用多线程,使用new的时候将该service赋值给实现类
  2. 写个获取 springbean 的帮助类,实现 ApplicationContextAware 接口:
代码语言:javascript
复制
/**
 * 以静态变量保存Spring ApplicationContext, 可在任何代码任何地方任何时候取出ApplicaitonContext.
 * 
 * @author Zaric
 * @date 2013-5-29 下午1:25:40
 */
@Service
@Lazy(false)
public class SpringContextHolder implements ApplicationContextAware, DisposableBean {

	private static ApplicationContext applicationContext = null;

	private static Logger logger = LoggerFactory.getLogger(SpringContextHolder.class);

	/**
	 * 取得存储在静态变量中的ApplicationContext.
	 */
	public static ApplicationContext getApplicationContext() {
		assertContextInjected();
		return applicationContext;
	}

	/**
	 * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
	 */
	@SuppressWarnings("unchecked")
	public static <T> T getBean(String name) {
		assertContextInjected();
		return (T) applicationContext.getBean(name);
	}

	/**
	 * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
	 */
	public static <T> T getBean(Class<T> requiredType) {
		assertContextInjected();
		return applicationContext.getBean(requiredType);
	}

	/**
	 * 清除SpringContextHolder中的ApplicationContext为Null.
	 */
	public static void clearHolder() {
		if (logger.isDebugEnabled()){
			logger.debug("清除SpringContextHolder中的ApplicationContext:" + applicationContext);
		}
		applicationContext = null;
	}

	/**
	 * 实现ApplicationContextAware接口, 注入Context到静态变量中.
	 */
	@Override
	public void setApplicationContext(ApplicationContext applicationContext) {
		SpringContextHolder.applicationContext = applicationContext;
	}

	/**
	 * 实现DisposableBean接口, 在Context关闭时清理静态变量.
	 */
	@Override
	public void destroy() throws Exception {
		SpringContextHolder.clearHolder();
	}

	/**
	 * 检查ApplicationContext不为空.
	 */
	private static void assertContextInjected() {
		Validate.validState(applicationContext != null, "applicaitonContext属性未注入, 请在applicationContext.xml中定义SpringContextHolder.");
	}
}

调用

代码语言:javascript
复制
private static LogDao logDao = SpringContextHolder.getBean(LogDao.class);

private static SynchroDataService synchroDataService = SpringContextHolder.getBean(SynchroDataService.class);

用帮助类的时候应注意以下几点:

a.如果是用注解形式注入spring容器(即不用spring的配置文件)的话,一定要使用@Component将此帮助类注入到spring容器中。此时可以通过clazz参数形式:clazz为在多线程中使用的service的类名.class(点class)。

b.帮助类中定义ApplicationContext类型的静态变量applicationContext,然后在获取bean的方法中使用该静态变量从spring容器中获取通过getBean方法获取容器中的bean。

c.当使用spring配置文件的时候,一定要使用<bean id="springBeanUtil" class="类的路径" />将帮助类注入到容器中。然后在多线程中使用serveri时获取bean的时候可以通过上面name参数形式:name一定是想要在多线程中使用的service在spring配置文件中注入的bean标签的id值,也可以通过上面clazz参数形式:clazz为在多线程中使用的service的类名.class(点class)。

d.帮助类获取bean的方法一定是static修饰静态方法

e.重要的事情说3遍:不管使用注解形式还是spring配置文件形式,帮助类一定要注入到spring容器中!!!

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-03-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档