【第四讲】Bean后处理器

第四讲:Bean后处理器

  1. Bean 后处理器的作用,为Bean生命周期各个阶段提供扩展
  2. 常见的后处理器

[015]-常见的后处理器

定义三个 bean ,名称分别为 Bean1Bean2Bean3

  • 其中bean1中依赖了Bean2Bean3
  • bean2通过@Autowired的注解注入
  • Bean3通过@Resource注解注入
  • 通过@Value注解注入一个Java的环境变量JAVA_HOME的值
  • 定义两个方法init()destroy(),分别加上@PostConstruct@PreDestroy
  • 最后定义一个Bean4——使用ConfigurationProperties

Bean1

@Slf4j
public class Bean1 {
    private Bean2 bean2;

    @Autowired
    public void setBean2(Bean2 bean2) {
        log.info("@Autowired 生效:{}", bean2);
        this.bean2 = bean2;
    }

    @Autowired
    public void setJava_home(@Value("${JAVA_HOME}") String java_home) {
        log.info("@Value 生效:{}", java_home);
        this.java_home = java_home;
    }

    private Bean3 bean3;

    @Resource
    public void setBean3(Bean3 bean3) {
        log.info("@Resource 生效:{}", bean3);
        this.bean3 = bean3;
    }

    private String java_home;

    @PostConstruct
    public void init() {
        log.info("@PostConstruct 生效:{}");
    }

    @PreDestroy
    public void destroy() {
        log.info("@PreDestroy 生效:{}");
    }

    @Override
    public String toString() {
        return "Bean1{" +
                "bean2=" + bean2 +
                ", bean3=" + bean3 +
                ", java_home='" + java_home + '\'' +
                '}';
    }
}

Bean2、Bean3、Bea4

public class Bean2 {
}

public class Bean3 {
}

@ConfigurationProperties(prefix = "java")
@Slf4j
public class Bean4 {
}

这里使用GenericApplicationContext来探究@Autowired@Value@Resource@PostConstruct@PreDestroy以及springboot项目中的@ConfigurationProperties这些注解分别是由哪个后处理器来解析的。

GenericApplicationContext 是一个【干净】的容器,默认不会添加任何后处理器,方便做测试,这里用DefaultListableBeanFactory也可以完成测试,只是会比使用GenericApplicationContext麻烦一些。

public class TestBeanPostProcessor {
    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);

        //解决No qualifying bean of type 'java.lang.String' available
        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();
        System.out.println("Bean4:"+context.getBean(Bean4.class));
        // 销毁容器
        context.close();

    }
}

在这里插入图片描述

结论

  • @Autowired 注解对应的后处理器是AutowiredAnnotationBeanPostProcessor
  • @Value注解需要配合@Autowired注解一起使用,所以也用到了AutowiredAnnotationBeanPostProcessor后处理器,然后@Value注解还需要再用到ContextAnnotationAutowireCandidateResolver解析器,否则会报错;
  • @Resource@PostConstruct@PreDestroy注解对应的后处理器是CommonAnnotationBeanPostProcessor
  • @ConfigurationProperties注解对应的后处理器是ConfigurationPropertiesBindingPostProcessor

Autowired bean后处理器分析

@Autowired注解解析用到的后处理器时AutowiredAnnotationBeanPostProcessor

  • 这个后处理器就是通过调用postProcessProperties(PropertyValues pvs, Object bean, String beanName)完成注解的解析和注入的功能

    看源码
    postProcessProperties 这个方法
    	1.方法中又调用了一个私有的方法findAutowiringMetadata(beanName, bean.getClass(), pvs),其返回值InjectionMetadata中封装了被@Autowired注解修饰的属性和方法
    	2.然后会调用InjectionMetadata.inject(bean1, "bean1", null)进行依赖注入
    
public static void main(String[] args) {
    DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
    // 创建过程、依赖注入、初始化
    beanFactory.registerSingleton("bean2",new Bean2());
    beanFactory.registerSingleton("bean3",new Bean3());
    // @Value
    beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());

    // 1.查找那些属性、方法加了@Autowired,这称为 InjectionMetadata
    AutowiredAnnotationBeanPostProcessor postProcessor = new AutowiredAnnotationBeanPostProcessor();
    postProcessor.setBeanFactory(beanFactory);

    Bean1 bean1 = new Bean1();
    System.out.println("前bean1:" + bean1);
    postProcessor.postProcessProperties(null,bean1,"bean1");
    System.out.println("后bean1:" + bean1);

}

