spring使用bean定义初始化bean分析

写在前面

spring IOC注册BeanDefinition
中已经完成了BeanDefinition向spring的map缓存中注册的工作,本文接着分析spring是如何通过beandefinition来初始化bean对象的。只看源码的话比较枯燥,对应的流程图版本可以参考这里

1:测试使用代码

1.1:使用的bean

public class BookService {
}

1.2: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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="bookService" class="yudaosourcecode.constructorarg.BookService"/>
</beans>

1.3:测试代码

@Test
public void testGetBean() {
    ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("testbeandefinition.xml");
    BookService bookService = ac.getBean("bookService", BookService.class);
    System.out.println(bookService);
}

运行:

yudaosourcecode.constructorarg.BookService@670b40af

Process finished with exit code 0

我们就从代码ac.getBean("bookService", BookService.class);开始看起吧!

2:getBean

先调用的是org.springframework.beans.factory.BeanFactory容器顶层接口的子类AbstractApplicationContext,源码:

org.springframework.context.support.AbstractApplicationContext#getBean(java.lang.String, java.lang.Class<T>)
public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
	// <2021-03-10 09:20>
	assertBeanFactoryActive();
	// <2021-03-10 09:21>
	return getBeanFactory().getBean(name, requiredType);
}

<2021-03-10 09:20>处是检测bean工厂容器的活跃性,源码:

org.springframework.context.support.AbstractApplicationContext#assertBeanFactoryActive
protected void assertBeanFactoryActive() {
	// this.active定义为private final AtomicBoolean active = new AtomicBoolean();
	// 若为false,则继续判断是否关闭
	if (!this.active.get()) {
		// this.closed定义为private final AtomicBoolean closed = new AtomicBoolean();
		// 若为true则抛出异常,给出已经关闭的信息
		if (this.closed.get()) {
			throw new IllegalStateException(getDisplayName() + " has been closed already");
		}
		// 若为false,说明没有关闭,给出容器还没有进行刷新的异常信息
		else {
			throw new IllegalStateException(getDisplayName() + " has not been refreshed yet");
		}
	}
}

<2021-03-10 09:21>getBeanFactory()调用的是BeanFactory顶层容器接口的子类AbstractRefreshableApplicationContext,源码:

org.springframework.context.support.AbstractRefreshableApplicationContext#getBeanFactory
public final ConfigurableListableBeanFactory getBeanFactory() {
	synchronized (this.beanFactoryMonitor) {
		// 如果是为null,说明已经关闭或者是容器还没有刷新
		// 给出相关的异常信息
		if (this.beanFactory == null) {
			throw new IllegalStateException("BeanFactory not initialized or already closed - " +
					"call 'refresh' before accessing beans via the ApplicationContext");
		}
		// 这里的类型是DefaultListableBeanFacotry
		return this.beanFactory;
	}
}

<2021-03-10 09:21>的getBean调用的是AbstractBeanFactory的方法,源码:

org.springframework.beans.factory.support.AbstractBeanFactory#getBean(java.lang.String, java.lang.Class<T>)
public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
	return doGetBean(name, requiredType, null, false);
}

继续:

