IOC容器初始化之创建对象的方式(六)

序言

为了对Spring内部创建对象机制有一个总体把控,先将Spring引用中创建对象的途径进行分类。Spring应用中创建对象的方式:

  • 一种是直接new一个对象,比如DefaultListableBeanFactory等;
  • 另一种方式是通过读取beanDefinition中的getBean的方式反射创建对象;
  • getBean的调用又分为几种情况:
    - 一是维持Spring自身运行的核心bean
    - 二是扩展Spring功能的核心bean
    - 三是集成第三方组件,比如shiro或者自定义的bean
  • 最后一种是通过完整类名反射创建对象

直接通过new对象的情形

  • Spring中通过new创建对象最常见的场景就是loadBeanDefinition操作,为解析XML而创建的解析对象。
  • 另一种是没必要通过loadBeanDefinition,在容器中生成对象。这一部分的代表对象是AOP中的,以及Spring事务的内部类等;但有一些内部类,比如ConfigurationClassPostProcessor中的,就需要生成beanDefinition,然后在registerBeanPostProcessors中创建对象。
  • 其次是方法中传入多参数时,通过持有对象比如ReaderContext或者Holder对象或者ParserContext等来便于多参数的管理。
    总结
    这部分创建的对象,都是为了将类解析成为BeanDefinition而服务的。
    详见第四篇的@AspectJ @Async @Schedule

通过getBean创建对象

维持Spring自身运行的核心bean

集中在invokeBeanFactoryPostProcessors以及registerBeanPostProcessors中。

  • 在获取BeanDefinitionRegistryPostProcessors的beanName时,如果是包含mybatis的spring应用,则会有两个符合该类型的beanName:
    <org.springframework.context.annotation.internalConfigurationAnnotationProcessor>
    <org.mybatis.spring.mapper.MapperScannerConfigurer#0>
    1.1 优先执行实现了PriorityOrdered的beanName,来创建对象,只有ConfigurationClassPostProcessors(该类的作用是,找到@Configuration注解的类,并进一步生成其内部的beanDefinition信息,比如@Bean方法,嵌套的内部类等);
    2.2 再执行实现了Ordered的beanName,并创建对象。
    3.3 剩余的beanName,并创建对象;比如集成了mybatis的mybatis-spring的MapperScannerConfigurer
  • 在registerBeanPostProcessors中,创建的是对具体bean的对象处理的后置处理对象,比如通过注解依赖注入的后置处理器等
    这些对象详见第四篇的registerBeanPostProcessors

维持Spring扩展功能的核心bean

比如Spring的@AspectJ @Async @Schedule等
这些对象详见第四篇的registerBeanPostProcessors

以Spring应用为基础的用户应用

用户自定义的要被Spring容器创建的对象

创建bean的流程机制

理解Spring容器创建对象的机制,首先要理解Spring容器中的各种集合对象。换句话说,Spring的IOC容器其实就是各种集合。

1. 存储BeanDefinition的集合

 /** Map of bean definition objects, keyed by bean name */
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

该集合将需要Spring容器创建对象的类解析成BeanDefinition存储。存储大体上分为两类:

  • 第一种是Spring核心的类的BeanDefinition,最明显的标志就是其key是包名+类名
  • 第二种是用户自定义的bean的beanName,包括XMl中定义的bean的id或者用Spring注解的类名等。

2. 存储创建对象的集合

发生在doGetBean时期

2.1 alreadyCreated

	/** Names of beans that have already been created at least once */
	private final Set<String> alreadyCreated =
			Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>(256));

当所创建的bean,typeCheckOnly为false时,且该集合不包含该beanName,添加。在doGetBean的markBeanAsCreated(beanName);

2.2 singletonsCurrentlyInCreation

	/** Names of beans that are currently in creation */
	private final Set<String> singletonsCurrentlyInCreation =
			Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>(16));

当正在创建该beanName的对象之前,向该集合添加。
发生在getSingleton(String beanName, ObjectFactory<?> singletonFactory)的beforeSingletonCreation(beanName);

