水稻:这两天看了BeanDefinition和BeanFactoryPostProcessor还有BeanPostProcessor的源码。要不要了解一下

菜瓜:six six six,大佬请讲

水稻:上次我们说SpringIOC容器是一个典型的工厂模式

  • 假如我们把Spring比作一个生产模型的大工厂,那么.class文件就是原材料。而BeanDefinition就是创建模型的模具。不管是传统的XML还是后面的注解,Spring在启动的时候都会创建一个扫描器去扫描指定目录下的.class文件,并根据文件的注解,实现的接口以及成员变量将其封装一个个的BeanDefinition。

    • 比较重要的属性有id,class,构造函数封装类,属性封装类,factoryMethod等
  • 在对象初始化之前Spring会完成BeanDefinition对象的解析并将其装入List容器beanDefinitionNames中,然后开始遍历该容器并根据BeanDefinition创建对象

菜瓜:sodasinei,BeanDefinition我了解了。它是创建bean的模板,类似于java创建对象依赖的class一样。那还有两个很长的单词是啥呢?

水稻:忽略掉后面老长的后缀,我们看BeanFactory和Bean是不是很亲切。PostProcessor被翻译成后置处理器,暂且我们把它看成是处理器就行

  • BeanFactory是bean工厂,它可以获取并修改BeanDefinition的属性,进而影响后面创建的对象。
  • Bean就是Spring的对象,这些个处理器才是真正处理bean对象的各个环节的工序,包括属性,注解,方法

菜瓜:有了模糊的概念,不明觉厉

水稻:来,看demo

package com.vip.qc.postprocessor;

import org.springframework.beans.BeansException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component; /**
* 获取初始化好的BeanFactory,此时还未进行bean的实例化
*
* @author QuCheng on 2020/6/14.
*/
@Component
public class BeanFactoryPostProcessorT implements BeanFactoryPostProcessor { public static final String BEAN_NAME = "processorT"; @Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
BeanDefinition initializingBeanT = beanFactory.getBeanDefinition(BEAN_NAME);
MutablePropertyValues propertyValues = initializingBeanT.getPropertyValues();
String pName = "a";
System.out.println("BeanFactoryPostProcessor a " + propertyValues.getPropertyValue(pName) + " -> 1");
propertyValues.addPropertyValue(pName, "1");
}
} package com.vip.qc.postprocessor; import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component; /**
* @author QuCheng on 2020/6/14.
*/
@Component
public class BeanPostProcessorT implements BeanPostProcessor { public static final String beanNameT = "processorT"; @Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (beanNameT.equals(beanName)) {
ProcessorT processorT = ((ProcessorT) bean);
System.out.println("BeanPostProcessor BeforeInitialization a:" + processorT.getA() + "-> 3");
processorT.setA("3");
}
return bean;
} @Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (beanNameT.equals(beanName)){
ProcessorT processorT = ((ProcessorT) bean);
System.out.println("BeanPostProcessor AfterInitialization a:" + processorT.getA() + "-> 4");
processorT.setA("4");
}
return bean;
} } package com.vip.qc.postprocessor; import org.springframework.stereotype.Component; /**
* @author QuCheng on 2020/6/14.
*/
@Component
public class ProcessorT { public ProcessorT() {
System.out.println("ProcessorT 无参构造 a:" + a + "-> 2" );
a = "2";
} private String a; public String getA() {
return a;
} public void setA(String a) {
this.a = a;
} @Override
public String toString() {
return "ProcessorT{" +
"a='" + a + '\'' +
'}';
}
} // 测试类
@Test
public void test() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext("com.vip.qc.postprocessor");
ProcessorT processorT = (ProcessorT) context.getBean("processorT");
System.out.println(processorT);
} // 结果
BeanFactoryPostProcessor a null -> 1
ProcessorT 无参构造 a:null-> 2
BeanPostProcessor BeforeInitialization a:1-> 3
BeanPostProcessor AfterInitialization a:3-> 4
ProcessorT{a='4'}
  • BeanFactoryPostProcessor在对象还未初始化前可以拿到对象的BeanDefinition对其设置属性值  

  • 过程中我们分别对属性a设置了1,2,3,4的值。最后我们拿到的值为4

菜瓜:好像看懂了。BeanFactoryPostProcessor可以拿到BeanFactory对象,获取里面所有的BeanDefinition并可对其进行干预。BeanPostProcessor其实是在bean已经被创建完成之后进行加工操作

水稻:没错。这是我们自己进行干预的demo。限于篇幅有限,你可以去看一下Spring自己对于这两个接口的实现源码。比较重要的推荐下面几个

  • ConfigurationClassPostProcessor 实现BeanFactoryPostProcessor子接口

    • 完成对@Configuration、@Component、@ComponentScan、@Bean、@Import、@ImportSource注解的搜集和解析
    • @Bean注解会被封装成所在Bean的BeanDefinition中的factoryMethod属性中,单独进行实例化
  • CommonAnnotationBeanPostProcessor 实现 BeanPostProcessor
    • 完成@PostConstruct@PreDestroy@Resource注解的搜集和解析工作
    • @PostConstruct会在对象初始化且属性渲染完成后进行
    • @Resource注解(参照下面)
  • AutowiredAnnotationBeanPostProcessor 实现 BeanPostProcessor
    • 完成@Autowired@Value注解的搜集和解析工作
    • 在对象初始化完成之后会先进行注解的搜集,然后进行属性渲染调用populateBean方法,使用策略模式调用实现接口对注解进行解析,有@Autowired和@Value注解会调用getBean方法发起对依赖属性的注入
  • AbstractAutoProxyCreator的入口类也是实现的BeanPostProcessor

