Spring创建bean的方式
- 序言
- 直接通过new对象的情形
- 通过getBean创建对象
- 维持Spring自身运行的核心bean
- 维持Spring扩展功能的核心bean
- 以Spring应用为基础的用户应用
- 创建bean的流程机制
- 1. 存储BeanDefinition的集合
- 2. 存储创建对象的集合
- 2.1 alreadyCreated
- 2.2 singletonsCurrentlyInCreation
- 2.3 singletonFactories
- 2.4 filteredPropertyDescriptorsCache
- 2.5 ignoredDependencyInterfaces
- 2.6 factoryBeanInstanceCache
- 2.4 disposableBeans
- 2.5 singletonObjects
- 2.6 registeredSingletons
- 3. 创建bean的详细过程
- 3.1 populateBean过程
- 3.2 initializeBean过程
- FactoryBean的作用机制,以MapperFactoryBean为例
序言
为了对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走不同,但总体上满足四个流程:
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;
}