Spring 源码(10)Spring Bean 的创建过程(1)

Spring Bean的创建刚开始进行了一些准备工作,比如转换服务的初始化,占位符解析器的初始化,BeanDefinition元数据的冻结等操作,都是为了在创建Bean的过程中保证Bean的正确的创建,接下来开始进行对Bean的创建进行解析。

Bean 的创建步骤

Spring源码中对Bean的创建遵循一个步骤就是:getBean --> doGetBean --> createBean --> doCreateBean ,常规的Bean的创建过程都是按照这个步骤执行,然后反射实例化,属性填充,初始化,放到一级缓存中。那么非常规的有可能就不遵循这个步骤,比如FactoryBeanInstantiationAwareBeanPostProcessor 等。

上源码:

public void preInstantiateSingletons() throws BeansException {   if (logger.isTraceEnabled()) {     logger.trace("Pre-instantiating singletons in " + this);   }    // Iterate over a copy to allow for init methods which in turn register new bean definitions.   // While this may not be part of the regular factory bootstrap, it does otherwise work fine.   List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);    // Trigger initialization of all non-lazy singleton beans...   // 遍历所有的beanName   for (String beanName : beanNames) {     // 获取RootBeanDefinition 从缓存中,第一个放入缓存是在 AbstractApplicationContext#invokeBeanFactoryPostProcessors 中的getBeanNamesForType方法中     RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);     // 如果不是抽象的,是单例的,是非懒加载的,则进行bean的创建,否则直接跳过     if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {       // 是否是FactoryBean       if (isFactoryBean(beanName)) {         // 获取bean实例         Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);         // 判断获取的Bean是否是FactoryBean         if (bean instanceof FactoryBean) {           FactoryBean<?> factory = (FactoryBean<?>) bean;           // 是否是饥饿初始化,默认是false           boolean isEagerInit;           // 权限校验           if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {             isEagerInit = AccessController.doPrivileged(               (PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,               getAccessControlContext());           }           else {             isEagerInit = (factory instanceof SmartFactoryBean &&                            ((SmartFactoryBean<?>) factory).isEagerInit());           }           // 如果是饥饿初始化,则进行bean的创建           if (isEagerInit) {             getBean(beanName);           }         }       }       else {         // 获取bean         getBean(beanName);       }     }   }    // Trigger post-initialization callback for all applicable beans...   // 触发 所有Bean初始化后的回调   for (String beanName : beanNames) {     Object singletonInstance = getSingleton(beanName);     // 获取单例对象,如果是SmartInitializingSingleton 则调用afterSingletonsInstantiated     // 在监听器中使用@EventListener注解标记的方法就是在这个方法中进行监听器的添加的,会创建一个监听器的适配器     // 调用类为 EventListenerMethodProcessor     if (singletonInstance instanceof SmartInitializingSingleton) {       SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;       // 权限检查       if (System.getSecurityManager() != null) {         AccessController.doPrivileged((PrivilegedAction<Object>) () -> {           smartSingleton.afterSingletonsInstantiated();           return null;         }, getAccessControlContext());       }       else {         smartSingleton.afterSingletonsInstantiated();       }     }   } } 

通过源码可以知道,Spring前期在进行XML进行loadBeanDefinitions加载或者BeanFactoryPostProcessor子类BeanDefinitionRegistryPostProcessor的实现类ConfigurationClassPostProcessor注解解析 出来的BeanDefinition放入两个集合BeanDefinitionMapBeanDefinitionNames,这里遍历的是BeanDefinitionNames这个集合,存放的是beanName

首先是进行了BeanDefinition的合并处理,最终返回的全是RootBeanDefinition,进入源码可以看到这里是从缓存中获取的,如果有则直接取出来,否则再去解析。

protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {   // Quick check on the concurrent map first, with minimal locking.   // 从缓存中获取   RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);   if (mbd != null && !mbd.stale) {     return mbd;   }   return getMergedBeanDefinition(beanName, getBeanDefinition(beanName)); } 

那么第一次进行调用时什么地方呢?是在进行BeanFactoryPostProcessor 的执行和解析时调用的,在解析BeanFactoryPostProcessor时调用了 getBeanNamesForType方法,然后调用doGetBeanNamesForType时进行了BeanDefinitionNames集合的遍历合并Bean

private String[] doGetBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) {   List<String> result = new ArrayList<>();   // Check all bean definitions.   // 遍历所有的BeanDefinitionNames集合   for (String beanName : this.beanDefinitionNames) {     // Only consider bean as eligible if the bean name is not defined as alias for some other bean.     if (!isAlias(beanName)) {       try {         // 从本地缓存中获取合并的BeanDefinition         RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);         // Only check bean definition if it is complete.         if (!mbd.isAbstract() && (allowEagerInit ||                                   (mbd.hasBeanClass() || !mbd.isLazyInit() || isAllowEagerClassLoading()) &&                                   !requiresEagerInitForType(mbd.getFactoryBeanName()))) {           // 是否是FactoryBean           boolean isFactoryBean = isFactoryBean(beanName, mbd);           BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();           boolean matchFound = false;           boolean allowFactoryBeanInit = (allowEagerInit || containsSingleton(beanName));           boolean isNonLazyDecorat             // 省略代码....         }       }     }   }  

所以在执行preInstantiateSingletons 预实例化单例时获取的RootBeanDefinition基本是从缓存中获取的。

接着是判断如果是单例的并且不是抽象的,不是懒加载的,那么就进行Bean的创建,然后又判断是否是FactoryBean,如果是那么就进行下一步逻辑。

FactoryBean 是什么?

FactoryBean是用来创建Bean对象的,他是一个接口,方法:

  • getObject 获取bean对象
  • getObjectType 获取bean的类型
  • isSingleton 是否是单例的,默认是true

在创建对象时,你可以直接在getObject方法中进行new,或者反射,或者是其他都可以,非常的灵活。接下来使用FactoryBean进行自定义的Bean的创建。

定义一个FactoryBean的实现类:

/**  * @author <a href="https://www.cnblogs.com/redwinter/">redwinter</a>  * @since 1.0  **/ public class MyFactoryBean implements FactoryBean<MyUser> {  	@Override 	public MyUser getObject() throws Exception {       	// 直接new一个对象 		return new MyUser(); 	}  	@Override 	public Class<?> getObjectType() { 		return MyUser.class; 	}  	@Override 	public boolean isSingleton() { 		return true; 	} } 

定义MyUser

/**  * @author <a href="https://www.cnblogs.com/redwinter/">redwinter</a>  * @since 1.0  **/ public class MyUser { }  

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="myFactoryBean" class="com.redwinter.selffactorybean.MyFactoryBean"/> </beans> 

测试类:

/**  * @author <a href="https://www.cnblogs.com/redwinter/">redwinter</a>  * @since 1.0  **/ public class FactoryBeanTest {  	@Test 	public void test(){ 		MyClassPathXmlApplicationContext context = new MyClassPathXmlApplicationContext("spring-factory.xml");  		Object myFactoryBean =  context.getBean("myFactoryBean"); 		System.out.println(myFactoryBean);  		Object myFactoryBean2 =  context.getBean("&myFactoryBean"); 		System.out.println(myFactoryBean2);  	} } 

输出:

com.redwinter.test.selffactorybean.MyUser@2d554825 com.redwinter.test.selffactorybean.MyFactoryBean@68837a77 

这里可以看到FactoryBean 创建Bean的时候,xml注册的是一个FactoryBean的实现,但是获取出来又是具体的MyUser对象,这里Spring使用了懒加载的机制,在SpringBean进行初始化时,实际上只将FactoryBean的实现类注册到了Spring容器中,当我们需要使用的时候,才去判断,如果是FactoryBean类型的,那么就去调用getObject方法去创建对象。如果是第二次去获取Bean,那么是从缓存中获取的,如果是获取&前缀的Bean,那就直接返回。

protected Object getObjectForBeanInstance(   Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {    // Don't let calling code try to dereference the factory if the bean isn't a factory.   // 判断是否是&前缀标识   if (BeanFactoryUtils.isFactoryDereference(name)) {     if (beanInstance instanceof NullBean) {       return beanInstance;     }     if (!(beanInstance instanceof FactoryBean)) {       throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());     }     if (mbd != null) {       mbd.isFactoryBean = true;     }     return beanInstance;   }    // Now we have the bean instance, which may be a normal bean or a FactoryBean.   // If it's a FactoryBean, we use it to create a bean instance, unless the   // caller actually wants a reference to the factory.   if (!(beanInstance instanceof FactoryBean)) {     return beanInstance;   }    Object object = null;   if (mbd != null) {     mbd.isFactoryBean = true;   }   else {     // 从缓存中获取     object = getCachedObjectForFactoryBean(beanName);   }   if (object == null) {     // Return bean instance from factory.     FactoryBean<?> factory = (FactoryBean<?>) beanInstance;     // Caches object obtained from FactoryBean if it is a singleton.     if (mbd == null && containsBeanDefinition(beanName)) {       mbd = getMergedLocalBeanDefinition(beanName);     }     // 判断是否是合成的Bean,是否是应用程序本身设置的,比如某些aop 就是合成的Bean     boolean synthetic = (mbd != null && mbd.isSynthetic());     // 执行getObject方法获取Bean     object = getObjectFromFactoryBean(factory, beanName, !synthetic);   }   return object; } 

Spring 源码(10)Spring Bean 的创建过程(1)

BeanFactory 和FactoryBean 的区别?

根据前面的文章介绍,我们知道BeanFactory是一个Bean的创建工厂,比如AbstractApplicationContext就是BeanFactory的实现类,这个类就是用来创建Bean的,创建出来的Bean放在缓存中。而FactoryBean就是Bean实例,是由BeanFactory创建的,并且FactoryBean也是用来创建Bean对象,使用getObject方法进行创建,也是会放在缓存中供下次直接获取,而且如果在使用时需要使用FactoryBean的实例时需要以&前缀才能获取到,比如getBean("&myFactoryBean"); 如果是获取通过getObject方法创建的对象时,就不需要添加&前缀,比如getBean("myFactoryBean"); 总结一下:

相同点:

  • 都是用来创建对象的
  • 都是创建出来之后放入缓存中供下次直接使用

不同点:

  • BeanFactory是一个对象创建工厂,而FactoryBean是一个Bean实例
  • BeanFactory创建的对象一般来说都是使用反射调用构造函数创建的,而FactoryBean创建对象是调用getObject方法创建,并且创建方式不一定是通过反射,可以是直接new对象或者其他方式
  • FactoryBean 在获取对象时,可以获取到两个对象,一个是存放在BeanFactory创建的缓存中,通过&beanName获取的FactoryBean的实现类对象,一个是调用getObject创建的,通过beanName获取的具体对象。

Spring 源码(10)Spring Bean 的创建过程(1)

Bean的创建过程非常复杂,下一篇继续。

发表评论

相关文章