org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
		@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
	// <2021-03-10 10:03>
	// 获取bean名称,如转换alias为beanName
	final String beanName = transformedBeanName(name);
	Object bean;

	// 从单例缓存中获取bean,单例bean只会创建一次,这里具体的代码体现
	Object sharedInstance = getSingleton(beanName);
	// 如果是单例bean,if内部会处理FactoryBean,后置bean处理器等逻辑
	if (sharedInstance != null && args == null) { // 单例bean的逻辑
		if (logger.isTraceEnabled()) {
			if (isSingletonCurrentlyInCreation(beanName)) {
				logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
						"' that is not fully initialized yet - a consequence of a circular reference");
			}
			else {
				logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
			}
		}
		// <2021-03-10 10:17>
		// 处理FactoryBean
		bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
	}

	else { // 原型bean的逻辑
		// <2021-03-10 18:41>
		// 如果是当前bean已经在创建中,并且是prototype的
		// 说明存在prototype的循环依赖,则抛出异常,因为spring只解决singleton的循环依赖
		if (isPrototypeCurrentlyInCreation(beanName)) {
			throw new BeanCurrentlyInCreationException(beanName);
		}

		// <2021-03-11 09:15>
		// 如果是后续无法从当前容器获取bean定义,则尝试从父容器中
		// 获取
		BeanFactory parentBeanFactory = getParentBeanFactory();
		if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
			// Not found -> check parent.
			String nameToLookup = originalBeanName(name);
			if (parentBeanFactory instanceof AbstractBeanFactory) {
				return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
						nameToLookup, requiredType, args, typeCheckOnly);
			}
			else if (args != null) {
				// Delegation to parent with explicit args.
				return (T) parentBeanFactory.getBean(nameToLookup, args);
			}
			else if (requiredType != null) {
				// No args -> delegate to standard getBean method.
				return parentBeanFactory.getBean(nameToLookup, requiredType);
			}
			else {
				return (T) parentBeanFactory.getBean(nameToLookup);
			}
		}
		// <2021-03-11 18:35>
		if (!typeCheckOnly) {
			markBeanAsCreated(beanName);
		}

		try {
			// <2021-03-11 18:39>
			final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
			// <2021-03-11 18:45>
			checkMergedBeanDefinition(mbd, beanName, args);

			// <2021-03-13 10:17>
			String[] dependsOn = mbd.getDependsOn();
			if (dependsOn != null) {
				for (String dep : dependsOn) {
					// 因为当前beanName是depend-on dep的
					// 如果是dep也depend-on beanName,则异常
					if (isDependent(beanName, dep)) {
						throw new BeanCreationException(mbd.getResourceDescription(), beanName,
								"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
					}
					registerDependentBean(dep, beanName);
					try {
						getBean(dep);
					}
					catch (NoSuchBeanDefinitionException ex) {
						throw new BeanCreationException(mbd.getResourceDescription(), beanName,
								"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
					}
				}
			}

			// <2021-03-13 10:29>
			// bean的实例化,分为单例singleton,原型prototype分别处理
			if (mbd.isSingleton()) { // 单例模式
				sharedInstance = getSingleton(beanName, () -> {
					try {
						return createBean(beanName, mbd, args);
					}
					catch (BeansException ex) {
						destroySingleton(beanName);
						throw ex;
					}
				});
				bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
			}

			else if (mbd.isPrototype()) { // 原型模式
				// It's a prototype -> create a new instance.
				Object prototypeInstance = null;
				try {
					beforePrototypeCreation(beanName);
					prototypeInstance = createBean(beanName, mbd, args);
				}
				finally {
					afterPrototypeCreation(beanName);
				}
				bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
			}

			else { // 不能直接判断
				// 显式获取scope
				String scopeName = mbd.getScope();
				// this.scopes是一个"scope名称->Scope对象"的map
				final Scope scope = this.scopes.get(scopeName);
				// 如果没有获取到scope则异常,因为创建bean需要依赖于其scope
				if (scope == null) {
					throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
				}
				try {
					Object scopedInstance = scope.get(beanName, () -> {
						beforePrototypeCreation(beanName);
						try {
							return createBean(beanName, mbd, args);
						}
						finally {
							afterPrototypeCreation(beanName);
						}
					});
					bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
				}
				catch (IllegalStateException ex) {
					throw new BeanCreationException(beanName,
							"Scope '" + scopeName + "' is not active for the current thread; consider " +
							"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
							ex);
				}
			}
		}
		catch (BeansException ex) {
			cleanupAfterBeanCreationFailure(beanName);
			throw ex;
		}
	}

	// <2021-03-13 10:50>
	// 检查需要的类型是否符合实际的类型
	if (requiredType != null && !requiredType.isInstance(bean)) {
		try {
			T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
			if (convertedBean == null) {
				throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
			}
			return convertedBean;
		}
		catch (TypeMismatchException ex) {
			if (logger.isTraceEnabled()) {
				logger.trace("Failed to convert bean '" + name + "' to required type '" +
						ClassUtils.getQualifiedName(requiredType) + "'", ex);
			}
			throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
		}
	}
	return (T) bean;
}

<2021-03-10 10:03>获取最终要初始化的beanName,具体参考2.1:transformedBeanName转换bean名称,<2021-03-10 10:17>处是从单例缓存中获取bean,并进行FactoryBean的相关处理,具体参考2.2:getObjectForBeanInstance,<2021-03-10 18:41>处代码是检测prototype的bean存在循环依赖的情况,spring不处理这种情况,具体参考2.3:prototype的bean循环依赖检测,<2021-03-11 09:15>处是尝试从父容器中查找bean定义,具体参考2.4:从父容器中查找bean定义,<2021-03-11 18:35>处是将bean标记为已创建或者是正在创建中,详细参考2.5:markBeanAsCreated,<2021-03-11 18:39>处是通过bean名称获取beandefinition,详细参考2.6:通过bean名称获取bean定义<2021-03-11 18:45>处是检查当前beandefinition是否为抽象bean,抽象bean仅仅用于定义公共信息,不能实例化,源码如下:

org.springframework.beans.factory.support.AbstractBeanFactory#checkMergedBeanDefinition
protected void checkMergedBeanDefinition(RootBeanDefinition mbd, String beanName, @Nullable Object[] args)
			throws BeanDefinitionStoreException {
	// 如果是抽象的,则异常
	if (mbd.isAbstract()) {
		throw new BeanIsAbstractException(beanName);
	}
}

详细关于抽象bean可以参考spring配置中的abstract,parent分析
,<2021-03-13 10:17>处是依赖bean的处理,具体参考2.7:依赖bean的处理,关于依赖bean depend-on可以参考spring如何控制bean的初始化顺序
,<2021-03-13 10:29>处是初始化不同作用域的bean,具体参考2.8:不同作用域bean的初始化,<2021-03-13 10:50>处是检查要求的类型是否和实际的类型一致,如果是不一致的话需要进行类型转换,详细参考2.9:强制类型转换

2.1:transformedBeanName转换bean名称

执行如下代码:

org.springframework.beans.factory.support.AbstractBeanFactory#transformedBeanName
protected String transformedBeanName(String name) {
	// <2021-03-14 09:17>
	// 这里是转换非标准bean名称(别名,工厂bean名称)为标准bean名称
	// 1:如果是工厂bean名称去除前面所有的&
	// 2:转换1的结果如果是别名则转换为标准bean名称
	// 需要注意工厂bean名称也可能存在别名的场景
	return canonicalName(BeanFactoryUtils.transformedBeanName(name));
}