在这里插入图片描述

反射调用 AutowiredAnnotationBeanPostProcessor类中 findAutowiringMetadata的方法

在这里插入图片描述

调用 InjectionMetadata 来进行依赖注入,注入时按类型查找值

// 2.调用 InjectionMetadata 来进行依赖注入,注入时按类型查找值
metadata.inject(bean1,"bean1",null);
System.out.println("----bean1----"+bean1);

在这里插入图片描述

总代码

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());
        // @Value
        beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
        // 设置解析 @Value 注解中的 ${} 表达式的解析器
        beanFactory.addEmbeddedValueResolver(new StandardEnvironment()::resolvePlaceholders);

        // 1.查找那些属性、方法加了@Autowired,这称为 InjectionMetadata
        AutowiredAnnotationBeanPostProcessor postProcessor = new AutowiredAnnotationBeanPostProcessor();
        postProcessor.setBeanFactory(beanFactory);

        Bean1 bean1 = new Bean1();
        //        System.out.println("前bean1:" + bean1);
        //        postProcessor.postProcessProperties(null,bean1,"bean1");
        //        System.out.println("后bean1:" + bean1);

        //--------- 模拟postProcessProperties 调用过程-------
        Method findAutowiringMetadata = AutowiredAnnotationBeanPostProcessor.
            class.getDeclaredMethod("findAutowiringMetadata", String.class, Class.class, PropertyValues.class);
        findAutowiringMetadata.setAccessible(true);
        InjectionMetadata metadata = (InjectionMetadata) findAutowiringMetadata.invoke(postProcessor,"bean1",Bean1.class,null);
        System.out.println(metadata);

        // 2.调用 InjectionMetadata 来进行依赖注入,注入时按类型查找值
        metadata.inject(bean1,"bean1",null);
        System.out.println("----bean1----"+bean1);

        // 3. 如何按照类型查找值

    }

InjectionMetadata.inject 分析

给 bean3 加上 @Autowired 注解

  1. 如何去Bean工厂里面按类型查找值

    由于InjectionMetadata.inject(bean1, “bean1”, null)的源码调用链过长,摘出主要调用过程进行演示

3.1@Autowired加在成员变量上
//3.1 @Autowired加在成员变量上,InjectionMetatadata给Bean1注入Bean3的过程
Field bean3 = Bean1.class.getDeclaredField("bean3");
bean3.setAccessible(true);
// 将这个属性封装成一个DependencyDescriptor对象
DependencyDescriptor dd1 = new DependencyDescriptor(bean3,false);
// 再执行beanFactory的doResolveDependency
Bean3 bean3Value = (Bean3)beanFactory.doResolveDependency(dd1,null,null,null);
System.out.println("bean3:----"+bean3Value);
3.2 @Autowired加在方法上
// 3.2 @Autowired加在方法上,InjectionMetatadata给Bean1注入Bean2的过程
Method setBean2 = Bean1.class.getDeclaredMethod("setBean2", Bean2.class);
DependencyDescriptor dd2 = new DependencyDescriptor(new MethodParameter(setBean2, 0), true);
Bean2 bean2Value = (Bean2) beanFactory.doResolveDependency(dd2, "bean2", null, null);
System.out.println("bean2:----"+bean2Value);

3.3 @Autowired加在方法上,方法参数为String类型,加了@Value
// 3.3 @Autowired加在方法上,方法参数为String类型,加了@Value,
// InjectionMetadata给Bean1注入环境变量JAVA_HOME属性的值
Method setJava_home = Bean1.class.getDeclaredMethod("setJava_home", String.class);
DependencyDescriptor dd3 = new DependencyDescriptor(new MethodParameter(setJava_home, 0), true);
String java_home = (String) beanFactory.doResolveDependency(dd3, null, null, null);
System.out.println("java_home:----"+java_home);

在这里插入图片描述

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值