Spring提供了BeanPostProcessor、BeanFactoryPostProcessor两大类后置处理器
- BeanPostProcessor:属于 bean 生命周期阶段(依赖注入, 初始化)的扩展功能。@Autowired、@Resource、@Value 等注解的解析由不同的 Bean后处理器来完成。
- BeanFactoryPostProcessor:主要就是补充了一些 bean 定义。@ComponentScan, @Bean, @Mapper 等注解的解析属于核心容器(即 BeanFactory)的扩展功能,这些扩展功能由不同的 BeanFactory 后处理器来完成。
Bean后置处理器
后置处理器 | 功能 |
---|---|
AutowiredAnnotationBeanPostProcessor | 解析 @Autowired 与 @Value |
CommonAnnotationBeanPostProcessor | 解析 @Resource、@PostConstruct、@PreDestroy |
ConfigurationPropertiesBindingPostProcessor | 解析 @ConfigurationProperties |
案例演示
准备Bean
public class Bean1 {
private static final Logger log = LoggerFactory.getLogger(Bean1.class);
private Bean2 bean2;
@Autowired
public void setBean2(Bean2 bean2) {
log.debug("@Autowired 生效: {}", bean2);
this.bean2 = bean2;
}
@Autowired
private Bean3 bean3;
@Resource
public void setBean3(Bean3 bean3) {
log.debug("@Resource 生效: {}", bean3);
this.bean3 = bean3;
}
private String home;
@Autowired
public void setHome(@Value("${JAVA_HOME}") String home) {
log.debug("@Value 生效: {}", home);
this.home = home;
}
@PostConstruct
public void init() {
log.debug("@PostConstruct 生效");
}
@PreDestroy
public void destroy() {
log.debug("@PreDestroy 生效");
}
@Override
public String toString() {
return "Bean1{" +
"bean2=" + bean2 +
", bean3=" + bean3 +
", home='" + home + '\'' +
'}';
}
}
public class Bean2 {
}
public class Bean3 {
}
@ConfigurationProperties(prefix = "java")
public class Bean4 {
private String home;
private String version;
public String getHome() {
return home;
}
public void setHome(String home) {
this.home = home;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
@Override
public String toString() {
return "Bean4{" +
"home='" + home + '\'' +
", version='" + version + '\'' +
'}';
}
}
测试
public static void main(String[] args) {
//GenericApplicationContext 是一个【干净】的容器, 不会注入后置处理器
GenericApplicationContext context = new GenericApplicationContext();
//用原始方法注册三个 bean
context.registerBean("bean1", Bean1.class);
context.registerBean("bean2", Bean2.class);
context.registerBean("bean3", Bean3.class);
context.registerBean("bean4", Bean4.class);
//@Value("${JAVA_HOME}") String home 作为方法参数解析 需要添加这个处理
context.getDefaultListableBeanFactory().setAutowireCandidateResolver(
new ContextAnnotationAutowireCandidateResolver());
//解析 @Autowired @Value
context.registerBean(AutowiredAnnotationBeanPostProcessor.class);
//解析 @Resource @PostConstruct @PreDestroy
context.registerBean(CommonAnnotationBeanPostProcessor.class);
//解析 @ConfigurationProperties
ConfigurationPropertiesBindingPostProcessor.register(context.getDefaultListableBeanFactory());
//初始化容器
context.refresh(); // 执行beanFactory后处理器, 添加bean后处理器, 初始化所有单例
System.out.println(context.getBean(Bean1.class));
System.out.println(context.getBean(Bean4.class));
//销毁容器
context.close();
}
@Autowired bean 后置处理器运行分析
public class DigInAutowired {
public static void main(String[] args) throws Throwable {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
//这样注册的bean不会进行依赖注入,初始化的过程
beanFactory.registerSingleton("bean2", new Bean2());
beanFactory.registerSingleton("bean3", new Bean3());
//不加的时候解析@Value的信息会报错
beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
AutowiredAnnotationBeanPostProcessor processor = new AutowiredAnnotationBeanPostProcessor();
processor.setBeanFactory(beanFactory);
Bean1 bean1 = new Bean1();
System.out.println(bean1);
// 执行依赖注入 @Autowired @Value
processor.postProcessProperties(null, bean1, "bean1");
System.out.println(bean1);
}
}
查看postProcessProperties源码,调用了InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);使用反射获取里面的信息,发现使用@Value @Autowired 的成员变量,方法参数信息都被封装到了InjectionMetadata对象里面。
Method findAutowiringMetadata = AutowiredAnnotationBeanPostProcessor.class.getDeclaredMethod(
"findAutowiringMetadata", String.class, Class.class, PropertyValues.class);
findAutowiringMetadata.setAccessible(true);
// 获取 Bean1 上加了 @Value @Autowired 的成员变量,方法参数信息
InjectionMetadata metadata = (InjectionMetadata) findAutowiringMetadata.invoke(processor,
"bean1", Bean1.class, null);
System.out.println(metadata);
通过上面的可以知道:AutowiredAnnotationBeanPostProcessor执行依赖注入的时候
- 调用postProcessProperties方法,找到标注为@Value @Autowired 的成员变量和方法
- 调用 InjectionMetadata 来进行依赖注入, 注入时按类型查找值
metadata.inject(bean1, “bean1”, null);
@Value的值没有解析
查看日志发现JAVA_HOME的信息没有被注入到home中,这是因为容器少加了一个解析器
// ${} 的解析器
beanFactory.addEmbeddedValueResolver(new StandardEnvironment()::resolvePlaceholders);
InjectionMetadata内部处理机制
- InjectionMetadata 内部根据成员变量,方法参数封装为 DependencyDescriptor 类型
- 有了 DependencyDescriptor,就可以利用 beanFactory.doResolveDependency 方法进行基于类型的查找
//加了 @Autowired成员变量的依赖注入
Field bean3 = Bean1.class.getDeclaredField("bean3");
DependencyDescriptor dd1 = new DependencyDescriptor(bean3, false);
Object o = beanFactory.doResolveDependency(dd1, null, null, null);
System.out.println(o);
//加了 @Autowired方法的依赖注入
Method setBean2 = Bean1.class.getDeclaredMethod("setBean2", Bean2.class);
DependencyDescriptor dd2 =
new DependencyDescriptor(new MethodParameter(setBean2, 0), true);
Object o1 = beanFactory.doResolveDependency(dd2, null, null, null);
System.out.println(o1);
//加了 @Value的依赖注入
Method setHome = Bean1.class.getDeclaredMethod("setHome", String.class);
DependencyDescriptor dd3 = new DependencyDescriptor(new MethodParameter(setHome, 0), true);
Object o2 = beanFactory.doResolveDependency(dd3, null, null, null);
System.out.println(o2);
BeanFactory后置处理器
后置处理器 | 功能 |
---|---|
ConfigurationClassPostProcessor | 可以解析@ComponentScan、@Bean、@Import、@ImportResource |
MapperScannerConfigurer | 可以解析Mapper 接口 |
案例演示
pom文件
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.8</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
定义Bean
public class Bean1 {
private static final Logger log = LoggerFactory.getLogger(Bean1.class);
public Bean1() {
log.debug("我被 Spring 管理啦");
}
}
@Configuration
@ComponentScan("com.javaming.study.spring.heima.a05.component")
public class Config {
@Bean
public Bean1 bean1() {
return new Bean1();
}
@Bean
public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource) {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource);
return sqlSessionFactoryBean;
}
@Bean(initMethod = "init")
public DruidDataSource dataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUrl("jdbc:mysql://localhost:3306/test");
dataSource.setUsername("root");
dataSource.setPassword("root");
return dataSource;
}
}
//component目录下定义的类
@Component
public class Bean2 {
private static final Logger log = LoggerFactory.getLogger(Bean2.class);
public Bean2() {
log.debug("我被 Spring 管理啦");
}
}
@Controller
public class Bean3 {
private static final Logger log = LoggerFactory.getLogger(Bean3.class);
public Bean3() {
log.debug("我被 Spring 管理啦");
}
}
测试发现:只打印了config一个bean,Bean1、Bean2这些类都没有注入。
public static void main(String[] args) throws IOException {
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("config", Config.class);
//初始化容器
context.refresh();
for (String name : context.getBeanDefinitionNames()) {
System.out.println(name);
}
//销毁容器
context.close();
}
容器中注册ConfigurationClassPostProcessor后,
// @ComponentScan @Bean @Import @ImportResource
context.registerBean(ConfigurationClassPostProcessor.class);
如何增加@Mapper的扫描
@Mapper
public interface Mapper1 {
}
// @MapperScanner 指定扫描的包
context.registerBean(MapperScannerConfigurer.class, bd -> {
bd.getPropertyValues().add("basePackage", "com.javaming.study.spring.heima.a05.mapper");
});
发现除了扫描到的@Mapper文件,还会帮我们加上其他的后置处理器