<2021-03-14 09:17>transformedBeanName是去除bean工厂的修饰符&,关于bean工厂可以参考spring的BeanFactory分析
,源码如下:

org.springframework.beans.factory.BeanFactoryUtils#transformedBeanName
public static String transformedBeanName(String name) {
	// 判空
	Assert.notNull(name, "'name' must not be null");
	// 如果不是以&开头,则不是bean工厂的bean名称,直接返回
	if (!name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
		return name;
	}
	// transformedBeanNameCache定义为:
	//  Map<String, String> transformedBeanNameCache = new ConcurrentHashMap<>();
	// 是一个存储”bean工厂bean名称->实际bean名称“的缓存
	// 这里,如果是存在key为name的则直接返回,否则,调用
	// conputerIfAbsent的第二个参数,去除&,直到不以&开头就是我们需要的结果了
	return transformedBeanNameCache.computeIfAbsent(name, beanName -> {
		do {
			beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
		}
		while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
		// 返回bean名称,如&&&myBeanName,结果就是myBeanName
		return beanName;
	});
}

<2021-03-14 09:17>处canonicalName是转换别名为标准名称,源码:

org.springframework.core.SimpleAliasRegistry#canonicalName
public String canonicalName(String name) {
	// 默认使用当前名称作为标准名称
	String canonicalName = name;
	String resolvedName;
	do {
		// 从别名map中获取标准bean名称
		// 这里循环处理的原因是别名获取的结果可能还是别名,如通过
		// alias标签即可以给标准bean名称设置别名,也可以给别名设置
		// 别名,如下配置:
		/*
		<bean id="car" name="car_1,car_2" class="yudaosourcecode.factorybean.CarFactoryBean">
        <property name="carInfo" value="超级跑车,400,2000000"/>
	    </bean>
	    <alias name="car_1" alias="car_1_1"/>
		*/
		// 则会有"car_1_1->car_1",”car_1->car“的映射,当通过
		// car_1_1获取时就会经过两次转换
		resolvedName = this.aliasMap.get(canonicalName);
		if (resolvedName != null) {
			canonicalName = resolvedName;
		}
	}
	while (resolvedName != null);
	// 返回标准bean名称
	return canonicalName;
}

2.2:getObjectForBeanInstance

该处是bean为单例bean时执行的逻辑,处理FactoryBean相关的内容,源码如下:

org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
			@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
	...snip...
	// <2021-03-14 11:34>
	Object sharedInstance = getSingleton(beanName);
	if (sharedInstance != null && args == null) {
		if (logger.isTraceEnabled()) {
			// 根据是否正在创建中,打印不同的日志信息
			if (isSingletonCurrentlyInCreation(beanName)) {
				logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
						"' that is not fully initialized yet - a consequence of a circular reference");
			}
			else {
				logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
			}
		}
		// <2021-03-14 15:23>
		bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
	}
	...snip...
	return (T) bean;
}

<2021-03-14 11:34>处是从单例缓存中获取bean,具体参考2.2.1:从单例缓存中获取bean,<2021-03-14 15:23>是处理FactoryBean相关逻辑,具体参考2.2.2:单例bean处理工厂bean逻辑

2.2.1:从单例缓存中获取bean

源码:

org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String)
public Object getSingleton(String beanName) {
	return getSingleton(beanName, true);
}

继续:

org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean)
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
	// <2021-03-14 14:26>
	Object singletonObject = this.singletonObjects.get(beanName);
	// <2021-03-14 14:53>
	if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
		synchronized (this.singletonObjects) {
			// <2021-03-14 15:06>
			// 从早期单例对象集合中获取
			singletonObject = this.earlySingletonObjects.get(beanName);
			// 如果是从早期对象对象map中也没有获取,并且允许提前创建
			if (singletonObject == null && allowEarlyReference) {
				// 根据bean名称获取用于单例bean创建的对象ObjectFactory
				ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
				// 如果是获取到对应单例工厂类,则创建单例对象
				if (singletonFactory != null) {
					singletonObject = singletonFactory.getObject();
					// 存放到早期单例对象map中
					this.earlySingletonObjects.put(beanName, singletonObject);
					// 从单例工厂中移除
					this.singletonFactories.remove(beanName);
				}
			}
		}
	}
	return singletonObject;
}

<2021-03-14 14:26>处代码是从单例缓存中获取对象,缓存如下:

/** beanName->object的单例缓存map */
private final Map<String, Object> singletonObjects 
	= new ConcurrentHashMap<>(256);

<2021-03-14 14:53>处如果是没有获取到且正在创建中,其中isSingletonCurrentlyInCreation源码如下:

org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#isSingletonCurrentlyInCreation
public boolean isSingletonCurrentlyInCreation(String beanName) {
	// private final Set<String> singletonsCurrentlyInCreation 
	// = Collections.newSetFromMap(new ConcurrentHashMap<>(16));
	// 如果是在集合中包含则说明是正在创建中,在第一次getBean处理过程中会放到集合中
	return this.singletonsCurrentlyInCreation.contains(beanName);
}

<2021-03-14 15:06>earlySingletonObjects定义如下:

// beanName->instance 的map,不过存储的是早期bean实例,用来辅助解决单例
// bean的循环依赖问题
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
2.2.2:单例bean处理工厂bean逻辑

