bean的后处理器和beanfactory的后处理器、Aware和InitializingBean、初始化和销毁

目录

Bean的后处理器

AutowiredAnnotationBeanPostProcessor运行分析

BeanFactory的后置处理器

@ComponentScan

@Bean

@ComponentScan

Aware

InitializingBean

问题

案例1:

案例2:

初始化

销毁


Bean的后处理器

AutowiredAnnotationBeanPostProcessor运行分析

里边装配主要方法是

    public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
        // 获取bean上加相应注解的信息
        InjectionMetadata metadata = this.findAutowiringMetadata(beanName, bean.getClass(), pvs);

        try {
            // 进行依赖注入
            metadata.inject(bean, beanName, pvs);
            return pvs;
        } catch (BeanCreationException var6) {
            throw var6;
        } catch (Throwable var7) {
            throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", var7);
        }
    }

inject方法主要流程

  1. 拿到属性
  2. 封装成DependencyDescriptor
  3. 调用beanfactory的doResolveDependency方法

BeanFactory的后置处理器

ConfigurationClassPostProcessor:处理@ComponentScan 、@Bean、 @Import()、@ImportResource等注解

@ComponentScan

  1. 找到注解
  2. 找需要扫描的包,转化为classpath*:com/***(例子)的格式
  3. 拿到这些class文件
  4. 读取类的元数据
  5. 用类的元信息判断看是否有@Component注解包括合成注解如@Controller
  6. 含有则变为BeanDefinition,然后放入beanFactory

@Bean

处理@Bean和上边类似,但是在装配的时候如果有参数,则还需要指定注入模式。同时也可以获取到属性做需要的操作,比如在设置初始化方法等等。

@ComponentScan

新增判断是否是接口,需要新增加入sqlsessionfactory,在生成名字时,源码中的做法是又生成了一个beandefinition。

Aware

这个接口用于注入一些与容器有关的信息,比如

  • BeanNameAware:注入bean的名字
  • BeanFactoryAware:注入BeanFactory容器

  • ApplicationContextAware:注入ApplicationContextAware容器

  • EmbeddedValueResolverAware:解析${}

InitializingBean

为Bean添加初始化方法

先调用aware接口,再触发初始化方法

问题

Q:Aware的某些功能用@Autowired就可以实现,为什么还要用到Aware的接口?

A:@Autowired需要用到bean的后处理器,是扩展功能。但是Aware属于内置功能,某些情况下@Autowired不能被识别,但是内置功能不会失效。比如未注册beanFactory后处理器。

案例1:

未注册beanFactory后处理器

public class MyMain {
    public static void main(String[] args) {
        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean("myConfig",MyConfig.class);
        //注释掉添加后处理器
//        context.registerBean(AutowiredAnnotationBeanPostProcessor.class);
//        context.registerBean(CommonAnnotationBeanPostProcessor.class);
        context.refresh();
        context.close();
    }
}
public class MyConfig implements BeanNameAware, ApplicationContextAware, InitializingBean {
    @Override
    public void setBeanName(String s) {
        System.out.println("name-------------------->"+s);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("InitializingBean初始化返回方法");
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("ApplicationContextAware:applicationContext-------------------->"+applicationContext);
    }

    @Autowired
    public void aaa(ApplicationContext applicationContext){
        System.out.println("@Autowired:applicationContext-------------------->"+applicationContext);
    }
    @PostConstruct
    public void init(){
        System.out.println("@PostConstruct初始化返回方法");
    }
}

如果不添加后置处理器,则@Autowired、@PostConstruct等bean后处理器处理的无法生效。打印结果为

name-------------------->myConfig
ApplicationContextAware:applicationContext-------------------->org.springframework.context.support.GenericApplicationContext@3f102e87, started on Tue May 24 14:07:12 CST 2022
InitializingBean初始化返回方法

如果主启动类注释放开(加上后处理器),结果为

@Autowired:applicationContext-------------------->org.springframework.context.support.GenericApplicationContext@3f102e87, started on Tue May 24 14:08:46 CST 2022
name-------------------->myConfig
ApplicationContextAware:applicationContext-------------------->org.springframework.context.support.GenericApplicationContext@3f102e87, started on Tue May 24 14:08:46 CST 2022
@PostConstruct初始化返回方法
InitializingBean初始化返回方法

案例2:

Java配置类包含了BeanFactoryPostProcessor

public class MyMain {
    public static void main(String[] args) {
        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean("myConfig1", MyConfig1.class);
        context.registerBean(AutowiredAnnotationBeanPostProcessor.class);
        context.registerBean(CommonAnnotationBeanPostProcessor.class);
        context.registerBean(ConfigurationClassPostProcessor.class);
        context.refresh();
        context.close();
    }
}
@Configuration
public class MyConfig1{

    @Autowired
    public void aaa(ApplicationContext applicationContext){
        System.out.println("@Autowired:applicationContext-------------------->"+applicationContext);
    }
    @PostConstruct
    public void init(){
        System.out.println("@PostConstruct初始化返回方法");
    }
//    @Bean
//    public BeanFactoryPostProcessor processor1(){
//        return configurableListableBeanFactory -> System.out.println("processor1执行");
//    }
}

结果正常为

@Autowired:applicationContext-------------------->org.springframework.context.support.GenericApplicationContext@3f102e87, started on Tue May 24 14:17:12 CST 2022
@PostConstruct初始化返回方法

当我们把MyConfig1注释放开,加一个BeanFactoryPostProcessor的bean时,打印结果为

processor1执行

我们发现@Autowired和@PostConstruct并没有执行。为什么

我们先来了解一下refresh()的大概步骤

  1. beanFactory后处理器注册beanDefinition
  2. 注册bean后处理器
  3. 初始化单例
    1. 依赖注入扩展@Autowired
    2. 初始化扩展@PostConstruct
    3. 执行Aware和InitializingBean
    4. 创建成功

但是,我们的Java配置类包含了BeanFactoryPostProcessor所以要创建beanFactory后处理器要先创建Java配置类,但是这个时候bean后处理器还没准备好,所以@Autowired和@PostConstruct等注解失效。顺序变为

  1. 创建和初始化
    1. 执行Aware和InitializingBean
    2. 创建成功
  2. beanFactory后处理器注册beanDefinition
  3. 注册bean后处理器

解决办法,改为实现Aware和InitializingBean接口。代码不再赘述。

初始化

三种方法:

  1. @PostConstruct
  2. InitializingBean
  3. @Bean(initMethod = "name")

执行顺序是@PostConstruct——>InitializingBean——>@Bean(initMethod = "name")

销毁

三种方法:

  1. @PreDestroy
  2. 实现DisposableBean
  3. @Bean(destroyMethod = "name")

也是先执行扩展功能,再执行内置功能,在执行@Bean

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值