Bean 注入失败问题汇总
阅读本文大概需要 5 分钟。
来自:blog.csdn.net/qq_51439643/article/details/124781526
目录
错误案例 常见情况一:bean 没有被扫描 常见情况二:多模块架构 bean 没有被扫描 常见情况三:使用 @Qualifier
或@Resource
注入时指定的 name 不存在常见情况四:在拦截器或过滤器或监听器中注入 bean 使用 IDEA 工具查看 IOC 容器
错误案例
常见情况一:bean 没有被扫描
com.training
包下放置主函数与服务代码,在 com.utils
包下放置一些配置与工具类。com.training
,所以在com.training
包与其子包下的 Bean 会被默认自动扫描加入到 Spring 容器中。com.utils
包不包含在默认扫描的包之内,就算是将 bean1 对象使用注解尝试注入容器,Spring 也不会扫描到该类,因此这是大部分 bean 注入失败的原因。com.utils
包加入到扫描中,可以使用 @ComponentScan
指定额外的扫描包,配置如下:package com.training;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication
// 将com.utils 包加入到 Spring 扫描范围中
@ComponentScan(basePackages = {"com.training","com.utils"})
@MapperScan(basePackages = "com.training.dao")
public class MusicMainClass {
public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(MusicMainClass.class, args);
}
}
@ComponetScan
后默认的扫描位置会发生改变,因此添加新的扫描包后要确保启动类所在的包也能被扫描到!@ComponentScan
进行配置,@SpringBootApplication
中的 scanBasePackages
属性指定也能起到同样的作用,配置方式如下:package com.training;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
// 使用 scanBasePackages 属性同样能够实现
@SpringBootApplication(scanBasePackages = {"com.training","com.utils"})
@MapperScan(basePackages = "com.training.dao")
public class MusicMainClass {
public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(MusicMainClass.class, args);
}
}
常见情况二:多模块架构 bean 没有被扫描
com.common.*
,而启动类所在的包路径为:com.training.*
,因此子模块中的 bean 无法被 Spring 自动扫描到。@ComponentScan
或 ScanbasePackages
属性,这里不过多赘述。常见情况三:使用@Qualifier 或 @Resource 注入时指定的 name 不存在
@Component
、@Repository
、@Service
、@Controller
去把一个类配置为bean时,如果不指定bean的名称,那么 bean 的名称的默认规则是:类名的首字母小写,例如:类名称 UserDao ,那么默认的bean名称 userDao
如果类名前两个(或两个以上)连续的字母都是大写,那么默认的bean名称与类名一样,例如:类名称 MIXDao ,那么默认的bean名称 MIXDao
@Bean + @Configuration
注入 bean 时,如果不指定 bean 的名称,那么 bean 的名称默认规则是:bean 名称与注入的方法名同名@Autowired
注解能够自动注入同类型的 bean,但如果与该属性同类型的 bean 不止一个存在时,Spring 无法判断具体注入哪个 bean ,@Qualifer
注解就能够解决这样的歧义。@Qualifer
能够指定 value 字段指定需要注入 bean 的名称,通过指定名称来指定 Spring 到底应该注入哪一个 bean ,这样就能消除歧义,例如下面的例子:public class Teacher{
@Autowired
private Student student;
}
<bean id="teacher" class="com.test.Teacher"/>
# 下面有两个相同类型不同 name 的 Student bean
<bean id="student1"class="com.test.Student">
<property name="name"value="zhangsan"/>
</bean>
<bean id="student2"class="com.test.Student">
<property name="name"value="lisi"/>
</bean>
@Autowired
注解产生了歧义,因此需要使用 @Qualifer
注解消除歧义:public class Teacher{
@Qualifer(value = "student1")
@Autowired
private Student student;
}
@Resource
注解默认通过 名称 进行注入,名称可以通过 name 属性进行指定,如果没有指定name属性,当注解写在字段上时,默认取字段名进行安装名称查找,如果注解写在setter方法上默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型进行装配。@Qualifer
注解进行限定。常见情况四:在拦截器或过滤器或监听器中注入 bean
SpringBoot + SpringSecurity
做认证授权处理,确定注入的 bean 能够被 Spring 扫描到,同时在 Controller、Service 层的注入也没有问题,但是在用户授权过滤器 UsernamePasswordAuthenticationFilter
中死活就是注入不了 bean。context-param–>listener–>filter–>servlet --> … -> Bean 的实例化
context-param–>listener–>filter–>servlet–>interceptor(指的是拦截器) --> … -> Bean 的实例化
使用 IDEA 工具查看 IOC 容器
推荐阅读:
Jenkins+Docker 实现一键自动化部署项目!步骤齐全,少走坑路
终于搞懂了 @Configuration 和 @Component 的区别
互联网初中高级大厂面试题(9个G) 内容包含Java基础、JavaWeb、MySQL性能优化、JVM、锁、百万并发、消息队列、高性能缓存、反射、Spring全家桶原理、微服务、Zookeeper......等技术栈!
⬇戳阅读原文领取! 朕已阅