Bean与后处理器

笔记参考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

暂无评论

发送评论 编辑评论

|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