Spring 源码(12)Spring Bean 的创建过程(3)
继续上一篇Spring Bean的创建过程的解读,上一篇介绍了Spring在创建过程中doGetBean方法,在执行过程中会调用getSingleton方法并且设置一个lambda表达式,这个lambda表达式是ObjectFactory的实现,当调用这个接口的getObject方法时就会执行到createBean方法,在createBean方法中会进行bean类型的解析,并且会进行方法覆盖的设置,当我们配置了如:lookup-method或者replace-method方法的时候就会在创建Bean的过程中设置一个CGLIB的工厂类为Bean的对象,当调用的时候就会触发CGLIB的拦截器方法执行具体的Bean的获取,如果是单例对象引用了多例对象,那么就会每次创建一个新的对象给调用的方法执行。

接下来继续解读Spring 创建Bean的过程。
早期Bean的创建
在createBean方法中有一段代码:
try {
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
// 解析提前实例化,使用InstantiationAwareBeanPostProcessor实现
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
点进去:
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
Object bean = null;
if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
// Make sure bean class is actually resolved at this point.
// 判断是否有InstantiationAwareBeanPostProcessor在容器中
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
Class<?> targetType = determineTargetType(beanName, mbd);
if (targetType != null) {
// 执行前实例化
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
if (bean != null) {
// 执行后置初始化
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
}
}
mbd.beforeInstantiationResolved = (bean != null);
}
return bean;
}
这里判断了容器中如果有实现InstantiationAwareBeanPostProcessor接口,那么就执行前置实例化,InstantiationAwareBeanPostProcessor接口继承了BeanPostProcessor,并且这个接口的方法跟BeanPostProcessor非常相似,InstantiationAwareBeanPostProcessor的接口一个是前置的实例化postProcessBeforeInstantiation,一个是后置的实例化postProcessAfterInstantiation,而BeanPostProcessor的接口一个是前置初始化postProcessBeforeInitialization,一个是后置初始化postProcessAfterInitialization。
在Spring中Bean的创建分为实例化+初始化,当然还有属性填充,这里进行提前实例化其实就是给了一个扩展点,让对象可以提前创建,而不用再继续走doCreateBean方法里面的复杂逻辑,这样的话就提供给用户能够自己控制对象的创建过程以及执行增强等操作。
那这个实例化增强类是何时放进Spring容器的呢?
答案很简单,InstantiationAwareBeanPostProcessor是一个BeanPostProcessor,那么自然也就是在注册BeanPostProcessor时放进去的。
看源码:
public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
Assert.notNull(beanPostProcessor, "BeanPostProcessor must not be null");
// Remove from old position, if any
// 先删除掉旧的
this.beanPostProcessors.remove(beanPostProcessor);
// Track whether it is instantiation/destruction aware
// 如果是InstantiationAwareBeanPostProcessor 设置属性
if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) {
this.hasInstantiationAwareBeanPostProcessors = true;
}
// 设置销毁的标识位
if (beanPostProcessor instanceof DestructionAwareBeanPostProcessor) {
this.hasDestructionAwareBeanPostProcessors = true;
}
// Add to end of list
// 添加到链表尾
this.beanPostProcessors.add(beanPostProcessor);
}
接下来试试提前实例化的案例:
InstantiationAwareBeanPostProcessor 实验
创建一个需要提前实例化的对象:
/**
* @author <a href="https://www.cnblogs.com/redwinter/">redwinter</a>
* @since 1.0
**/
public class MyBeforeInstantiation {
public void beforeInvoke(){
System.out.println("提前实例化,开始执行业务....");
}
}
创建一个InstantiationAwareBeanPostProcessor的实现类:
/**
* @author <a href="https://www.cnblogs.com/redwinter/">redwinter</a>
* @since 1.0
**/
public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
System.out.println("beanName: " + beanName + "执行了 postProcessBeforeInstantiation 方法");
// 提前进行实例化
if (beanClass == MyBeforeInstantiation.class) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(beanClass);
enhancer.setCallback(new MyMethodInterceptor());
Object obj = enhancer.create();
System.out.println("创建对象:" + obj);
return obj;
}
return null;
}
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
System.out.println("beanName: " + beanName + "执行了 postProcessAfterInstantiation 方法");
return false;
}
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
System.out.println("beanName: " + beanName + "执行了 postProcessProperties 方法");
return pvs;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("beanName: " + beanName + "执行了 postProcessBeforeInitialization 方法");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("beanName: " + beanName + "执行了 postProcessAfterInitialization 方法");
return bean;
}
}
这里使用了CGLIB 动态代理去增强创建代理对象,编写一个回调拦截器:
/**
* @author <a href="https://www.cnblogs.com/redwinter/">redwinter</a>
* @since 1.0
**/
public class MyMethodInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("方法执行前:"+method);
Object o1 = methodProxy.invokeSuper(o, objects);
System.out.println("方法执行后:"+method);
return o1;
}
}
xml配置:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="myBeforeInstantiation" class="com.redwinter.test.beforeInstantiation.MyBeforeInstantiation"/>
<bean id="myInstantiationAwareBeanPostProcessor" class="com.redwinter.test.beforeInstantiation.MyInstantiationAwareBeanPostProcessor"/>
</beans>
测试类:
/**
* @author <a href="https://www.cnblogs.com/redwinter/">redwinter</a>
* @since 1.0
**/
public class BeforeInstantiationTest {
@Test
public void test(){
ApplicationContext ac = new ClassPathXmlApplicationContext("before-instantiation.xml");
MyBeforeInstantiation bean = ac.getBean(MyBeforeInstantiation.class);
bean.beforeInvoke();
}
}
输出:
beanName: myBeforeInstantiation执行了 postProcessBeforeInstantiation 方法
方法执行前:public java.lang.String java.lang.Object.toString()
方法执行前:public native int java.lang.Object.hashCode()
方法执行后:public native int java.lang.Object.hashCode()
方法执行后:public java.lang.String java.lang.Object.toString()
创建对象:com.redwinter.test.beforeInstantiation.MyBeforeInstantiation$$EnhancerByCGLIB$$f92db8b4@1fd3711
beanName: myBeforeInstantiation执行了 postProcessAfterInitialization 方法
方法执行前:public void com.redwinter.test.beforeInstantiation.MyBeforeInstantiation.beforeInvoke()
提前实例化,开始执行业务....
方法执行后:public void com.redwinter.test.beforeInstantiation.MyBeforeInstantiation.beforeInvoke()
可以看到,这里只执行了两个方法,一个是postProcessBeforeInstantiation,是InstantiationAwareBeanPostProcessor的前置实例化接口,一个是postProcessAfterInitialization,是BeanPostProcessor的后置实例化接口。
相当于说Bean对象提前被创建了,而没有执行下面的doCreateBean方法的逻辑。 Spring设计了很多的扩展点,帮助用户实现很多自定义的处理,Spring强大之处就在这里。
这篇就介绍到这里,下一篇介绍Spring其他方式的进行提前创建Bean对象。
Spring 源码(12)Spring Bean 的创建过程(3)的更多相关文章
- Spring源码分析之Bean的创建过程详解
前文传送门: Spring源码分析之预启动流程 Spring源码分析之BeanFactory体系结构 Spring源码分析之BeanFactoryPostProcessor调用过程详解 本文内容: 在 ...
- Spring 源码分析之 bean 依赖注入原理(注入属性)
最近在研究Spring bean 生命周期相关知识点以及源码,所以打算写一篇 Spring bean生命周期相关的文章,但是整理过程中发现涉及的点太多而且又很复杂,很难在一篇文章中把Spri ...
- Spring源码-IOC部分-Bean实例化过程【5】
实验环境:spring-framework-5.0.2.jdk8.gradle4.3.1 Spring源码-IOC部分-容器简介[1] Spring源码-IOC部分-容器初始化过程[2] Spring ...
- dubbo源码分析3-service bean的创建与发布
dubbo源码分析1-reference bean创建 dubbo源码分析2-reference bean发起服务方法调用 dubbo源码分析3-service bean的创建与发布 dubbo源码分 ...
- Spring源码分析专题 —— IOC容器启动过程(上篇)
声明 1.建议先阅读<Spring源码分析专题 -- 阅读指引> 2.强烈建议阅读过程中要参照调用过程图,每篇都有其对应的调用过程图 3.写文不易,转载请标明出处 前言 关于 IOC 容器 ...
- 【Spring源码分析】Bean加载流程概览
代码入口 之前写文章都会啰啰嗦嗦一大堆再开始,进入[Spring源码分析]这个板块就直接切入正题了. 很多朋友可能想看Spring源码,但是不知道应当如何入手去看,这个可以理解:Java开发者通常从事 ...
- 【Spring源码分析】Bean加载流程概览(转)
转载自:https://www.cnblogs.com/xrq730/p/6285358.html 代码入口 之前写文章都会啰啰嗦嗦一大堆再开始,进入[Spring源码分析]这个板块就直接切入正题了. ...
- Spring源码分析:Bean加载流程概览及配置文件读取
很多朋友可能想看Spring源码,但是不知道应当如何入手去看,这个可以理解:Java开发者通常从事的都是Java Web的工作,对于程序员来说,一个Web项目用到Spring,只是配置一下配置文件而已 ...
- Spring 源码分析之 bean 实例化原理
本次主要想写spring bean的实例化相关的内容.创建spring bean 实例是spring bean 生命周期的第一阶段.bean 的生命周期主要有如下几个步骤: 创建bean的实例 给实例 ...
- 初探Spring源码之Spring Bean的生命周期
写在前面的话: 学无止境,写博客纯粹是一种乐趣而已,把自己理解的东西分享出去,不意味全是对的,欢迎指正! Spring 容器初始化过程做了什么? AnnotationConfigApplication ...
随机推荐
- 学习Apache(三)
对某个目录开启验证登录 <Directory /var/www/html/admin > AllowOverride All Order allow,deny Allow from all ...
- 学习GlusterFS(五)
一,分布式文件系统理论基础 1.1 分布式文件系统出现 计算机通过文件系统管理,存储数据,而现在数据信息爆炸的时代中人们可以获取的数据成指数倍的增长,单纯通过增加硬盘个数来扩展计算机文件系统的存储容量 ...
- mysql8.0时区问题
今天在mysql新增一条数据的时候,发现时间类型的字段比起现在少了8个小时,查了资料才发现,这个是MySQL8.0出现的问题,讲下解决方法. 1.在java项目中application.yml文件中的 ...
- Python学习--Python的了解与安装
Python简介: Python 是一种解释型.面向对象.动态数据类型的高级程序设计语言. Python 由荷兰人Guido van Rossum 于 1989 年底发明,第一个公开发行版发行于 19 ...
- 一个用于学习的react项目
React-element 根据开源项目 vue-sell进行的开发,将其改造成了react的项目.在开始学习vue的时候就是用的这个项目,发现效果不错,所以在学习React也使用了此项目. 目的:将 ...
- 在IntelliJ IDEA配置Tomcat
1,点击Run---EDit Configurations... 2.点击左侧"+"号,找到Tomcat Server---Local(若是没有找到Tomcat Server 可以 ...
- 腾讯云服务nginx部署静态项目
一直想要搭建自己的blog,买了基础云服务器练手 文章内容是根据腾讯文档(https://cloud.tencent.com/document/product/213/2131)总结 部署静态页面归纳 ...
- EMS查看邮箱容量限制的方法
以Exchange管理员身份打开EMS控制台.在PowerShell命令行提示符下,输入以下命令. Get-MailboxDatabase | FL name,IssueWarningQuota,Pr ...
- nodeJs入门的第一节课
nodejs是什么? nodejs的架构模式以及优缺点 nodejs异步IO nodejs事件驱动 nodejs单线程 nodejs应用场景 一.nodejs是什么? 1.1nodejs是一个开源的. ...
- Ncrystal Skill设计
在使用allegro时一般都会听说过skill,使用合适的Skill会使事情事半功倍.但是现阶段所能看到的个人白嫖的Skill都有一些通病.所以我才开发符合自己操作习惯的Skill. 当前我们所能找的 ...