2.3 singletonFactories

	/** Cache of singleton factories: bean name --> ObjectFactory */
	private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

向这一集合添加beanName跟对象工厂的映射,发生在doCreateBean时期。
当创建beanName的对象时,该beanName所对应的BeanDefinition,如果是单例的,并且允许循环引用,且正在创建bean的单例对象,就向该集合中添加。

2.4 filteredPropertyDescriptorsCache

	/** Cache of filtered PropertyDescriptors: bean Class -> PropertyDescriptor array */
	private final ConcurrentMap<Class<?>, PropertyDescriptor[]> filteredPropertyDescriptorsCache =
			new ConcurrentHashMap<Class<?>, PropertyDescriptor[]>(256);

2.5 ignoredDependencyInterfaces

	/**
	 * Dependency interfaces to ignore on dependency check and autowire, as Set of
	 * Class objects. By default, only the BeanFactory interface is ignored.
	 */
	private final Set<Class<?>> ignoredDependencyInterfaces = new HashSet<Class<?>>();

这个集合作用,忽视依赖检查注入的的接口集合。

2.6 factoryBeanInstanceCache

	/** Cache of unfinished FactoryBean instances: FactoryBean name --> BeanWrapper */
	private final Map<String, BeanWrapper> factoryBeanInstanceCache =
			new ConcurrentHashMap<String, BeanWrapper>(16);

