1、完整报错
2023-06-29 16:17:28.127 WARN 3732 --- [ main] ConfigServletWebServerApplicationContext : Exception encountered during context
initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'sysLogAspect': Unsatisfied dependency expressed through field 'remoteSysLogService';
nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean
of type 'cn.ycl.system.api.syslog.feign.RemoteSysLogService' available: expected at least 1 bean which qualifies as autowire candidate.
Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
2023-06-29 16:17:28.154 INFO 3732 --- [ main] o.apache.catalina.core.StandardService : Stopping service [Tomcat]
2022-06-29 16:17:28.167 INFO 3732 --- [ main] ConditionEvaluationReportLoggingListener :
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2023-06-29 16:17:28.189 ERROR 3732 --- [ main] o.s.b.d.LoggingFailureAnalysisReporter :
***************************
APPLICATION FAILED TO START
***************************
Description:
Field remoteSysLogService in cn.ycl.syslog.SysLogAspect required a bean of type 'cn.ycl.system.api.syslog.feign.RemoteSysLogService' that could not be found.
The injection point has the following annotations:
- @org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean of type 'cn.ycl.system.api.syslog.feign.RemoteSysLogService' in your configuration.
Disconnected from the target VM, address: '127.0.0.1:63200', transport: 'socket'
Process finished with exit code 1
可以看到异常提示是:NoSuchBeanDefinitionException,报这种错一般就是Spring注入bean实例失败了。
2、我的最终解决方式
在启动类的@EnableFeignClients后面加上包扫描路径,如下:
import com.pig4cloud.pigx.common.feign.annotation.EnablePigxFeignClients;
import com.pig4cloud.pigx.common.security.annotation.EnablePigxResourceServer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
/**
* @author
* @date 2023年06月21日 app消息推送服务
*/
@EnablePigxFeignClients
@EnablePigxResourceServer
@EnableDiscoveryClient
@SpringBootApplication
public class LnPushApplication {
public static void main(String[] args) {
SpringApplication.run(LnPushApplication.class, args);
}
}
3、为什么那么久才找到解决办法
如果只有一个启动类中存在@EnableFeignClients注解,那么不需要加basepackage也不会报错并启动成功;
但是一旦有了两个或以上的业务模块作为feign客户端,也就是有两个以上的启动类上存在@EnableFeignClients注解,不加basepackage将报如上错误。
4、没有集成feign时,报此错的解决办法
前面说了,报这种错一般就是Spring注入bean实例失败,所以要么是包扫描路径的问题,比如我遇到的这个问题,以及经典的启动类上没有配置mapper包扫描路径,导致报错XxxMapper类找不到,或者XxxDao类找不到:
要么就是报错的bean上面没有加注解,比如@Service、@Component、@Mapper、@Repository、@Configuration、@RestController等。
看过SpringBoot启动类源码的都知道,Spring boot只会将两种类注入bean容器中:
第一种:要么是在Resource/META-INF/spring.factories文件夹下手动配置的类;
第二种:要么是在启动类所属包下,且被@Component或其派生注解修饰的类(上面提到的注解都是@Component的派生注解)
才会被注入bean容器中。
5、集成了openfeign时的其他可能原因
1、feign接口是否定义了实现类,最好添加实现类
2、feign接口实现类上方是否加了@Service注解
3、一般定义feign接口的模块都是没有启动类的模块,若想要在其他模块调用此模块中的feign接口,是否在Resource/META-INF/spring.factories中手动配置了feign接口的实现类
6、补充
feign接口写法示例:
import com.pig4cloud.pigx.admin.api.interceptor.FeignRequestInterceptor;
import com.pig4cloud.pigx.common.core.constant.ServiceNameConstants;
import com.xxl.job.core.biz.model.ReturnT;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import push.entity.MessagePush;
/**
* @author
* @date 2023/5/9
* <p>
* app消息推送服务
*/
@FeignClient(contextId = "remoteMessagePushService", value = ServiceNameConstants.PUSH_SERVER,configuration = {FeignRequestInterceptor.class})
public interface RemoteMessagePushService {
/**
* app消息推送
* @param vo
* @return ReturnT
*/
@PostMapping("/lnrq/message/push")
public ReturnT saveMessagePush(@RequestBody MessagePush vo);
}
import com.pig4cloud.pigx.common.security.annotation.Inner;
import com.xxl.job.core.biz.model.ReturnT;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import push.entity.MessagePush;
import push.service.impl.MessagePushServiceImpl;
/**
* 业务类型表
*
* @author Roger 652321516@qq.com
* @since 1.0.0 2023-04-03
*/
@RestController
@CrossOrigin
@RequestMapping("/lnrq/message")
public class MessagePushController {
@Autowired
private MessagePushServiceImpl messagePushServiceImpl;
@Inner(value = false)
@PostMapping("/push")
public ReturnT push(@RequestBody MessagePush vo) {
messagePushServiceImpl.saveMessagePush(vo);
return new ReturnT("推送成功");
}
}
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xxl.job.core.biz.model.ReturnT;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import push.entity.MessagePush;
import push.handler.AliPush;
import push.handler.MessageSendDTO;
import push.mapper.MessagePushMapper;
import push.service.MessagePushService;
import java.util.concurrent.TimeUnit;
@Slf4j
@Service
@AllArgsConstructor
public class MessagePushServiceImpl extends ServiceImpl<MessagePushMapper, MessagePush> implements MessagePushService {
@Autowired
private MessagePushMapper messagePushMapper;
@Autowired
private RedisTemplate redisTemplate;
@Autowired
private AliPush aliPush;
/**
* app推送消息,保存消息
*/
@Override
@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
public ReturnT saveMessagePush(MessagePush vo) {
//调用推送sdk
MessageSendDTO dto = new MessageSendDTO();
dto.setTitle(vo.getTitle());
dto.setContent(vo.getContent());
aliPush.pushIOSMessage(dto,Long.valueOf(vo.getReceiveUserId()));
aliPush.pushAndroidMessage(dto,Long.valueOf(vo.getReceiveUserId()));
//入库
messagePushMapper.saveMessagePush(vo);
Long id = vo.getId();
//保存消息到 redis
redisTemplate.setHashValueSerializer(new Jackson2JsonRedisSerializer<>(MessagePush.class));
redisTemplate.opsForHash().put("pm: push_massage", String.valueOf(id), vo);
redisTemplate.expire("pm: push_massage", 90, TimeUnit.DAYS);
return ReturnT.SUCCESS;
}
/**
* 查询消息
*/
@Override
public IPage<MessageSendDTO> getMessagePushList(Page page, MessageSendDTO params) {
IPage<MessageSendDTO> result = messagePushMapper.getMessagePushList(page, params);
return result;
}
}