spring原理(第四天)

Bean 后处理器

后处理器作用
  1. @Autowired 等注解的解析属于 bean 生命周期阶段(依赖注入, 初始化)的扩展功能,这些扩展功能由 bean 后处理器来完成

  2. 每个后处理器各自增强什么功能

    • AutowiredAnnotationBeanPostProcessor 解析 @Autowired 与 @Value

    • CommonAnnotationBeanPostProcessor 解析 @Resource、@PostConstruct、@PreDestroy

    • ConfigurationPropertiesBindingPostProcessor 解析 @ConfigurationProperties

  3. 另外 ContextAnnotationAutowireCandidateResolver 负责获取 @Value 的值,解析 @Qualifier、泛型、@Lazy 等

为了演示各个bean后处理器的作用,首先我们需要创建bean对象

bean1(其中通过setter方法注入了bean2以及bean3,还注入了一个成员变量)

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;
    }

 bean2

public class Bean2 {
}

bean3

public class Bean3 {
}

 现在我们可以创建容器并把这些bean对象注册到容器当中,初始化容器时执行beanFactory后处理器, 添加bean后处理器, 初始化所有单例,关闭容器时可以看到bean对象的销毁阶段

public class Spring04Application {

    public static void main(String[] args) {
        //比较干净的容器,没有默认的bean后处理器
        GenericApplicationContext context = new GenericApplicationContext();

        //注册bean
        context.registerBean("bean1", Bean1.class);
        context.registerBean("bean2", Bean2.class);
        context.registerBean("bean3", Bean3.class);
       
        //初始化容器
        context.refresh();

        for (String name : context.getBeanDefinitionNames()) {
              System.out.println(name);
            }

        context.close();
    }

}

此时我们可以看到容器内部只添加了我们手动注册的bean对象,依赖注入的对象以及成员变量并没有被解析 

由于是比较干净的容器,容器内部并没有默认的bean的后处理器,我们可以逐一添加bean的后处理器观察结果(添加AutowiredAnnotationBeanPostProcessor后处理器可以解析autowired,value注解)

public class Spring04Application {

    public static void main(String[] args) {
        //比较干净的容器,没有默认的bean后处理器
        GenericApplicationContext context = new GenericApplicationContext();

        //注册bean
        context.registerBean("bean1", Bean1.class);
        context.registerBean("bean2", Bean2.class);
        context.registerBean("bean3", Bean3.class);

        //添加到beanfactory,交给容器管理
        context.getDefaultListableBeanFactory().setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
        context.registerBean(AutowiredAnnotationBeanPostProcessor.class);  //autowired value注解

        //初始化容器
        context.refresh();

        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }

        context.close();
    }
}

此时我们可以发现容器内部多出了我们添加的bean后处理器以及@value,@autowired注解也被成功解析

我们可以再往容器内部添加 CommonAnnotationBeanPostProcessor后处理器(可以解析@Resource @PostConstruct @PreDestroy注解)

public class Spring04Application {

    public static void main(String[] args) {
        //比较干净的容器,没有默认的bean后处理器
        GenericApplicationContext context = new GenericApplicationContext();

        //注册bean
        context.registerBean("bean1", Bean1.class);
        context.registerBean("bean2", Bean2.class);
        context.registerBean("bean3", Bean3.class);

        //添加到beanfactory,交给容器管理
        context.getDefaultListableBeanFactory().setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
        context.registerBean(AutowiredAnnotationBeanPostProcessor.class);  //autowired value注解
        context.registerBean(CommonAnnotationBeanPostProcessor.class); // @Resource @PostConstruct @PreDestroy

        //初始化容器
        context.refresh();

        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }
        context.close();
    }
}

可以观察到容器内部多出了一个新的后处理器,以及上述三个注解都生效了 

还有一个注解@ConfigurationProperties,接下来我们来创建该类(指定了配置类属性的前缀名,以及在这个类中利用setter注入两个成员变量,并重写了该类的tostring方法)

