【异常】because it is a JDK dynamic proxy that implements

本文涉及的产品
云数据库 Redis 版,标准版 2GB
推荐场景:
搭建游戏排行榜
云原生内存数据库 Tair,内存型 2GB
简介: 【异常】because it is a JDK dynamic proxy that implements

一、背景描述

项目技术栈:Spring boot (2.1.5.RELEASE) + mqtt (5.1.5.RELEASE)

项目是一个 Springboot 项目,集成了 EMQX,项目在启动时,提示应用启动失败,详情如下:

***************************
APPLICATION FAILED TO START
***************************
Description:
The bean 'mqttSender' could not be injected as a 'com.iot.back.net.device.infrastructure.component.MqttMessageComponent' because it is a JDK dynamic proxy that implements:
Action:
Consider injecting the bean as one of its interfaces or forcing the use of CGLib-based proxies by setting proxyTargetClass=true on @EnableAsync and/or @EnableCaching.

详细信息如图所示:

二、问题原因

原因一:使用 @Resource 注解导致的问题

因为 @Autowired 默认按类型装配,而 @Resource 优先按名称装配。

比如项目中存在一个 RedisTemplate bean,而由于需求的原因,又自定义了一个 RedisTemplate (比如切换 Redis 的数据库时),然后如果使用 @Resource 注解,由于项目中已经有另外一个 bean 叫 “RedisTemplate”,也可能出现这个错误。

原因二:粗心导致

比如基于 xml 的配置

<bean id="powerSwtichService" class="com.xxx.xxx.xxx.xx.PowerSwtichService"/>

这里的 class 并不是实际应该配置的:com.xxx.xxx.xxx.xx.PowerSwtichService

原因三:注解配置缺少属性

@EnableAsync、@EnableCaching 或者 @EnableAspectJAutoProxy 再或者 @EnableTransactionManagement 这些注解都可以设置 proxyTargetClass = true 属性

主要配置基于 JDK 的代理还是基于类的动态代理的配置,这种错误提示需要设置基于类的代理才行。

三、解决方案

方案一:自动注入使用 @Autoware 注解

此方案主要是针对原因一导致的问题而使用的解决方法,我项目里的解决方法就是使用方案一搞定的。

@Slf4j
@Component
public class MusicQueryStateManager {
    @Autowired
    private MqttMessageComponent mqttMessageComponent;
    @Resource
    private HomeRpc homeRpc;
    @Resource
    private RedisTemplate<String, String> redisTemplateDb16;
    public void handleDeviceAction(CommonControlParam controlParam) {
        log.info("E|MusicQueryStateManager|handleDeviceAction()|处理设备动作控制查询状态!controlParam = {}", JSONUtil.toJsonStr(controlParam));
        String hostSn = homeRpc.getHostSnByHomeSn(controlParam.getSn());
        String key = RedisKeyConstants.DEVICE_STATE + controlParam.getSn() + StrUtil.COLON + controlParam.getDeviceId();
        String value = redisTemplateDb16.opsForValue().get(key);
        DeviceStateDTO deviceStateDTO = JSONObject.parseObject(value, DeviceStateDTO.class);
        Assert.notNull(deviceStateDTO, "deviceStateDTO不能为空!");
        sendMessageToOpenPlatform(controlParam, hostSn, deviceStateDTO.getProperties());
    }
    /**
     * 发送消息给开放平台
     *
     * @param controlParam 控制请求参数
     * @param hostSn       主机sn
     */
    private void sendMessageToOpenPlatform(CommonControlParam controlParam, String hostSn, JSONObject properties) {
        String uuid = controlParam.getUuid();
        String topic = "thirdBgmusic/tgw_cloud/control/" + uuid + "/queryState";
        JSONObject data = new JSONObject();
        data.put("channel", 1);
        data.put("properties", properties);
        MqttMessagePublisher mqttPublisher = new MqttMessagePublisher.Builder()
                .title("背景音乐设备动作控制播放状态消息发送!")
                .topic(topic)
                .identity(hostSn)
                .clientType("tgw_host")
                .msgId(controlParam.getMsgId())
                .compression(CompressionEnum.ZLIB.getType())
                .encry(false)
                .data(data)
                .params(Params.create().set("sn", hostSn))
                .build();
        mqttMessageComponent.sendMessage(mqttPublisher);
    }
}

方案二:仔细检查配置文件

比如 xml 配置文件,properties 配置文件,yml 配置文件等。

方案三:注解里添加必要的属性

比如:

  • @EnableAsync(proxyTargetClass = true) 或者
  • @EnableCaching(proxyTargetClass = true) 或者
  • @EnableAspectJAutoProxy(proxyTargetClass = true) 或者
  • @EnableTransactionManagement(proxyTargetClass = true)

proxy-target-class 属性值决定是基于 JDK 接口还是基于类的代理被创建。

  • 如果为 true 代表基于类的代理,
  • 如果为 false 代表基于 JDK 接口的代理。

如果 springboot 项目,也可以在配置文件里写上如下内容:

spring.aop.proxy-target-class=true

 

完结!


相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
Java
java202303java学习笔记第三十五天IO流中不同JDK版本捕获异常的方式1
java202303java学习笔记第三十五天IO流中不同JDK版本捕获异常的方式1
69 0
如何处理JDK线程池内线程执行异常?讲得这么通俗,别还搞不懂
本篇 《如何处理 JDK 线程池内线程执行异常》 这篇文章适合哪些小伙伴阅读呢? 适合工作中使用线程池却不知异常的处理流程,以及不知如何正确处理抛出的异常
|
Java
java202303java学习笔记第三十五天IO流中不同JDK版本捕获异常的方式2
java202303java学习笔记第三十五天IO流中不同JDK版本捕获异常的方式2
56 0
|
Java
java202303java学习笔记第三十五天IO流中不同JDK版本捕获异常的方式3
java202303java学习笔记第三十五天IO流中不同JDK版本捕获异常的方式3
57 0
如何处理 JDK 线程池内线程执行异常
如何处理 JDK 线程池内线程执行异常
127 2
|
Java
Java(JDK)13新特性之Dynamic CDS Archives
Java(JDK)13新特性之Dynamic CDS Archives
208 0
|
缓存 Java
电脑蓝屏重启后IDEA导包异常setup JDK
电脑正常开发过程中突然卡死不动(不是代码的问题,是电脑CPU处理器较老),操作鼠标键盘都无任何反应,一段时间后电脑蓝屏自动重启,重启后打开IDEA项目,结果发现所有的导包全部报红
电脑蓝屏重启后IDEA导包异常setup JDK
|
Java Linux 开发工具
Linux(CentOS)中常用软件安装,使用及异常——XManager, 中文支持,JDK
XManager图形化界面远程连接 采用Xshell的方式可以不用在CentOS系统中配置即可以相连,主要原理就是SSH连接的方式,但是XManager图形化界面远程连接是需要修改CentOS系统的。
1549 0
JDK1.7新特性(2):异常和可变长参数处理
异常   jdk1.7对try--catch--finally的异常处理模式进行了增强,下面我们依次来看增强的方面。   1. 为了防止异常覆盖,给Throwable类增加了addSuppressed方法,可以将一个异常信息追加到另一个异常信息之后: 1 /** 2 * 这是第一种防止前面异常被覆盖的方法,通过在finally块中判断前面是否有异常抛出 3 * 如果有则最终抛出的异常为原来的异常,没有则最终抛出的异常为finally块中的异常。
928 0