菜瓜:你放心,我不会看的。这么复杂的东西,听着都费劲

水稻:不愧是你!没事,有机会聊bean的生命周期的时候咱们还会说到这些东西。到时候再刷一遍

Spring:BeanDefinition&PostProcessor不了解一下吗?的更多相关文章

  1. Spring BeanDefinition的加载

     前面提到AbstractRefreshableApplicationContext在刷新BeanFactory时,会调用loadBeanDefinitions方法以加载系统中Bean的定义,下面将讲 ...

  2. 扯淡 Spring BeanDefinition

    相关文章 Spring 整体架构 编译Spring5.2.0源码 Spring-资源加载 Spring 容器的初始化 Spring-AliasRegistry Spring 获取单例流程(一) Spr ...

  3. Spring beanDefinition载入

    @Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.st ...

  4. Spring BeanDefinition

    定义 /** * A BeanDefinition describes a bean instance, which has property values, * constructor argume ...

  5. spring BeanDefinition 继承结构图

    ConfigurationClassBeanDefinition 是ConfigurationClassBeanDefinitionReader的静态内部类

  6. Spring工厂方式创建Bean实例

    创建Bean实例的方式: 1) 通过构造器(有参或无参) 方式: <bean id="" class=""/> 2) 通过静态工厂方法 方式: &l ...

  7. Spring之一:IoC容器体系结构

    温故而知心. Spring IoC概述 常说spring的控制反转(依赖反转),看看维基百科的解释: 如果合作对象的引用或依赖关系的管理要由具体对象来完成,会导致代码的高度耦合和可测试性降低,这对复杂 ...

  8. Spring框架之beans源码完全解析

    导读:Spring可以说是Java企业开发里最重要的技术.而Spring两大核心IOC(Inversion of Control控制反转)和AOP(Aspect Oriented Programmin ...

  9. 【Spring】IoC容器 - Spring Bean作用域Scope(含SpringCloud中的RefreshScope )

    前言 上一章学习了[依赖来源],本章主要讨论SpringBean的作用域,我们这里讨论的Bean的作用域,很大程度都是默认只讨论依赖来源为[Spring BeanDefinition]的作用域,因为在 ...

随机推荐

  1. hibernate 异常分析:java.lang.NoClassDefFoundError: org/hibernate/Session

    原因: NoClassDefFoundError的含义就是说编译器找不到org/hibernate/Session这个类的定义 解决方法: 1.检查java中是否导入hibernate 包 impor ...

  2. 【转】Mac系统常用快捷键大全

    Mac系统常用快捷键大全 通用 Command是Mac里最重要的修饰键,在大多数情况下相当于Windows下的Ctrl.所以以下最基本操作很好理解: Command + Z 撤销 Command + ...

  3. IIS 报 :HTTP Error 503. The service is unavailable.

    打开IIS 找到你对应的网站名称然后你会发现应用池停止了 点击你对应的网站右键点击启动既可

  4. 封装 private

    封装表现: 1.方法就是一个最基本封装体. 2.类其实也是一个封装体. 从以上两点得出结论,封装的好处: 1.提高了代码的复用性. 2.隐藏了实现细节,还要对外提供可以访问的方式.便于调用者的使用.这 ...

  5. 不懂代码?没关系,照样可以做SaaS软件开发

    众所周知,一家标准化的企业的日常运营管理都需要一个强大的中枢或中台管理系统来统筹整个企业或是整个集团的运作,这个强大的中台管理系统就相当于是企业的引擎.在引擎的带动下,汽车可以快速的飞驰起来,同样,在 ...

  6. lin-cms-dotnetcore.是如何方法级别的权限控制的?

    方法级别的权限控制(API级别) Lin的定位在于实现一整套 CMS的解决方案,它是一个设计方案,提供了不同的后端,不同的前端,而且也支持不同的数据库 目前官方团队维护 lin-cms-vue,lin ...

  7. 8.Hash集合类型操作使用

    数据类型Hash (1)介绍 hash数据类型存储的数据与mysql数据库中存储的一条记录极为相似 Redis本身就类似于Hash的存储结构,分为key-value键值对,实际上它的Hash数据就好像 ...

  8. 拨号vps,拨号vps是什么意思干什么用的,如何使用拨号vps

    首先,拨号vps是动态IP的VPS.vps虚拟服务器.拨号服务器.有些业务,如刷单.投票等操作对ip地址有限制,不能过多的使用.而拨号VPS通过拨号上网,每拨号一次号,就变一次IP,完成ip地址的动态 ...

  9. 关于服务器运维人员,该如何管理很多VPS呢?

    众所周知,服务器运营人员的工作内容,主要围绕着公司上下所有服务器.网络等硬件平台的运维工作,对每台服务器的状况,如磁盘.内存.网络.CPU等资源情况都要有明确的了解,还要定期对服务器进行巡检和修复,避 ...

  10. Autofac依赖注入

    简介 Autofac 是一款超赞的.NET IoC 容器 . 它管理类之间的依赖关系, 从而使 应用在规模及复杂性增长的情况下依然可以轻易地修改 .它的实现方式是将常规的.net类当做 组件 处理. ...