源码:

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#getObjectForBeanInstance
protected Object getObjectForBeanInstance(
			Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
	// 从threadlocal中获取当前正在创建的bean
	String currentlyCreatedBean = this.currentlyCreatedBean.get();
	// 这里可以认为是false
	if (currentlyCreatedBean != null) {
		registerDependentBean(beanName, currentlyCreatedBean);
	}
	// <2021-03-14 15:40>
	return super.getObjectForBeanInstance(beanInstance, name, beanName, mbd);
}

<2021-03-14 15:40>处调用父类处理工厂bean逻辑,源码:

org.springframework.beans.factory.support.AbstractBeanFactory#getObjectForBeanInstance
protected Object getObjectForBeanInstance(
			Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {

	// isFactoryDereference方法判断是否以&开头,是则是获取工厂bean本身
	// 而非工厂bean生产的对象,即getObject方法返回的对象
	if (BeanFactoryUtils.isFactoryDereference(name)) {
		// NullBean是spring定义的用来代表null对象的,如果是则直接返回
		if (beanInstance instanceof NullBean) {
			return beanInstance;
		}
		// 如果不是FactoryBean类型的,则抛出BeanIsNotAFactoryBean
		// 异常
		if (!(beanInstance instanceof FactoryBean)) {
			throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
		}
	}

	// 如果不是FactoryBean类型,或者bean名称直接以&开头,则直接返回
	// 实例,其中以&开头说明调用者就是希望获取工厂bean本身
	if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
		return beanInstance;
	}

	Object object = null;
	// 如果bean定义为空,则从工厂bean缓存map中获取
	if (mbd == null) {
		object = getCachedObjectForFactoryBean(beanName);
	}
	// 如果从工厂bean缓存map中也没有获取
	if (object == null) {
		// 执行到这里就说明一定是BeanFactory了,进行强转
		FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
		// 如果是bean定义为空,则从bean定义的缓存map中通过bean名称获取bean定义
		if (mbd == null && containsBeanDefinition(beanName)) {
			// 从bean定义的缓存map中获取bean定义
			mbd = getMergedLocalBeanDefinition(beanName);
		}
		// 是否为用户自定义bd,可以认为是false
		boolean synthetic = (mbd != null && mbd.isSynthetic());
		// <2021-03-14 16:24>,从工厂bean中获取目标bean
		object = getObjectFromFactoryBean(factory, beanName, !synthetic);
	}
	return object;
}

<2021-03-14 16:24>就是当为工厂bean时通过工厂bean获取对象的逻辑了,源码如下:

org.springframework.beans.factory.support.FactoryBeanRegistrySupport#getObjectFromFactoryBean
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
	// factory.isSingleton()判断工厂bean是否为单例的,如果没有设置其和
	// 普通的bean一样默认也是单例的
	// containsSingleton(beanName)判断单例缓存map中是否包含,一般是包含的
	if (factory.isSingleton() && containsSingleton(beanName)) {
		// 上锁
		synchronized (getSingletonMutex()) {
			// factoryBeanObjectCache是一个工厂bean名称到其生产的bean的map缓存,首次一般为null,第一次调用getObject后会放进来作为缓存
			Object object = this.factoryBeanObjectCache.get(beanName);
			// 如果为空,则通过工厂bean获取
			if (object == null) {
				// <2021-03-14 16:32> 从工厂bean对象获取目标对象
				object = doGetObjectFromFactoryBean(factory, beanName);
				// 又是缓存获取,可以认为是null
				Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
				// 可以认为进else
				if (alreadyThere != null) {
					object = alreadyThere;
				}
				else {
					// 如果是需要后置处理
					if (shouldPostProcess) {
						// 如果单例bean正在创建中,直接返回,而不存储???应该是防止单例bean重复处理吧
						if (isSingletonCurrentlyInCreation(beanName)) {
							// Temporarily return non-post-processed object, not storing it yet..
							return object;
						}
						// <2021-03-14 16:53>标记为该单例bean创建中
						beforeSingletonCreation(beanName);
						try {
							// <2021-03-14 16:56>应用bean的后置处理器
							object = postProcessObjectFromFactoryBean(object, beanName);
						}
						catch (Throwable ex) {
							throw new BeanCreationException(beanName,
									"Post-processing of FactoryBean's singleton object failed", ex);
						}
						finally {
							// 从正在创建代理缓存中remove
							afterSingletonCreation(beanName);
						}
					}
					// 如果在单例中包含,则放到bean工厂名称->实际对象的map缓存中,则下次再获取时就可以直接使用缓存了
					if (containsSingleton(beanName)) {
						this.factoryBeanObjectCache.put(beanName, object);
					}
				}
			}
			// 返回
			return object;
		}
	}
	// 非单例
	else {
		// 同<2021-03-14 16:32>,但是因为不是单例,就每次重新获取了
		Object object = doGetObjectFromFactoryBean(factory, beanName);
		// 需要后置处理
		if (shouldPostProcess) {
			try {
				// 同<2021-03-14 16:56>
				object = postProcessObjectFromFactoryBean(object, beanName);
			}
			catch (Throwable ex) {
				throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
			}
		}
		return object;
	}
}

<2021-03-14 16:32>处是从工厂bean中获取目标bean,具体参考2.2.3:从工厂bean中获取目标bean,<2021-03-14 16:53>处为标记bean为正在创建中,源码:

org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#beforeSingletonCreation
protected void beforeSingletonCreation(String beanName) {
	if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
		throw new BeanCurrentlyInCreationException(beanName);
	}
}

<2021-03-14 16:56>处是应用bean的后置处理器,具体参考2.2.4:应用bean的后置处理器,关于后置bean处理器的简单用法可以参考spring的BeanPostProcessor分析

2.2.3:从工厂bean中获取目标bean

源码:

org.springframework.beans.factory.support.FactoryBeanRegistrySupport#doGetObjectFromFactoryBean
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((PrivilegedExceptionAction<Object>) factory::getObject, acc);
			}
			catch (PrivilegedActionException pae) {
				throw pae.getException();
			}
		}
		else {
			// 调用工厂bean的getObject方法获取目标对象
			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);
	}

	// 没有获取到
	if (object == null) {
		// 当前工厂bean正在创建中,则抛出异常
		if (isSingletonCurrentlyInCreation(beanName)) {
			throw new BeanCurrentlyInCreationException(
					beanName, "FactoryBean which is currently in creation returned null from getObject");
		}
		// 到这就说明通过getObject方法返回的对象为null,则使用定义的NullBean
		object = new NullBean();
	}
	// 返回目标对象
	return object;
}
2.2.4:应用bean的后置处理器

关于后置bean处理器的用法可以参考spring的BeanPostProcessor分析
。源码:

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
			throws BeansException {

	Object result = existingBean;
	// 获取所有的后置bean处理器,调用其postProcessAfterInnitialization方法进行后置处理
	for (BeanPostProcessor processor : getBeanPostProcessors()) {
		Object current = processor.postProcessAfterInitialization(result, beanName);
		if (current == null) {
			return result;
		}
		result = current;
	}
	return result;
}

2.3:prototype的bean循环依赖检测

如果是执行到这里,就是说明是代码Object sharedInstance = getSingleton(beanName);获取到的sharedInstance是null,此时就有以下两种情况:

1:bean是单例的但是还没有初始化
2:bean是原型的

而本处处理的就是2:bean是原型的的情况下存在循环依赖的情况。
关于spring bean的循环依赖可以参考spring循环依赖分析
。源码如下:

org.springframework.beans.factory.support.AbstractBeanFactory#isPrototypeCurrentlyInCreation
protected boolean isPrototypeCurrentlyInCreation(String beanName) {
	// this.prototypesCurrentlyInCreation是一个threadlocal
	// 存储的是正在创建beanname或者是beanname的set集合
	Object curVal = this.prototypesCurrentlyInCreation.get();
	// 在当前threadlocal存储有值的情况下
	// 1:如果是存储的值和bean名称相等,或者是
	// 2:存储的是正在创建的原型bean名称的set集合,且该集合中包含当前bean名称
	// 时,就是原型bean正在创建。
	return (curVal != null &&
			(curVal.equals(beanName) || (curVal instanceof Set && ((Set<?>) curVal).contains(beanName))));
}

2.4:从父容器中查找bean定义

到这里,要获取的bean到底是单例的还是原型的依然是不确定的,唯一确定的是肯定不是存在循环依赖的原型bean,因为如果是在2.3:prototype的bean循环依赖检测中已经异常了,不会执行到这里,看下源码:

org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
			@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
	...snip...
	else {
		...snip...
		// 获取父容器
		BeanFactory parentBeanFactory = getParentBeanFactory();
		// 如果是父容器不为空,并且当前容器的beandefinitionmap不存在
		// beanname对应的GenericBeanDefinition,则尝试从父容器中获取
		if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
			// <2021-03-16 16:13>
			// 获取原始bean名称,主要是处理别名
			String nameToLookup = originalBeanName(name);
			// 以下是根据父容器不同的类型和参数的不同调用父容器
			// 不同的方法,其实就是委托
			if (parentBeanFactory instanceof AbstractBeanFactory) { // 如果是AbstractBeanFactory类型
				return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
						nameToLookup, requiredType, args, typeCheckOnly);
			}
			else if (args != null) { // 如果有args参数
				// Delegation to parent with explicit args.
				return (T) parentBeanFactory.getBean(nameToLookup, args);
			}
			else if (requiredType != null) { // 如果有requiredType
				// No args -> delegate to standard getBean method.
				return parentBeanFactory.getBean(nameToLookup, requiredType);
			}
			else { // 否则调用只有beanName参数的方法
				return (T) parentBeanFactory.getBean(nameToLookup);
			}
		}
		...snip...
	}
	return (T) bean;
}

<2021-03-16 16:13>处是获取原始bean名称,即在beandefinitionmap中注册的名称,源码如下:

org.springframework.beans.factory.support.AbstractBeanFactory#originalBeanName
protected String originalBeanName(String name) {
	// 获取标准bean名称,在“2.1:transformedBeanName转换bean名称”
	// 中已经分析过了
	String beanName = transformedBeanName(name);
	// 因为在transformedBeanName方法中如果以&开头的会去掉&,
	// 这里需要加回去
	if (name.startsWith(FACTORY_BEAN_PREFIX)) {
		beanName = FACTORY_BEAN_PREFIX + beanName;
	}
	return beanName;
}

2.5:markBeanAsCreated

该处是如果不仅仅是类型检查时,标记bean为已创建状态,源码如下:

org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
			@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
		...snip...
		// 不是仅类型检查
		if (!typeCheckOnly) {
			// <2021-03-16 18:06>
			markBeanAsCreated(beanName);
		}
		...snip...
	return (T) bean;
}

