记一次bean加载冲突

一个工具类引发的生产失效

以下代码为SpringUtils工具类,作用是可以在spring项目中引用已经加载的bean

import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component; import java.util.Map; /** * @author: yuyangkang * @Title: SpringUtil * @ProjectName: settle * @Description: * @date: 2021/7/25 18:20 */ @Component public class SpringUtil implements ApplicationContextAware { private static ApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext applicationContext) { SpringUtil.applicationContext = applicationContext; } public static <T> T getBean(String beanName) { if(applicationContext.containsBean(beanName)){ return (T) applicationContext.getBean(beanName); }else{ return null; } } public static <T> Map<String, T> getBeansOfType(Class<T> baseType){ return applicationContext.getBeansOfType(baseType); } }

日期回到2022年5月27日

生产环境部署TIS之后,已经生效的一个组件出现异常。异常代码为

java.lang.NullPointerException: null at com.kcsm.trade.utils.SpringUtil.getBeansOfType(SpringUtil.java:34) ~[classes!/:0.0.1-SNAPSHOT] at com.kcsm.trade.service.arrears.bo.RecoverArrearsTradeCreateRule.loadRule(RecoverArrearsTradeCreateRule.java:41) ~[classes!/:0.0.1-SNAPSHOT] at com.kcsm.trade.service.impl.BeRevoverTradeImpl.createTaskGroup(BeRevoverTradeImpl.java:78) ~[classes!/:0.0.1-SNAPSHOT] ......

"at com.kcsm.trade.utils.SpringUtil.getBeansOfType(SpringUtil.java:34) ~[classes!/:0.0.1-SNAPSHOT]"

根据抛出的栈信息可知

return applicationContext.getBeansOfType(baseType);

此行代码抛出了一个异常错误 NullPointerException

debug后可知

private static ApplicationContext applicationContext;

该变量为null。

该工具类使用许久从未发生过此情况。

ApplicationContext applicationContext;

ApplicationContext和BeanFactory是Spring的两大核心接口,而其中ApplicationContext是BeanFactory的子接口。它们都可以当做Spring的容器,Spring容器是生成Bean实例的工厂,并管理容器中的Bean。在基于Spring的Java EE应用中,所有的组件都被当成Bean处理,包括数据源,Hibernate的SessionFactory、事务管理器等。

为null。

ApplicationContext类本身就是在spring项目启动时去从spring工厂中取出;

那么此时为null,就是取出的过程出现了问题。

根据springBoot的工厂装配原理可知。

如果采取自动装配

如下Demo接口

public interface Demo{ void demo(); } @Component public class Aclass implements Demo{ @Overwrite public void demo(){ } } @Component public class Bclass implements Demo{ @Overwrite public void demo(){ } }

此时如果自动装配

@Autowirte private Demo demo;

Spring项目是无法找到唯一对应的。

代码应该为

public interface Demo{ void demo(); } @Component("demoA") public class Aclass implements Demo{ @Overwrite public void demo(){ } } @Component("demoB") public class Bclass implements Demo{ @Overwrite public void demo(){ } }

装配改为

@Resource(name = "demoB") private Demo demo;

此时变量demo 即加载Bclass

结论

综上,当我在失效项目中输入springUtil时出现如下选项

其中出现了三个相同命名的类。并且作用也是一样的。

此时可以确定问题出现在

中,因为我生产项目默认扫描的包是“com.kcsm”。

那么我trade项目本身的springUtil加载和common包内的加载由于是同名的类。其实再注入的时候,由于beanName的命名冲突有一个是无法注入到项目中的;

自然无法加载到 ApplicationContext applicationContext 变量。

解决方式

为该bean命名

import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component; import java.util.Map; /** * @author: yuyangkang * @Title: SpringUtil * @ProjectName: settle * @Description: * @date: 2021/7/25 18:20 */ @Component("tradeSpringUtil") public class SpringUtil implements ApplicationContextAware { private static ApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext applicationContext) { SpringUtil.applicationContext = applicationContext; } public static <T> T getBean(String beanName) { if(applicationContext.containsBean(beanName)){ return (T) applicationContext.getBean(beanName); }else{ return null; } } public static <T> Map<String, T> getBeansOfType(Class<T> baseType){ return applicationContext.getBeansOfType(baseType); } }

为该修改类名

import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component; import java.util.Map; /** * @author: yuyangkang * @Title: SpringUtil * @ProjectName: settle * @Description: * @date: 2021/7/25 18:20 */ @Component public class SpringUtilForSome implements ApplicationContextAware { private static ApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext applicationContext) { SpringUtil.applicationContext = applicationContext; } public static <T> T getBean(String beanName) { if(applicationContext.containsBean(beanName)){ return (T) applicationContext.getBean(beanName); }else{ return null; } } public static <T> Map<String, T> getBeansOfType(Class<T> baseType){ return applicationContext.getBeansOfType(baseType); } }

都可解决该问题。

后记·思考

需要注入的bean是否有必要加载到公共包内。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码

)">
< <上一篇
下一篇>>