@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 + '\'' +
                '}';
    }
}

创建了配置类,由于是普通的java项目,我们需要手动在启动类上开启配置类注解并扫描到该类

@EnableConfigurationProperties(value = {Bean4.class})

把bean4对象注册到容器中,由于重写了tostring方法,只需要获取到该类的bean对象并打印就可看到成员变量是否被成功注入

@EnableConfigurationProperties(value = {Bean4.class})
public class Spring04Application {

    public static void main(String[] args) {
        //比较干净的容器,没有默认的bean后处理器
        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);

        //添加到beanfactory,交给容器管理
        context.getDefaultListableBeanFactory().setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
        context.registerBean(AutowiredAnnotationBeanPostProcessor.class);  //autowired value注解
        context.registerBean(CommonAnnotationBeanPostProcessor.class); // @Resource @PostConstruct @PreDestroy


        //初始化容器
        context.refresh();

        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }
        System.out.println(context.getBean(Bean4.class));
        context.close();
    }
}

可以看到容器内部只多出了我们手动注册的对象,成员变量为空值

添加解析 @ConfigurationProperties注解的后处理器,它和前两种方式有所不同(通过ConfigurationPropertiesBindingPostProcessor配置属性类绑定后处理器)

@EnableConfigurationProperties(value = {Bean4.class})
public class Spring04Application {

    public static void main(String[] args) {
        //比较干净的容器,没有默认的bean后处理器
        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);

        //添加到beanfactory,交给容器管理
        context.getDefaultListableBeanFactory().setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
        context.registerBean(AutowiredAnnotationBeanPostProcessor.class);  //autowired value注解
        context.registerBean(CommonAnnotationBeanPostProcessor.class); // @Resource @PostConstruct @PreDestroy
        ConfigurationPropertiesBindingPostProcessor.register(context.getDefaultListableBeanFactory());

        //初始化容器
        context.refresh();

        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }
        System.out.println(context.getBean(Bean4.class));
        context.close();
    }
}

可以发现容器内部多出了三个bean的后处理器,以及成员变量也被成功注入 

学到了什么
                a. @Autowired 等注解的解析属于 bean 生命周期阶段(依赖注入, 初始化)的扩展功能
                b. 这些扩展功能由 bean 后处理器来完成

@Autowired bean 后处理器运行分析

// 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
        beanFactory.addEmbeddedValueResolver(new StandardEnvironment()::resolvePlaceholders); // ${} 的解析器

        // 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);

//        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);

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

        // 3. 如何按类型查找值
        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);

        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);

    }
}

 1. 查找哪些属性、方法加了 @Autowired, 这称之为 InjectionMetadata

首先我们实例化一个后处理器AutowiredAnnotationBeanPostProcessor对象并与该beanfactory进行绑定,添加到容器中,该处理器会去 查找哪些属性、方法加了 @Autowired,查找到的类统一称为 InjectionMetadata

其次把bean1对象依赖注入到容器当中,观察其他类或属性是否成功注入

此时可以看到注入成功

然后我们可以使用方法findAutowiringMetadata,默认该方法是不能查找到bean对象的,把他设置成true,通过该方法获取 Bean1 上加了 @Value @Autowired 的成员变量,方法参数信息 

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

我们可以通过获取到的InjectionMetadata对象调用它的inject方法来注入

可以发现也能成功注入

3. 如何按类型查找值 

// 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
        beanFactory.addEmbeddedValueResolver(new StandardEnvironment()::resolvePlaceholders); // ${} 的解析器

        // 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);

//        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);

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

        // 3. 如何按类型查找值
        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);

        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);

    }
}

首先通过bean1的字节码反射获取到它的成员变量和成员方法

其通过获取到的方法与方法获取到DependencyDescriptor对象

调用beanFactory的doResolveDependency方法就可以获取到注入的值或对象

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值