Spring 源码(11)Spring Bean 的创建过程(2)
2022-05-10 20:48
731 查看
Spring Bean的创建过程介绍了
FactoryBean的创建方式,那么接下来介绍不是
FactoryBean的创建方式,在创建过程中,又会分为单例的Bean的创建,原型类型的Bean的创建等。一般来说在Spring中几乎所有对象都是单例创建的,除非有其他业务需要设置为其他作用域的Bean,所以重点以创建单例Bean为例。
单例Bean的创建
在创建时会调用
getBean,然后
doGetBean,一般来说在
Spring中只要是
do开头方法基本就是真正干活的方法,所以我们看
doGetBean方法的源码:
protected <T> T doGetBean( String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException { // 解析成规范的Bean name ,因为可能是FactoryBean加了& 前缀的Bean或者是有别名的Bean String beanName = transformedBeanName(name); Object bean; // Eagerly check singleton cache for manually registered singletons. // 获取缓存中的Bean Object sharedInstance = getSingleton(beanName); if (sharedInstance != null && args == null) { bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); } // 如果缓存中没有,那么就会按照单例或者多例的方式创建 else { // 省略代码.... // Check if bean definition exists in this factory. // 检查父类容器 // 省略代码.... if (!typeCheckOnly) { // 标记已经被创建 markBeanAsCreated(beanName); } try { // 合并BeanDefinition RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); checkMergedBeanDefinition(mbd, beanName, args); // Guarantee initialization of beans that the current bean depends on. // 判断是否存在依赖的Bean的创建,比如dependsOn 依赖 A 这个Bean,那么就需要先创建A这个bean String[] dependsOn = mbd.getDependsOn(); if (dependsOn != null) { for (String dep : dependsOn) { if (isDependent(beanName, dep)) { // 省略代码.... } // 注册依赖的Bean,放在集合中 registerDependentBean(dep, beanName); try { // 创建Bean getBean(dep); } catch (NoSuchBeanDefinitionException ex) { // 省略代码.... } } } // Create bean instance. if (mbd.isSingleton()) { // 如果是单例的,就去创建Bean sharedInstance = getSingleton(beanName, () -> { try { // 创建Bean return createBean(beanName, mbd, args); } catch (BeansException ex) { // 省略代码.... } }); // 获取bean对象,会进行检查获取对象是否是FactoryBean bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); } // 原型作用的创建方式 else if (mbd.isPrototype()) { // 省略代码.... } else { // 省略代码.... } } catch (BeansException ex) { // 省略代码.... } } // 省略代码.... return (T) bean; }
去掉不重要的代码,可以看到首先是从缓存中获取,如果没有获取到就进行一些列检查,最终检查是否单例的
Bean,如果是,那么就会调用
getSingleton方法,传入一个
beanName,一个
ObjectFactory的
lambda表达式,表达式中有个
createBean方法,这个方法就是创建的
Bean方法。
那什么时候调用
crateBean方法呢?
答案是执行
lambda表达式的具体方法时执行,我们先看看这个
ObjectFactory接口是啥?
ObjectFactory 对象工厂
直接看源码:
@FunctionalInterface public interface ObjectFactory<T> { /** * Return an instance (possibly shared or independent) * of the object managed by this factory. * @return the resulting instance * @throws BeansException in case of creation errors */ T getObject() throws BeansException; }
这个接口是一个函数式接口,可以用于
lambda表达式直接使用,在调用
getObject方法时就是真正执行
lambda表达式中的方法。
具体看看
getSingleton方法的源码:
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) { Assert.notNull(beanName, "Bean name must not be null"); synchronized (this.singletonObjects) { Object singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null) { if (this.singletonsCurrentlyInDestruction) { // 省略代码.... } // 省略代码.... // 检查 并添加正在创建的单例对象到集合中 beforeSingletonCreation(beanName); // 设置为新的单例对象标识 boolean newSingleton = false; // 设置异常集合,出现异常时将异常加入到集合中 boolean recordSuppressedExceptions = (this.suppressedExceptions == null); if (recordSuppressedExceptions) { this.suppressedExceptions = new LinkedHashSet<>(); } try { // 执行具体的方法,调用crateBean方法 singletonObject = singletonFactory.getObject(); // 标识为新的单例对象 newSingleton = true; } catch (IllegalStateException ex) { // 省略代码.... } catch (BeanCreationException ex) { // 省略代码.... } finally { if (recordSuppressedExceptions) { this.suppressedExceptions = null; } // 检查 并移除正在创建的单例对象 afterSingletonCreation(beanName); } if (newSingleton) { // 加入到缓存中 addSingleton(beanName, singletonObject); } } return singletonObject; }
这里执行完之后就会执行到
lambda表达式中的
createBean方法:
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException { // 省略代码.... RootBeanDefinition mbdToUse = mbd; // Make sure bean class is actually resolved at this point, and // clone the bean definition in case of a dynamically resolved Class // which cannot be stored in the shared merged bean definition. // 解析Bean的Class 用于反射创建对象 Class<?> resolvedClass = resolveBeanClass(mbd, beanName); if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) { mbdToUse = new RootBeanDefinition(mbd); mbdToUse.setBeanClass(resolvedClass); } // Prepare method overrides. try { // 方法覆盖准备 lookup-method replace-method mbdToUse.prepareMethodOverrides(); } catch (BeanDefinitionValidationException ex) { // 省略代码.... } 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; } } catch (Throwable ex) { // 省略代码.... } try { // 实例化 + 初始化 Bean // 真正的创建Bean Object beanInstance = doCreateBean(beanName, mbdToUse, args); // 省略代码.... return beanInstance; } catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) { // 省略代码.... } catch (Throwable ex) { // 省略代码.... } }
首先是进行了
Bean的类型的解析,主要是用于后面的反射创建对象时使用,并设置到
RootBeanDefinition中,然后进行方法覆盖操作。
Spring方法覆盖实战
方法覆盖就是使用了
lookup-method和
replace-method标签的时候,就会进行方法的覆盖。方法覆盖有什么用处呢?
一般来说方法覆盖就是解决单例对象引用多例对象的时候使用方法覆盖。
做个实验试试:
定义一个房子类,用于停车
/** * @author <a href="https://www.cnblogs.com/redwinter/">redwinter</a> * @since 1.0 **/ public abstract class MyHouse { public abstract MyCar park(); }
定义我的车
/** * @author <a href="https://www.cnblogs.com/redwinter/">redwinter</a> * @since 1.0 **/ public interface MyCar { /** * 买一辆车 * @return 车 */ MyCar buy(); }
定义实现类:
宝马车:
/** * @author <a href="https://www.cnblogs.com/redwinter/">redwinter</a> * @since 1.0 **/ public class BMW implements MyCar{ @Override public MyCar buy() { return this; } }
奔驰车:
/** * @author <a href="https://www.cnblogs.com/redwinter/">redwinter</a> * @since 1.0 **/ public class Ben implements MyCar{ @Override public MyCar buy() { return this; } }
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" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <bean id="myHouse1" class="com.redwinter.test.methodoverride.lookupmethod.MyHouse" > <lookup-method name="park" bean="bmw"/> </bean> <bean id="myHouse2" class="com.redwinter.test.methodoverride.lookupmethod.MyHouse" > <lookup-method name="park" bean="ben"/> </bean> <!-- 设置为原型--> <bean id="bmw" class="com.redwinter.test.methodoverride.lookupmethod.BMW" scope="prototype"/> <bean id="ben" class="com.redwinter.test.methodoverride.lookupmethod.Ben"/> </beans>
测试类:
/** * @author <a href="https://www.cnblogs.com/redwinter/">redwinter</a> * @since 1.0 **/ public class LookupTest { /** * lookup-method 用来解决单例对象多例对象的 */ @Test public void lookupTest(){ ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:method-override.xml"); MyHouse myHouse = (MyHouse) context.getBean("myHouse1"); MyHouse myHouse1 = (MyHouse) context.getBean("myHouse1"); System.out.println(myHouse.park()); System.out.println(myHouse1.park()); } }
输出:
com.redwinter.test.methodoverride.lookupmethod.BMW@4a765 com.redwinter.test.methodoverride.lookupmethod.BMW@3e6358
这里
Myhouse是一个单例的对象,
myHouse1调用的方法每次调用都是不同的对象。
Spring是如何实现方法覆盖的?
源码过于繁琐和复杂,这里直接看执行流程:
Spring在加载
BeanDefinition的时候,执行
parseLookupOverrideSubElements这个方法的时候只要设置了
lookup-method标签就会创建一个
LookupOverride类放入到
BeanDefinition的
MethodOverrides属性中,在进行
Bean的创建的时候,就会判断这个属性值是否有值,如果有那么就会在对象实例化时获取一个实例化策略,然后执行实例化,就、就会调用
SimpleInstantiationStrategy#instantiate方法,然后使用
CGLIB进行实例化,创建出一个
Enhancer增强类,并且设置一个回调类型为:
private static final Class<?>[] CALLBACK_TYPES = new Class<?>[] {NoOp.class, LookupOverrideMethodInterceptor.class, ReplaceOverrideMethodInterceptor.class};
最终在执行方法的时候就会调用到回调类
LookupOverrideMethodInterceptor拦截器上,然后执行
Bean的创建:
@Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy mp) throws Throwable { // Cast is safe, as CallbackFilter filters are used selectively. LookupOverride lo = (LookupOverride) getBeanDefinition().getMethodOverrides().getOverride(method); Assert.state(lo != null, "LookupOverride not found"); Object[] argsToUse = (args.length > 0 ? args : null); // if no-arg, don't insist on args at all if (StringUtils.hasText(lo.getBeanName())) { // 创建Bean Object bean = (argsToUse != null ? this.owner.getBean(lo.getBeanName(), argsToUse) : this.owner.getBean(lo.getBeanName())); // Detect package-protected NullBean instance through equals(null) check return (bean.equals(null) ? null : bean); } else { return (argsToUse != null ? this.owner.getBean(method.getReturnType(), argsToUse) : this.owner.getBean(method.getReturnType())); } }
这篇文章就介绍到这里,下一篇继续。
相关文章推荐
- Spring IOC 容器源码分析 - 创建单例 bean 的过程
- Spring 创建Bean的过程及其源码浅析
- 白话Spring源码(五):Bean的创建过程
- 分析spring源码第五(三)篇:Spring中Bean的解析、加载、创建 过程总结
- Spring 源码(12)Spring Bean 的创建过程(3)
- Spring 源码(13)Spring Bean 的创建过程(4)
- spring源码bean的创建过程-解决循环依赖-
- Spring IOC 容器源码分析 - 创建单例 bean 的过程
- spring IOC源码分析(一)bean工厂的创建加载过程
- 2、Spring的LocalSessionFactoryBean创建过程源码分析
- Spring 源码 之 配置文件中的Bean在Spring中的创建过程
- SpringBoot初始化过程源码解析(五)自动化配置与bean信息读取
- spring 加载bean过程源码简易解剖(转载)
- spring源码学习 - 注解bean的初始化过程
- Spring源码解析 – AnnotationConfigApplicationContext容器创建过程
- Spring源码解析:Bean实例的创建与初始化
- Spring源码阅读——Bean的加载和获取过程
- Spring AOP高级——源码实现(3)AopProxy代理对象之JDK动态代理的创建过程
- spring启动过程之源码跟踪(续beanfactory)--spring Debug
- spring源码分析之bean的实例化过程