<2021-03-16 18:06>处是标记bean为已创建,源码如下:

org.springframework.beans.factory.support.AbstractBeanFactory#markBeanAsCreated
protected void markBeanAsCreated(String beanName) {
	// alreadyCreated是一个set集合,如果不存在说明你还没有创建
	if (!this.alreadyCreated.contains(beanName)) {
		// 获取同步锁
		synchronized (this.mergedBeanDefinitions) {
			// <2021-03-16 18:09>
			// DCL双重检查
			if (!this.alreadyCreated.contains(beanName)) {
				// 清空beanName对应的mergedBeanDefinition信息
				/*
				protected void clearMergedBeanDefinition(String beanName) {
				    this.mergedBeanDefinitions.remove(beanName);
				}
				*/
				clearMergedBeanDefinition(beanName);
				// 添加beanName到已创建的set集合中
				this.alreadyCreated.add(beanName);
			}
		}
	}
}

<2021-03-16 18:09>是DCL双重检查,防止获取锁后检查状态发生变化,具体可以参考基于DCL的单例懒汉模式实现

2.6:通过bean名称获取bean定义

如果是执行到这里,就说明,在当前容器的beandenitionmap中存在beanName对应的BeanDefinition对象,源码如下:

org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean 
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
			@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
	...snip...
	// <2021-03-17 09:16>
	// 合并parent的属性如果存在的话
	final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
	// <2021-03-17 09:17>
	checkMergedBeanDefinition(mbd, beanName, args);
	...snip...
}

<2021-03-17 09:16>处是合并parent中的抽象bean的公共属性,关于抽象bean可以参考spring配置中的abstract,parent分析
,具体参考2.6.1:getMergedLocalBeanDefinition<2021-03-17 09:17>处参考2.6.2:checkMergedBeanDefinition

2.6.1:getMergedLocalBeanDefinition

源码如下:

org.springframework.beans.factory.support.AbstractBeanFactory#getMergedLocalBeanDefinition
protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
	// 先从合并父bean公共属性后的mergedBeanDefinitions的map中获取看是否已经存在(因为可能存在其他线程已经合并完毕的情况)
	RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
	// 如果是存在则直接返回
	if (mbd != null) {
		return mbd;
	}
	// <2021-03-17 09:21>
	// getBeanDefinition(beanName)是从beandefinitionmap中获取bean定义
	return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
}

<2021-03-17 09:21>处源码如下:

org.springframework.beans.factory.support.AbstractBeanFactory#getMergedBeanDefinition(java.lang.String, org.springframework.beans.factory.config.BeanDefinition)
protected RootBeanDefinition getMergedBeanDefinition(String beanName, BeanDefinition bd)
			throws BeanDefinitionStoreException {
	// 该方法会解析父抽象bean并将相关信息合并到当前beandefinition
	// 最终定义一个RootBeanDefinition,详细不再解析
	return getMergedBeanDefinition(beanName, bd, null);
}
2.6.2:checkMergedBeanDefinition
org.springframework.beans.factory.support.AbstractBeanFactory#checkMergedBeanDefinition
protected void checkMergedBeanDefinition(RootBeanDefinition mbd, String beanName, @Nullable Object[] args)
			throws BeanDefinitionStoreException {
// 检测bean如果是抽象的则直接异常,因为抽象bean不能实例化
if (mbd.isAbstract()) {
		throw new BeanIsAbstractException(beanName);
	}
}

2.7:依赖bean的处理

这里处理的是depend-on的情况,详细可以参考spring如何控制bean的初始化顺序
。源码如下:

org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
			@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
    ...snip...
    // 获取通过depend-on配置的依赖bean
	String[] dependsOn = mbd.getDependsOn();
	if (dependsOn != null) {
		// 循环所有的依赖bean
		for (String dep : dependsOn) {
			// 当前beanName depend-on dep
			// 如果时dep也depend-on beanName,则存在循环depend-on
			// 直接异常
			if (isDependent(beanName, dep)) {
				throw new BeanCreationException(mbd.getResourceDescription(), beanName,
						"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
			}
			// <2021-03-17 17:43>
			registerDependentBean(dep, beanName);
			try {
				// 加载被depend-on的bean
				getBean(dep);
			}
			catch (NoSuchBeanDefinitionException ex) {
				throw new BeanCreationException(mbd.getResourceDescription(), beanName,
						"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
			}
		}
	}
	...snip...
}

<2021-03-17 17:43>是注册依赖关系,源码如下:

org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#registerDependentBean
public void registerDependentBean(String beanName, String dependentBeanName) {
	// 获取标准名称
	String canonicalName = canonicalName(beanName);

	synchronized (this.dependentBeanMap) {
		// 如果是存在key为canonicalName的数据,则返回
		// 否则put以canonicalName为key,以new LinkedHashSet<>(8)
		// 为value的数据,并返回new LinkedHashSet<>(8)
		// dependentBeanMap存储的是"被依赖bean->依赖自己的bean集合"
		Set<String> dependentBeans =
				this.dependentBeanMap.computeIfAbsent(canonicalName, k -> new LinkedHashSet<>(8));
		// 添加依赖的bean名称
		if (!dependentBeans.add(dependentBeanName)) {
			return;
		}
	}

	synchronized (this.dependenciesForBeanMap) {
		// 同上逻辑
		// dependenciesForBeanMap存储的是"bean->自己依赖的bean集合"
		Set<String> dependenciesForBean =
				this.dependenciesForBeanMap.computeIfAbsent(dependentBeanName, k -> new LinkedHashSet<>(8));
		// 添加当前存在依赖的bean到集合中
		dependenciesForBean.add(canonicalName);
	}
}

2.8:不同作用域bean的初始化

所有的准备工作,检测工作等做完之后,到这里就是要开始bean的初始化了,源码如下:

org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
			@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
	...snip...
	// 根据bean的不同的scope来进行初始化
	if (mbd.isSingleton()) { // scope为singleton的初始化
		// <2021-03-18 11:25>,创建单例bean
		sharedInstance = getSingleton(beanName, () -> {
			try {
				return createBean(beanName, mbd, args);
			}
			catch (BeansException ex) {
				// 可能存在单例循环依赖场景bean已经存在的情况
				// 所以这里需要销毁
				destroySingleton(beanName);
				throw ex;
			}
		});
		// 该处是处理FactoryBean相关内容,在"2.2:getObjectForBeanInstance"已经进行了分析
		bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
	}
	// <2021-03-18 13:41> 原型模式创建bean
	else if (mbd.isPrototype()) { // scope为prototype的初始化
		// It's a prototype -> create a new instance.
		Object prototypeInstance = null;
		try {
			beforePrototypeCreation(beanName);
			prototypeInstance = createBean(beanName, mbd, args);
		}
		finally {
			afterPrototypeCreation(beanName);
		}
		// 该处是处理FactoryBean相关内容,在"2.2:getObjectForBeanInstance"已经进行了分析
		bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
	}
	// <2021-03-18 14:26>
	else { // 其他作用于,如web环境中的request,session等
		String scopeName = mbd.getScope();
		final Scope scope = this.scopes.get(scopeName);
		if (scope == null) {
			throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
		}
		try {
			Object scopedInstance = scope.get(beanName, () -> {
				beforePrototypeCreation(beanName);
				try {
					return createBean(beanName, mbd, args);
				}
				finally {
					afterPrototypeCreation(beanName);
				}
			});
			bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
		}
		catch (IllegalStateException ex) {
			throw new BeanCreationException(beanName,
					"Scope '" + scopeName + "' is not active for the current thread; consider " +
					"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
					ex);
		}
	}
	...snip...
}

<2021-03-18 11:25>处是创建单例bean,具体参考2.8.1:单例map缓存无时创建单例bean<2021-03-18 13:41>处参考2.8.3:创建原型bean<2021-03-18 14:26>处参考2.8.4:其他scope bean的创建

2.8.1:单例map缓存无时创建单例bean

源码如下:

org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, org.springframework.beans.factory.ObjectFactory<?>)
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
	// 断言判断
	Assert.notNull(beanName, "Bean name must not be null");
	// 使用单例缓存map上锁,防止多线程操作出现问题
	synchronized (this.singletonObjects) {
		// 因为当执行到这里时其他线程可能已经初始化了bean,
		// 所以这里必须检查一下,保证"singleton"语义的准确性
		Object singletonObject = this.singletonObjects.get(beanName);
		// 为空才创建,DCL双重检查锁
		if (singletonObject == null) {
			if (this.singletonsCurrentlyInDestruction) {
				throw new BeanCreationNotAllowedException(beanName,
						"Singleton bean creation not allowed while singletons of this factory are in destruction " +
						"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
			}
			if (logger.isDebugEnabled()) {
				logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
			}
			// <2021-03-18 12:57>
			beforeSingletonCreation(beanName);
			// 标记
			boolean newSingleton = false;
			boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
			if (recordSuppressedExceptions) {
				this.suppressedExceptions = new LinkedHashSet<>();
			}
			try {
				// <2021-03-18 13:03>,调用singletonFactory入参的getObject方法
				// 创建单例bean
				singletonObject = singletonFactory.getObject();
				// 创建单例bean完毕,修改标记
				newSingleton = true;
			}
			catch (IllegalStateException ex) {
				singletonObject = this.singletonObjects.get(beanName);
				if (singletonObject == null) {
					throw ex;
				}
			}
			catch (BeanCreationException ex) {
				if (recordSuppressedExceptions) {
					for (Exception suppressedException : this.suppressedExceptions) {
						ex.addRelatedCause(suppressedException);
					}
				}
				throw ex;
			}
			finally {
				if (recordSuppressedExceptions) {
					this.suppressedExceptions = null;
				}
				// <2021-03-18 13:06>
				afterSingletonCreation(beanName);
			}
			// <2021-03-18 13:14>
			if (newSingleton) {
				addSingleton(beanName, singletonObject);
			}
		}
		return singletonObject;
	}
}

<2021-03-18 12:57>处代码是创建单例bean前做一些前置的准备工作,代码如下:

org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#beforeSingletonCreation
protected void beforeSingletonCreation(String beanName) {
	// 添加到当前正在创建的单例bean的set集合中,如果是添加不成功
	// 则说明已经存在了,抛出BeanCurrentlyInCreatetion异常
	if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
		throw new BeanCurrentlyInCreationException(beanName);
	}
}

<2021-03-18 13:03>处调用的是入参中的ObjectFactory参数的实现类的getObject方法具体参看2.8.2:通过ObjectFactory的getObject创建单例<2021-03-18 13:06>处是创建单例bean后处理,源码如下:

