笔记参考B站黑马程序员视频:spring原理
1.Bean的生命周期
Bean的生命周期主要包括以下几个阶段:创建,依赖注入,初始化,销毁
需要一个启动类
package com.dreams.demo03;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
/*
bean 的生命周期, 以及 bean 后处理器
*/
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(DemoApplication.class, args);
// 关闭 ,展示生命周期
context.close();
}
}然后调用方法查看执行顺序
package com.dreams.demo03;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
@Component
public class LifeCycleBean {
private static final Logger log = LoggerFactory.getLogger(LifeCycleBean.class);
public LifeCycleBean() {
log.debug("构造");
}
@Autowired
public void autowire(@Value("${JAVA_HOME}") String home) {
log.debug("依赖注入: {}", home);
}
@PostConstruct
public void init() {
log.debug("初始化");
}
@PreDestroy
public void destroy() {
log.debug("销毁");
}
}执行顺序如下:

InstantiationAwareBeanPostProcessor和DestructionAwareBeanPostProcessor是Spring框架中的两个特定的Bean后置处理器接口,用于在Bean实例化和销毁过程中执行自定义的逻辑。
InstantiationAwareBeanPostProcessor:
InstantiationAwareBeanPostProcessor接口在Bean实例化阶段(即在Bean对象创建之前和之后)提供了扩展点,允许开发者在Bean实例化过程中干预和定制化。
它包含了以下方法:
postProcessBeforeInstantiation():在实例化Bean之前调用,可以返回一个代理对象或者直接返回null来跳过原始实例化。
postProcessAfterInstantiation():在实例化Bean之后,但在任何初始化回调之前调用,允许对实例进行自定义修改。
DestructionAwareBeanPostProcessor:
DestructionAwareBeanPostProcessor接口允许在Bean销毁之前进行处理,通常用于执行一些清理和资源释放的工作。它包含了一个方法:
postProcessBeforeDestruction():在Bean销毁之前调用,允许进行一些清理操作,例如释放资源或发送通知。
这个接口的实现允许开发者在Bean被销毁之前进行最后的操作,确保资源的正确释放和清理,以避免潜在的资源泄漏或其他问题。
代码示例:
package com.dreams.demo03;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import org.springframework.stereotype.Component;
@Component
public class MyBeanPostProcessor implements InstantiationAwareBeanPostProcessor, DestructionAwareBeanPostProcessor {
private static final Logger log = LoggerFactory.getLogger(MyBeanPostProcessor.class);
@Override
public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
if (beanName.equals("lifeCycleBean"))
log.debug("<<<<<< 销毁之前执行, 如 @PreDestroy");
}
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
if (beanName.equals("lifeCycleBean"))
log.debug("<<<<<< 实例化之前执行, 这里返回的对象会替换掉原本的 bean");
return null;
}
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
if (beanName.equals("lifeCycleBean")) {
log.debug("<<<<<< 实例化之后执行, 这里如果返回 false 会跳过依赖注入阶段");
// return false;
}
return true;
}
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
if (beanName.equals("lifeCycleBean"))
log.debug("<<<<<< 依赖注入阶段执行, 如 @Autowired、@Value、@Resource");
return pvs;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (beanName.equals("lifeCycleBean"))
log.debug("<<<<<< 初始化之前执行, 这里返回的对象会替换掉原本的 bean, 如 @PostConstruct、@ConfigurationProperties");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (beanName.equals("lifeCycleBean"))
log.debug("<<<<<< 初始化之后执行, 这里返回的对象会替换掉原本的 bean, 如代理增强");
return bean;
}
}
2.Bean后处理器
@Autowired 等注解的解析属于 bean 生命周期阶段(依赖注入,初始化)的扩展功能,这些扩展功能由 bean 后处理器来完成
GenericApplicationContext 是一个非常基本的 Spring 应用上下文实现。它不会自动添加任何预定义的 Bean 后处理器或配置。而AnnotationConfigApplicationContext 是基于注解配置的 Spring 应用上下文实现。它会自动注册一些常用的 Bean 后处理器,如 AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor 等。这些后处理器用于处理注解驱动的依赖注入、通用注解的处理等。
这里使用GenericApplicationContext
Bean配置
package com.dreams.demo04;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
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 + '\'' +
'}';
}
}
class Bean2 {
}
class Bean3 {
}如上代码,如果注入成功应该会输出日志
启动类:
package com.dreams.demo04;
import org.springframework.context.support.GenericApplicationContext;
/*
bean 后处理器的作用
*/
public class DemoApplication {
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);
// 初始化容器
context.refresh(); // 执行beanFactory后处理器, 添加bean后处理器, 初始化所有单例
System.out.println(context.getBean(Bean1.class));
// ️销毁容器
context.close();
}
}
可以看到没有添加Bean后置处理器是没有注入成功的,所以没有输出日志
添加一个@Autowired @Value的后置处理器,配置在初始化容器之前
context.registerBean(AutowiredAnnotationBeanPostProcessor.class); // @Autowired @Value // 初始化容器 context.refresh(); // 执行beanFactory后处理器, 添加bean后处理器, 初始化所有单例
不过这时运行会报错

