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.gaodi.net/redwinter/">redwinter</a> * @since 1.0 **/ public abstract class MyHouse { public abstract MyCar park(); }
定义我的车
/** * @author <a href="https://www.gaodi.net/redwinter/">redwinter</a> * @since 1.0 **/ public interface MyCar { /** * 买一辆车 * @return 车 */ MyCar buy(); }
定义实现类:
宝马车:
/** * @author <a href="https://www.gaodi.net/redwinter/">redwinter</a> * @since 1.0 **/ public class BMW implements MyCar{ @Override public MyCar buy() { return this; } }
奔驰车:
/** * @author <a href="https://www.gaodi.net/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.gaodi.net/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())); } }
这篇文章就介绍到这里,下一篇继续。