本文目录
项目技术栈: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.
详细信息如图所示:
因为 @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 的代理还是基于类的动态代理的配置,这种错误提示需要设置基于类的代理才行。
此方案主要是针对原因一导致的问题而使用的解决方法,我项目里的解决方法就是使用方案一搞定的。
- @Slf4j
- @Component
- public class MusicQueryStateManager {
-
- @Autowired
- private MqttMessageComponent mqttMessageComponent;
- @Resource
- private HomeRpc homeRpc;
- @Resource
- private RedisTemplate
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
完结!