存放早期创建的FactoryBean对象。这种创建过程就单单是创建了一个对象,跟doCreateBean的创建不是一个流程。这里创建的对象暂时不会放到singletonObjects中。这个是为了防止早期创建的对象后,又通过getBean创建该对象。比如shiroFilter对象。最先开始创建该对象的时机在registerBeanPostProcessors的ordered步骤中。通过从所有的beanDefinition中找到TaskExecutor并创建。又在该方法中的nonOrdered再次创建该对象。,所以有了这一步的处理

		BeanWrapper instanceWrapper = null;
		if (mbd.isSingleton()) {
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		// 从factoryBeanInstanceCache删除该对象成功,代表已经创建过该beanName的对象了
		if (instanceWrapper == null) {
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
	/**
	 * Obtain a "shortcut" singleton FactoryBean instance to use for a
	 * {@code getObjectType()} call, without full initialization of the FactoryBean.
	 * @param beanName the name of the bean
	 * @param mbd the bean definition for the bean
	 * @return the FactoryBean instance, or {@code null} to indicate
	 * that we couldn't obtain a shortcut FactoryBean instance
	 */
	private FactoryBean<?> getSingletonFactoryBeanForTypeCheck(String beanName, RootBeanDefinition mbd) {
		synchronized (getSingletonMutex()) {
			BeanWrapper bw = this.factoryBeanInstanceCache.get(beanName);
			if (bw != null) {
				return (FactoryBean<?>) bw.getWrappedInstance();
			}
			if (isSingletonCurrentlyInCreation(beanName) ||
					(mbd.getFactoryBeanName() != null && isSingletonCurrentlyInCreation(mbd.getFactoryBeanName()))) {
				return null;
			}
			Object instance = null;
			try {
				// Mark this bean as currently in creation, even if just partially.
				beforeSingletonCreation(beanName);
				// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
				instance = resolveBeforeInstantiation(beanName, mbd);
				if (instance == null) {
					bw = createBeanInstance(beanName, mbd, null);
					instance = bw.getWrappedInstance();
				}
			}
			finally {
				// Finished partial creation of this bean.
				afterSingletonCreation(beanName);
			}
			FactoryBean<?> fb = getFactoryBean(beanName, instance);
			if (bw != null) {
				this.factoryBeanInstanceCache.put(beanName, bw);
			}
			return fb;
		}
	}

2.4 disposableBeans

	/** Disposable bean instances: bean name --> disposable instance */
	private final Map<String, Object> disposableBeans = new LinkedHashMap<String, Object>();

为了可以销毁指定的bean实例而保留的集合

2.5 singletonObjects

	/** Cache of singleton objects: bean name --> bean instance */
	private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);

创建完一个完整的bean实例后,包含populateBean和initializeBean的bean,才向singletonObjects中添加新对象。

2.6 registeredSingletons

	/** Set of registered singletons, containing the bean names in registration order */
	private final Set<String> registeredSingletons = new LinkedHashSet<String>(256);

3. 创建bean的详细过程

创建bean,也分场景。不同类型的bean走不同,但总体上满足四个流程:

createBeanInstance
populateBean
initializeBean
registerDisposableBeanIfNecessary

3.1 populateBean过程

第一种情况:
以org.springframework.aop.config.internalAutoProxyCreator为例填充属性值。
从PropertyValues找到并向创建的bean实例中设置值,设置的三个值分别是ordered(最大值),exposeProxy和proxyTargetClass都为true。这个是在loadBeanDefinition中解析xml标签的属性设置的。
第二种情况:
以org.springframework.context.annotation.internalAsyncAnnotationProcessor为例的填充值。
PropertyValues为空。
第三种情况:
以&shiroFilter为例的填充值。 它的bean property为securityManager,是RuntimeBeanReference类型,调用resolveReference(argName, ref);来创建该beanName的属性的对象。

/**
	 * Resolve a reference to another bean in the factory.
	 */
	private Object resolveReference(Object argName, RuntimeBeanReference ref) {
		try {
			String refName = ref.getBeanName();
			refName = String.valueOf(doEvaluate(refName));
			if (ref.isToParent()) {
				if (this.beanFactory.getParentBeanFactory() == null) {
					throw new BeanCreationException(
							this.beanDefinition.getResourceDescription(), this.beanName,
							"Can't resolve reference to bean '" + refName +
							"' in parent factory: no parent factory available");
				}
				return this.beanFactory.getParentBeanFactory().getBean(refName);
			}
			else {
			    // shiroFilter的bean property = securityManager
				Object bean = this.beanFactory.getBean(refName);
				this.beanFactory.registerDependentBean(refName, this.beanName);
				return bean;
			}
		}
		catch (BeansException ex) {
			throw new BeanCreationException(
					this.beanDefinition.getResourceDescription(), this.beanName,
					"Cannot resolve reference to bean '" + ref.getBeanName() + "' while setting " + argName, ex);
		}
	}

第四种情况:
以bean property 其实是一个list。以XML为例

	<bean id="authenticator" class="org.apache.shiro.authc.pam.ModularRealmAuthenticator">
        <property name="realms">
            <list>
                <ref bean="customRealm"/>
                <ref bean="operLoginValidRealm"/>
            </list>
        </property>
        <property name="authenticationStrategy">
            <bean class="org.apache.shiro.authc.pam.AllSuccessfulStrategy"/>
        </property>
        <property name="authenticationListeners">
            <list>
                <bean class="com.yxf.common.shiro.listener.CustomAuthenticationListener"/>
            </list>
        </property>
    </bean>

这个realms其实是一个resolveManagedList。
Autowired属性注入的对象创建的时机发生在populateBean的后置处理器。调用element.inject(…)的beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);。这是因为Autowired注解注入的对象创建是由AutowiredAnnotationBeanPostProcessor的实现了InjectionMetadata的内部类处理。

if (hasInstAwareBpps || needsDepCheck) {
			PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
			if (hasInstAwareBpps) {
				for (BeanPostProcessor bp : getBeanPostProcessors()) {
					if (bp instanceof InstantiationAwareBeanPostProcessor) {
						InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
						// 当有bean property使用Autowired时等
						pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
						if (pvs == null) {
							return;
						}
					}
				}
			}
			if (needsDepCheck) {
				checkDependencies(beanName, mbd, filteredPds, pvs);
			}
		}

读取依赖创建@Autowired