问题出在这里
@Autowired
public void setHome(@Value("${JAVA_HOME}") String home) {
log.debug("@Value 生效: {}", home);
this.home = home;
}默认无法获取String类型注入,就是@Value的问题
调用 getDefaultListableBeanFactory() 方法获取了 GenericApplicationContext 的默认 bean 工厂,并且设置了一个新的 AutowireCandidateResolver,即 ContextAnnotationAutowireCandidateResolver。
context.getDefaultListableBeanFactory().setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver()); context.registerBean(AutowiredAnnotationBeanPostProcessor.class); // @Autowired @Value // 初始化容器 context.refresh(); // 执行beanFactory后处理器, 添加bean后处理器, 初始化所有单例
这样就成功了

CommonAnnotationBeanPostProcessor用于处理包括 @Resource、@PostConstruct 和 @PreDestroy。
同样在reflesh方法前配置
// @Resource @PostConstruct @PreDestroy context.registerBean(CommonAnnotationBeanPostProcessor.class); // @Resource @PostConstruct @PreDestroy

还有一个springboot的后处理器,在 Spring Boot 中,@ConfigurationProperties 注解用于将配置文件中的属性值映射到一个 Java Bean 中
package com.dreams.demo04;
import org.springframework.boot.context.properties.ConfigurationProperties;
/*
java.home=
java.version=
*/
@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 + '\'' +
'}';
}
}要处理上面的配置,需要注册一个 ConfigurationPropertiesBindingPostProcessor 实例到 Spring 应用的默认 bean 工厂中。这个后处理器用于处理 @ConfigurationProperties 注解,将配置文件中的属性值绑定到对应的 Java Bean 中。
ConfigurationPropertiesBindingPostProcessor.register(context.getDefaultListableBeanFactory()); // 初始化容器 context.refresh(); // 执行beanFactory后处理器, 添加bean后处理器, 初始化所有单例 System.out.println(context.getBean(Bean4.class));

