热部署引发的类型转换异常

热部署引发的类型转换异常

起因

主要公司有个老的项目,想合并,里面有个工作流,里面需要配置监听器,然后监听器需要用到spring管理的其他的类,然后如果用@Component,@Autowired来注入的话,项目启动会报找不到这个类的问题,然后我以为是有同名类,导致注入不进去,所以我改用@Component(“”)来声明,注入的时候,也用@Resource(name ="kaptchaProducer"``),但是注入的bean的时候,会报类型转换异常。

既然不让我用spring的主动注入,那我就用SpringContextUtils,注入ApplicationContext来获取bean。

但是就出现了奇怪的问题。

类型转换异常

这个框架用的是一个开源的框架,里面自己写了springholder,然后我用这个工具类,去拿类的时候,报了个类型转换异常,一个代理类不能转换为原类,emmm,我以为是因为用的cglib的动态代理,不是jdk的动态代理,导致转换异常,然后我就把注入的这个类实现了接口,然后我用接口来接,emm,还是转换异常,没办法了,是不是这个工具类有问题,我用SpringContextUtils自己的工具类试试。

空指针问题

如果我把需要注入的bean当做属性来管理的话,

 */
@Slf4j
@Data
public class BusinessRejectListener extends BusinessTaskBasicListener {

    private ActTaskService actTaskService = (ActTaskService) SpringContextUtils.getBean(ActTaskService.class);

这里的时候,报了个空指针问题,emmm。我的理解是,这个监听器的加载时间是在类的加载的时候,而SpringContextUtils的注入,是在容器初始化后再注入容器的,导致空指针问题。

那么我就用到的地方在再来使用。

private void copyAct(String businessKey) {
    ActTaskService actTaskService = (ActTaskService) SpringContextUtils.getBean(ActTaskService.class);
    actTaskService.copyAct(businessKey);
}

妈的,还是报空指针问题,是我没注入ApplicationContext吗。

debug一下。

SpringContextUtils有两种写法,一种是实现ApplicationContextAware ,然后注入。一种是利用springboot的启动方法注入。

public static void main(String[] args) {

    SpringApplication app = new SpringApplication(ActivityApplication.class);
    ConfigurableApplicationContext ctx = app.run(args);
    SpringContextUtils.setApplicationContext(ctx);
}

我debug一看,更奇怪了,注入进来了。可是一到用的地方,又是空指针。为啥啊

结果

一下子,陷入了死局,为什么已经注入了属性,可是为什么到具体使用的时候,里面的属性是又为空了,是又被注入了null?不对啊,debug的时候,只有一次。

那为什么呢。莫非这两个类不是同一个类,我用反射去拿下这个类的静态属性看看。

https://blog.csdn.net/huangshanchun/article/details/78308833

private static List<String> getStaticField() throws Exception {
    List<String> result = new ArrayList<String>();

    Field[] fields = Test.class.getDeclaredFields();
    if (fields == null || fields.length <= 0) {
        return result;
    }

    for (Field field : fields) {
        field.setAccessible(true);
        //只获取字符串类型
        if (field.getType() == String.class && Modifier.isStatic(field.getModifiers())) {
            result.add(String.valueOf(field.get(Test.class)));
        }
    }
    return result;
}

emm。还是为空。那为什么呢。问题是,jvm如何确定一个类是一个类的呢。我记起来了,jvm是通过全限定类名+classloader来确定一个类是一个类,这样同名同包类不会被当做一个类。然后jdk的类也不会因此而被覆盖。

那是不是这两个类的加载器不同。

然后注意了下项目启动时加载项目中的SpringContextUtils类使用的加载器都是
org.springframework.boot.devtools.restart.classloader.RestartClassLoader
而从监听器取出来的对象的类加载器都是
sun.misc.Launcher.AppClassLoader。

问题解决了,从类加载就能看出来,org.springframework.boot.devtools.restart.classloader.RestartClassLoader是热部署的类加载器。然后百度一看,大家都遇到过这个问题,SpringBoot使用devtools导致的类型转换异常

https://blog.csdn.net/qq_35893120/article/details/85161091?utm_medium=distribute.pc_relevant.none-task-blog-baidujs_title-3&spm=1001.2101.3001.4242

那么问题就很清楚了,这是因为启用热部署之后,启动时使用的类加载器和重新加载使用的类加载器不一样导致的。

那么去掉热部署的pom,问题就解决了。

那么之前的问题就都能解释了。为什么会空指针,会类型转换异常,会注入失败。都是这个类加载器不同的原因,监听器的加载器都是默认的加载器,而我们写的类,都是被热部署插件自己的加载器加载的,所以自己类注入没问题,到监听器注入,获取类都失败了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值