value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);

还是以shiroFilter为例。
在读取依赖的过程中,会再次调用doGetBeanNamesForType方法。还是从所有的beanDefinition中匹配与注入类型相同的。在这一个过程中,会再次找到shiroFilterFactoryBean。再次调用isTypeMatch。已经创建过该对象。会通过==getSingleton(beanName=shiroFilter)==一直调用。

/**
	 * Return the (raw) singleton object registered under the given name.
	 * <p>Checks already instantiated singletons and also allows for an early
	 * reference to a currently created singleton (resolving a circular reference).
	 * @param beanName the name of the bean to look for
	 * @param allowEarlyReference whether early references should be created or not
	 * @return the registered singleton object, or {@code null} if none found
	 */
	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		Object singletonObject = this.singletonObjects.get(beanName);
		// 现在处于populateBean(shiroFilter的阶段,所以如下两个条件都满足)
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			synchronized (this.singletonObjects) {
				singletonObject = this.earlySingletonObjects.get(beanName);
				if (singletonObject == null && allowEarlyReference) {
					// 这上面的条件也满足且shiroFilter已经创建了不过这个对象并不完整。
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					if (singletonFactory != null) {
					    // singletonFactory = AbstractAutowireCapableBeanFactory$2
						singletonObject = singletonFactory.getObject();
						this.earlySingletonObjects.put(beanName, singletonObject);
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return (singletonObject != NULL_OBJECT ? singletonObject : null);
	}
	-----------------------------------------------------------
	addSingletonFactory(beanName, new ObjectFactory<Object>() {
				@Override
				public Object getObject() throws BeansException {
				    // 还有BeanPostProcessor,此时的加上了AOP等。
					return getEarlyBeanReference(beanName, mbd, bean);
				}
			});

3.2 initializeBean过程

这里有一个invokeAware方法。这个是对扩展Spring预留的持有Spring容器或者资源加载器或者类加载的入口。
第一种情况:
以org.springframework.aop.config.internalAutoProxyCreator为例,这个初始化主要是该类的内部类的对象的创建。
第二种情况:
以org.springframework.context.annotation.internalAsyncAnnotationProcessor为例,在执行这个方法时,向这个Bean后置处理器装入Spring的类加载器,资源加载器,以及Spring的beanFactory。这个AnnotationAwareAsyncBeanPostProcessor后置处理器,要生成一个TaskExecutor对象,且通过容器生成对象并注册到容器中。这就是BeanFactoryAware的作用,实现了这个接口的对象,会让我们能够从Spring中获取到容器对象,对beanFactory进行手动getBean的操作等。

	@Override
	public void setBeanFactory(BeanFactory beanFactory) {
		super.setBeanFactory(beanFactory);

		Executor executorToUse = this.executor;
		if (executorToUse == null) {
			try {
				// Search for TaskExecutor bean... not plain Executor since that would
				// match with ScheduledExecutorService as well, which is unusable for
				// our purposes here. TaskExecutor is more clearly designed for it.
				executorToUse = beanFactory.getBean(TaskExecutor.class);
			}
			catch (NoUniqueBeanDefinitionException ex) {
				try {
					executorToUse = beanFactory.getBean(DEFAULT_TASK_EXECUTOR_BEAN_NAME, Executor.class);
				}
				catch (NoSuchBeanDefinitionException ex2) {
					logger.info("More than one TaskExecutor bean found within the context, and none is " +
							"named 'taskExecutor'. Mark one of them as primary or name it 'taskExecutor' " +
							"(possibly as an alias) in order to use it for async annotation processing.");
				}
			}
			catch (NoSuchBeanDefinitionException ex) {
				logger.info("No TaskExecutor bean found for async annotation processing.");
				// Giving up -> falling back to default executor within the advisor...
			}
		}

		AsyncAnnotationAdvisor advisor =  new AsyncAnnotationAdvisor(executorToUse, this.exceptionHandler);
		if (this.asyncAnnotationType != null) {
			advisor.setAsyncAnnotationType(this.asyncAnnotationType);
		}
		advisor.setBeanFactory(beanFactory);
		this.advisor = advisor;
	}

在这一步中,会读取所有的beanDefinition进行查找符合TaskExecutor类型的。同时呢,如果这些beanDefinition中有FactoryBean的会进行另一步操作。比如,有sqlSessionFactory,判断sqlSessionFactory的类型,是FactoryBean且该beanName=sqlSessionFactory不是以&开头,调用getTypeForFactoryBean(beanName, mbd)。在方法内会创建FactoryBean类型的对象。比如,sqlSessionFactory是单例的,就会调用getSingletonFactoryBeanForTypeCheck获取FactoryBean,这个走的是无参构造;
当然了各种mybatis的mapper接口在这里也会被创建出来,因为这些mapper接口的BeanDefinition都是MapperFactoryBean类型。走的是有参构造autowireConstructor(beanName, mbd, ctors, args);
最终找到定义的ThreadPoolTaskExecutor的beanName。
这个ThreadPoolTaskExecutor实现了BeanNameAware,也实现了InitializingBean。以便创建玩对象初始化后,创建ThreadPoolExecutor并赋值给ThreadPoolTaskExecutor.
创建该bean对象,又回到之前的创建bean流程。【只要是通过beanName创建bean对象】
这个是通过populateBean的applyPropertyValues的resolveValueIfNecessary,通过resolveInnerBean创建bean对象即rejectedExecutionHandler这种方式

<bean id="threadPool"
          class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor"> 
        <!-- 线程池对拒绝任务(无线程可用)的处理策略 ThreadPoolExecutor.CallerRunsPolicy策略 ,调用者的线程会执行该任务,如果执行器已关闭,则丢弃. -->
        <property name="rejectedExecutionHandler">
            <bean class="java.util.concurrent.ThreadPoolExecutor$CallerRunsPolicy" />
        </property>
    </bean>

FactoryBean的作用机制,以MapperFactoryBean为例

如果sharedInstance是FactoryBean,从FactoryBean中获取bean对象,而不是FactoryBean实例。
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
总结
bean对象并不都是通过DefaultListableBeanFactory创建的,比如mybatis的mapper接口对象是通过MapperFactoryBean创建的。每一个Mapper接口对应一个MapperFactoryBean对象,最终创建的是MapperProxy对象。(也就是用@Autowired注解的对象)

/**
	 * Obtain an object to expose from the given FactoryBean.
	 * @param factory the FactoryBean instance
	 * @param beanName the name of the bean
	 * @return the object obtained from the FactoryBean
	 * @throws BeanCreationException if FactoryBean object creation failed
	 * @see org.springframework.beans.factory.FactoryBean#getObject()
	 */
	private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)
			throws BeanCreationException {

		Object object;
		try {
			if (System.getSecurityManager() != null) {
				AccessControlContext acc = getAccessControlContext();
				try {
					object = AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
						@Override
						public Object run() throws Exception {
								return factory.getObject();
							}
						}, acc);
				}
				catch (PrivilegedActionException pae) {
					throw pae.getException();
				}
			}
			else {
			    // 以MapperFactoryBean为例,调用的是MapperFactoryBean的重写getObject方法。(从MapperFactoryBean创建对象,而不是		 
			    // beanFactory)
				object = factory.getObject();
			}
		}
		catch (FactoryBeanNotInitializedException ex) {
			throw new BeanCurrentlyInCreationException(beanName, ex.toString());
		}
		catch (Throwable ex) {
			throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
		}

		// Do not accept a null value for a FactoryBean that's not fully
		// initialized yet: Many FactoryBeans just return null then.
		if (object == null && isSingletonCurrentlyInCreation(beanName)) {
			throw new BeanCurrentlyInCreationException(
					beanName, "FactoryBean which is currently in creation returned null from getObject");
		}
		return object;
	}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值