处理器是怎么处理的
直接创建个AutowiredAnnotationBeanPostProcessor,去调用它的方法,它会去扫描class拿到@Autowired,所以需要拿到那个对象,所以需要传入beanFactory
package com.dreams.demo04;
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.ContextAnnotationAutowireCandidateResolver;
// AutowiredAnnotationBeanPostProcessor 运行分析
public class DigInAutowired {
public static void main(String[] args) throws Throwable {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
beanFactory.registerSingleton("bean2", new Bean2()); // 创建过程,依赖注入,初始化
beanFactory.registerSingleton("bean3", new Bean3());
beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver()); // @Value
// 1. 查找哪些属性、方法加了 @Autowired, 这称之为 InjectionMetadata
AutowiredAnnotationBeanPostProcessor processor = new AutowiredAnnotationBeanPostProcessor();
processor.setBeanFactory(beanFactory);
Bean1 bean1 = new Bean1();
System.out.println(bean1);
processor.postProcessProperties(null, bean1, "bean1"); // 执行依赖注入 @Autowired @Value
System.out.println(bean1);
}
}postProcessProperties 是 BeanPostProcessor 接口中的一个方法,用于在 Spring 容器加载 bean 属性文件时进行处理。
参数说明:
- propertyValues:bean 的属性值,可以在此方法中对其进行修改或扩展。
- bean:正在被处理的 bean 实例。
- beanName:被处理的 bean 在容器中的名称。
这个方法执行后就@Autowired注入了,如图,可以看到未执行该方法时@Autowired没有注入为空。
这里执行依赖注入 @Autowired @Value,不执行@Resource

看看源码:
调用了 findAutowiringMetadata 方法来获取 InjectionMetadata 对象。这个方法的作用是根据给定的 bean 名称、bean 的类以及属性值来查找适合自动装配的元数据。接着调用 metadata.inject(bean, beanName, pvs)方法来执行依赖注入的过程,也就是使用反射实现。

我们直接在外面通过反射使用这个方法看看
Method findAutowiringMetadata = AutowiredAnnotationBeanPostProcessor.class.getDeclaredMethod("findAutowiringMetadata", String.class, Class.class, PropertyValues.class);
findAutowiringMetadata.setAccessible(true);
InjectionMetadata metadata = (InjectionMetadata) findAutowiringMetadata.invoke(processor, "bean1", Bean1.class, null);// 获取 Bean1 上加了 @Value @Autowired 的成员变量,方法参数信息
System.out.println(metadata);debug一下:
metadata对象里有一个injectedElements,这里存储的就是找到的被@Autowired注解修饰的


注释掉上面直接调用postProcessProperties方法,可以看到调用inject就可以实现注入了
// 调用 InjectionMetadata 来进行依赖注入, 注入时按类型查找值 metadata.inject(bean1, "bean1", null); System.out.println(bean1);

如上还不能在解析${},加上如下代码
beanFactory.addEmbeddedValueResolver(new StandardEnvironment()::resolvePlaceholders); // ${} 的解析器
在自动注入时,是如何按类型查找值的呢,调用如下代码:
Field bean3 = Bean1.class.getDeclaredField("bean3");
DependencyDescriptor dd1 = new DependencyDescriptor(bean3, false);
Object o = beanFactory.doResolveDependency(dd1, null, null, null);
System.out.println(o);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);分别对应读取以下Bean代码:

在运行前,需要实例化

如图:

还有读取配置

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);
3.BeanFactory后处理器
加入两个依赖springboot对mybatis和druid的整合
<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>@ComponentScan, @Bean, @Mapper 等注解的解析属于核心容器(即 BeanFactory)的扩展功能。这些扩展功能由不同的 BeanFactory 后处理器来完成, 其实主要就是补充了一些 bean 定义。
一个配置类
package com.dreams.demo05;
import com.alibaba.druid.pool.DruidDataSource;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;
@Configuration
@ComponentScan("com.dreams.demo05.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.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/mybatis");
dataSource.setUsername("root");
dataSource.setPassword("123456");
return dataSource;
}
}还有
package com.dreams.demo05.component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Component
public class Bean2 {
private static final Logger log = LoggerFactory.getLogger(Bean2.class);
public Bean2() {
log.debug("我被 Spring 管理啦");
}
}再来看启动类,上面应该有5个Bean
package com.dreams.demo05;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.support.GenericApplicationContext;
import java.io.IOException;
/*
BeanFactory 后处理器的作用
*/
public class DemoApplication {
private static final Logger log = LoggerFactory.getLogger(DemoApplication.class);
public static void main(String[] args) throws IOException {
// GenericApplicationContext 是一个【干净】的容器
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("config", Config.class);
// 初始化容器
context.refresh();
for (String name : context.getBeanDefinitionNames()) {
System.out.println(name);
}
// 销毁容器
context.close();
}
}但是在输出了1个