org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#afterSingletonCreation
protected void afterSingletonCreation(String beanName) {
	// 从正在创建的单例bean的set集合中删除,如果是删除失败
	// 则说明bean当前不在创建中,抛出IllegalStateException异常
	if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
		throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
	}
}

<2021-03-18 13:14>成功创建单例bean后记录bean的已创建的状态,源码如下:

org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#addSingleton
protected void addSingleton(String beanName, Object singletonObject) {
	synchronized (this.singletonObjects) {
		// 添加到单例bean的map缓存中
		this.singletonObjects.put(beanName, singletonObject);
		// 删除beanName和对应的ObjectFactory,其中ObjectFactory
		// 是用于创建单例bean的工厂
		this.singletonFactories.remove(beanName);
		// 删除beanName->早期bean的对应关系
		// 该map是解决单例bean循环依赖的关键
		this.earlySingletonObjects.remove(beanName);
		// 添加beanName到已注册的单例bean的set集合中
		this.registeredSingletons.add(beanName);
	}
}
2.8.2:通过ObjectFactory的getObject创建单例

具体参考3:bean具体创建过程

2.8.3:创建原型bean

再贴下源码:

else if (mbd.isPrototype()) { // scope为prototype的初始化
	// It's a prototype -> create a new instance.
	Object prototypeInstance = null;
	try {
		// <2021-03-18 13:43>
		beforePrototypeCreation(beanName);
		// <2021-03-18 13:52>
		prototypeInstance = createBean(beanName, mbd, args);
	}
	finally {
		// <2021-03-18 13:53>
		afterPrototypeCreation(beanName);
	}
	// 该处是处理FactoryBean相关内容,在"2.2:getObjectForBeanInstance"已经进行了分析
	bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}

<2021-03-18 13:43>处是创建原型bean做一些前置准备工作,源码如下:

org.springframework.beans.factory.support.AbstractBeanFactory#beforePrototypeCreation
protected void beforePrototypeCreation(String beanName) {
	// 从threadlocal中获取值
	Object curVal = this.prototypesCurrentlyInCreation.get();
	// 如果是没有值,则将当前的设置进去
	if (curVal == null) {
		this.prototypesCurrentlyInCreation.set(beanName);
	}
	// 如果是已经存在,并且类型是String则再创建set将已存在的
	// 和自己放到set集合中,然后重新将set集合放到threadlocal中
	else if (curVal instanceof String) {
		Set<String> beanNameSet = new HashSet<>(2);
		beanNameSet.add((String) curVal);
		beanNameSet.add(beanName);
		this.prototypesCurrentlyInCreation.set(beanNameSet);
	}
	// 到这里说明已经是set了,直接add即可
	else {
		Set<String> beanNameSet = (Set<String>) curVal;
		beanNameSet.add(beanName);
	}
}

<2021-03-18 13:52>处比较重要,是创建原型bean了,我现在也没详细看,等看了在分析。<2021-03-18 13:53>是原型bean创建后的处理,源码如下:

org.springframework.beans.factory.support.AbstractBeanFactory#afterPrototypeCreation
protected void afterPrototypeCreation(String beanName) {
	// 从threadlocal中获取值
	Object curVal = this.prototypesCurrentlyInCreation.get();
	// 如果是String则直接从threadlocal中删除
	if (curVal instanceof String) {
		this.prototypesCurrentlyInCreation.remove();
	}
	// 如果是set则强转set,然后从set中删除
	else if (curVal instanceof Set) {
		Set<String> beanNameSet = (Set<String>) curVal;
		beanNameSet.remove(beanName);
		// 如果是set已经空了,则从threadlocal中删除
		if (beanNameSet.isEmpty()) {
			this.prototypesCurrentlyInCreation.remove();
		}
	}
}
2.8.4:其他scope bean的创建

源码如下:

// 获取scope的名称
String scopeName = mbd.getScope();
// 根据名称获取scope实例
final Scope scope = this.scopes.get(scopeName);
if (scope == null) {
	throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
	// 通过scope获取实例
	Object scopedInstance = scope.get(beanName, () -> {
		beforePrototypeCreation(beanName);
		try {
			return createBean(beanName, mbd, args);
		}
		finally {
			afterPrototypeCreation(beanName);
		}
	});
	// 进行FactoryBean相关处理
	bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
	throw new BeanCreationException(beanName,
			"Scope '" + scopeName + "' is not active for the current thread; consider " +
			"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
			ex);
}

2.9:强制类型转换

当requiredType参数不为空,是会执行该处逻辑进行强转,对应的getBean的重载版本如下:

<T> T getBean(String name, Class<T> requiredType) throws BeansException;

强转源码如下:

if (requiredType != null && !requiredType.isInstance(bean)) {
	try {
		T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
		if (convertedBean == null) {
			throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
		}
		return convertedBean;
	}
	catch (TypeMismatchException ex) {
		if (logger.isTraceEnabled()) {
			logger.trace("Failed to convert bean '" + name + "' to required type '" +
					ClassUtils.getQualifiedName(requiredType) + "'", ex);
		}
		throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
	}
}

3:bean具体创建过程

鉴于本文已经比较长,我们单起一篇文章来分析这个过程,具体参考bean具体创建过程分析

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值