【异常】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
完结!
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)