只要加入
ConfigurationClassPostProcessor 负责解析和验证带有 @Configuration 注解的类,确保这些类中的 bean 定义和依赖关系是有效的。它会检查配置类中的各种注解,如 @Bean、@ComponentScan 等,并将它们注册到 Spring 容器中。
// @ComponentScan @Bean @Import @ImportResource context.registerBean(ConfigurationClassPostProcessor.class);

还有一个是处理mapper的
package com.dreams.demo05.mapper;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface Mapper1 {
}package com.dreams.demo05.mapper;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface Mapper2 {
}加入
context.registerBean(MapperScannerConfigurer.class, bd -> { // @MapperScanner
bd.getPropertyValues().add("basePackage", "com.dreams.demo05.mapper");
});
4.自定义处理器
AnnotationUtils.findAnnotation 是 Spring Framework 提供的一个工具方法,用于查找指定类上的特定注解,componentScan.basePackages()可以获取扫描的包路径。
package com.dreams.demo05;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.annotation.AnnotationUtils;
/**
* @author PoemsAndDreams
* @description //
*/
public class Main {
public static void main(String[] args) {
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("Config", Config.class);
ComponentScan componentScan = AnnotationUtils.findAnnotation(Config.class, ComponentScan.class);
if (componentScan != null) {
String[] basePackages = componentScan.basePackages();
for (String p : basePackages) {
System.out.println(p);
}
}
}
}
接着获取该包下的所有类
for (String p : basePackages) {
System.out.println(p);
// com.dreams.a05.component -> classpath*:com/itheima/a05/component/**/*.class
String path = "classpath*:" + p.replace(".", "/") + "/**/*.class";
System.out.println(path);
Resource[] resources = context.getResources(path);
for (Resource resource : resources) {
System.out.println(resource);
}
}
然后可以对这些类读取元信息,CachingMetadataReaderFactory是Spring Framework提供的一个类,用于读取和缓存类文件的元数据信息。利用 CachingMetadataReaderFactory 的 getMetadataReader 方法,传入资源对象 resource,可以获得一个 MetadataReader 对象,该对象包含了资源(类文件)的元数据信息。
CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
Resource[] resources = context.getResources(path);
for (Resource resource : resources) {
System.out.println(resource);
MetadataReader reader = factory.getMetadataReader(resource);
}通过 MetadataReader 对象,调用 getAnnotationMetadata 方法获取该资源的注解元数据信息。AnnotationMetadata 接口提供了方法来查询类的注解信息,使用 hasAnnotation 方法检查该资源是否标注了 @Component 注解。这里 Component.class.getName() 返回 @Component 注解的全限定名。使用 hasMetaAnnotation 方法检查该资源是否标注了任何派生自 @Component 注解的其他注解。
for (Resource resource : resources) {
System.out.println(resource);
MetadataReader reader = factory.getMetadataReader(resource);
AnnotationMetadata annotationMetadata = reader.getAnnotationMetadata();
System.out.println("是否加了 @Component:" + annotationMetadata.hasAnnotation(Component.class.getName()));
System.out.println("是否加了 @Component 派生:" + annotationMetadata.hasMetaAnnotation(Component.class.getName()));
}
全部代码如下:
如果符合条件,则创建相应的 BeanDefinition 对象,并使用 registerBeanDefinition 方法将其注册到 beanFactory 中。
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("Config", Config.class);
ComponentScan componentScan = AnnotationUtils.findAnnotation(Config.class, ComponentScan.class);
if (componentScan != null) {
String[] basePackages = componentScan.basePackages();
for (String p : basePackages) {
System.out.println(p);
// com.dreams.a05.component -> classpath*:com/itheima/a05/component/**/*.class
String path = "classpath*:" + p.replace(".", "/") + "/**/*.class";
System.out.println(path);
CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
Resource[] resources = context.getResources(path);
AnnotationBeanNameGenerator generator = new AnnotationBeanNameGenerator();
for (Resource resource : resources) {
System.out.println(resource);
MetadataReader reader = factory.getMetadataReader(resource);
AnnotationMetadata annotationMetadata = reader.getAnnotationMetadata();
System.out.println("是否加了 @Component:" + annotationMetadata.hasAnnotation(Component.class.getName()));
System.out.println("是否加了 @Component 派生:" + annotationMetadata.hasMetaAnnotation(Component.class.getName()));
if (annotationMetadata.hasAnnotation(Component.class.getName())
|| annotationMetadata.hasMetaAnnotation(Component.class.getName())) {
AbstractBeanDefinition bd = BeanDefinitionBuilder
.genericBeanDefinition(reader.getClassMetadata().getClassName())
.getBeanDefinition();
DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory();
String name = generator.generateBeanName(bd, beanFactory);
beanFactory.registerBeanDefinition(name, bd);
}
}
}
}
context.refresh();
for (String beanDefinitionName : context.getBeanDefinitionNames()) {
System.out.println(beanDefinitionName);
}
完成后的代码,注意import org.springframework.stereotype.Component;不要导错包了
package com.dreams.demo05;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.AnnotationBeanNameGenerator;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.io.Resource;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.stereotype.Component;
import java.io.IOException;
/**
* @author PoemsAndDreams
* @description //
*/
public class Main {
public static void main(String[] args) throws IOException {
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("config", Config.class);
ComponentScan componentScan = AnnotationUtils.findAnnotation(Config.class, ComponentScan.class);
if (componentScan != null) {
String[] basePackages = componentScan.basePackages();
for (String p : basePackages) {
System.out.println(p);
String path = "classpath*:" + p.replace(".", "/") + "/**/*.class";
System.out.println(path);
CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
Resource[] resources = context.getResources(path);
AnnotationBeanNameGenerator generator = new AnnotationBeanNameGenerator();
for (Resource resource : resources) {
System.out.println(resource);
MetadataReader reader = factory.getMetadataReader(resource);
AnnotationMetadata annotationMetadata = reader.getAnnotationMetadata();
System.out.println("是否加了 @Component:" + annotationMetadata.hasAnnotation(Component.class.getName()));
System.out.println("是否加了 @Component 派生:" + annotationMetadata.hasMetaAnnotation(Component.class.getName()));
if (annotationMetadata.hasAnnotation(Component.class.getName())
|| annotationMetadata.hasMetaAnnotation(Component.class.getName())) {
AbstractBeanDefinition bd = BeanDefinitionBuilder
.genericBeanDefinition(reader.getClassMetadata().getClassName())
.getBeanDefinition();
DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory();
String name = generator.generateBeanName(bd, beanFactory);
beanFactory.registerBeanDefinition(name, bd);
}
}
}
}
context.refresh();
for (String beanDefinitionName : context.getBeanDefinitionNames()) {
System.out.println(beanDefinitionName);
}
// 销毁容器
context.close();
}
}
将上面代码整理如下:
处理@Component注解的处理器
package com.dreams.demo05;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.context.annotation.AnnotationBeanNameGenerator;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.stereotype.Component;
import java.io.IOException;
public class ComponentScanPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override // context.refresh
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
}
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanFactory) throws BeansException {
try {
ComponentScan componentScan = AnnotationUtils.findAnnotation(Config.class, ComponentScan.class);
if (componentScan != null) {
for (String p : componentScan.basePackages()) {
System.out.println(p);
// com.dreams.a05.component -> classpath*:com/dreams/demo05/component/**/*.class
String path = "classpath*:" + p.replace(".", "/") + "/**/*.class";
System.out.println(path);
CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
Resource[] resources = new PathMatchingResourcePatternResolver().getResources(path);
AnnotationBeanNameGenerator generator = new AnnotationBeanNameGenerator();
for (Resource resource : resources) {
// System.out.println(resource);
MetadataReader reader = factory.getMetadataReader(resource);
// System.out.println("类名:" + reader.getClassMetadata().getClassName());
AnnotationMetadata annotationMetadata = reader.getAnnotationMetadata();
// System.out.println("是否加了 @Component:" + annotationMetadata.hasAnnotation(Component.class.getName()));
// System.out.println("是否加了 @Component 派生:" + annotationMetadata.hasMetaAnnotation(Component.class.getName()));
if (annotationMetadata.hasAnnotation(Component.class.getName())
|| annotationMetadata.hasMetaAnnotation(Component.class.getName())) {
AbstractBeanDefinition bd = BeanDefinitionBuilder
.genericBeanDefinition(reader.getClassMetadata().getClassName())
.getBeanDefinition();
String name = generator.generateBeanName(bd, beanFactory);
beanFactory.registerBeanDefinition(name, bd);
}
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}处理@mapper的处理器
package com.dreams.demo05;
import org.mybatis.spring.mapper.MapperFactoryBean;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.context.annotation.AnnotationBeanNameGenerator;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.type.ClassMetadata;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import java.io.IOException;
public class MapperPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanFactory) throws BeansException {
try {
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Resource[] resources = resolver.getResources("classpath:com/dreams/demo05/mapper/**/*.class");
AnnotationBeanNameGenerator generator = new AnnotationBeanNameGenerator();
CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
for (Resource resource : resources) {
MetadataReader reader = factory.getMetadataReader(resource);
ClassMetadata classMetadata = reader.getClassMetadata();
if (classMetadata.isInterface()) {
AbstractBeanDefinition bd = BeanDefinitionBuilder.genericBeanDefinition(MapperFactoryBean.class)
.addConstructorArgValue(classMetadata.getClassName())
.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE)
.getBeanDefinition();
AbstractBeanDefinition bd2 = BeanDefinitionBuilder.genericBeanDefinition(classMetadata.getClassName()).getBeanDefinition();
String name = generator.generateBeanName(bd2, beanFactory);
beanFactory.registerBeanDefinition(name, bd);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
}处理@Bean注解处理器
package com.dreams.demo05;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.type.MethodMetadata;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import java.io.IOException;
import java.util.Set;
public class AtBeanPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
}
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanFactory) throws BeansException {
try {
CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
MetadataReader reader = factory.getMetadataReader(new ClassPathResource("com/dreams/demo05/Config.class"));
Set<MethodMetadata> methods = reader.getAnnotationMetadata().getAnnotatedMethods(Bean.class.getName());
for (MethodMetadata method : methods) {
System.out.println(method);
String initMethod = method.getAnnotationAttributes(Bean.class.getName()).get("initMethod").toString();
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
builder.setFactoryMethodOnBean(method.getMethodName(), "config");
builder.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
if (initMethod.length() > 0) {
builder.setInitMethodName(initMethod);
}
AbstractBeanDefinition bd = builder.getBeanDefinition();
beanFactory.registerBeanDefinition(method.getMethodName(), bd);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}注释掉调用官方的处理器,换成我们自定义的处理器
context.registerBean(ComponentScanPostProcessor.class); // 解析 @ComponentScan
context.registerBean(AtBeanPostProcessor.class); // 解析 @Bean
context.registerBean(MapperPostProcessor.class); // 解析 Mapper 接口
// ️初始化容器
context.refresh();
for (String name : context.getBeanDefinitionNames()) {
System.out.println(name);
}
5.参考
黑马程序员:spring


