Bean loading (2)
The previous article mainly gave a brief introduction to the getBean method, the role of FactoryBean, and how to get beans from the cache. This article continues to explain the bean loading process.
Get an object from an instance of a bean
In the getBean method, getObjectForBeanInstance()
is a common method, whether to get the bean from the cache or load the bean according to different scope strategies. All in all, after we get the bean instance, the first step is to call this method to check the correctness. In fact, it is to check whether the current bean is a bean of type FactoryBean, and if so, call the getObject() of the FactoryBean instance as the return value.
It should be noted that whether the bean obtained in the cache or the bean loaded through the scope strategy is the original bean state , what we need is the bean returned in the factory-method method defined in the factory bean, and the getObjectForBeanInstance method is to complete this work. of.
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
//如果指定的name是工厂相关以"&"为前缀,并且beanInstance又不是FactoryBean则校验不通过
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;
}
//现在我们有了这个bean实例,这个实例可能是FactoryBean,也可能是正常的bean
//如果是FactoryBean的话,我们使用它创建实例,但如果是用户想要直接获取工厂实例而不是工厂的getObject方法则需要在BeanName前加上"&"
if (!(beanInstance instanceof FactoryBean)) {
return beanInstance;
}
//加载FactoryBean
Object object = null;
if (mbd != null) {
mbd.isFactoryBean = true;
}
else {
//尝试从缓存中加载bean
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
// 执行到这里表明beanInstance一定是一个FactoryBean
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
// containsBeanDefinition检测BeanDefinitionMap中也就是在所有一键加载的类中检测是否定义beanName
if (mbd == null && containsBeanDefinition(beanName)) {
//将GenericBeanDefinition转换为RootBeanDefinition,如果指定BeanName是子bean的话同时会合并父类的属性
mbd = getMergedLocalBeanDefinition(beanName);
}
//是否是用户定义的而不是应用程序本身定义的
boolean synthetic = (mbd != null && mbd.isSynthetic());
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
Let's take a look at what getObjectForBeanInstance mainly does:
- Verify FactoryBean correctness
- Do nothing for non-FactoryBeans
- Convert the bean
- The job of parsing beans from the Factory is delegated to
getObjectFromFactoryBean
.
Most of this code is auxiliary code, and the real core code is delegated to getObjectFromFactoryBean
.
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
if (factory.isSingleton() && containsSingleton(beanName)) {
synchronized (getSingletonMutex()) {
Object object = this.factoryBeanObjectCache.get(beanName);
if (object == null) {
//重点方法 doGetObjectFromFactoryBean
object = doGetObjectFromFactoryBean(factory, beanName);
//...省略
}
else {
//重点方法 doGetObjectFromFactoryBean
Object object = doGetObjectFromFactoryBean(factory, beanName);
if (shouldPostProcess) {
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
}
}
return object;
}
}
This code is the returned bean. If it is a singleton, it needs to be guaranteed to be globally unique. Because it is a singleton, it does not need to be created repeatedly. You can use caching to improve performance.
We enter the doGetObjectFromFactoryBean
method.
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 {
//直接调用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);
}
// Do not accept a null value for a FactoryBean that's not fully
// initialized yet: Many FactoryBeans just return null then.
if (object == null) {
if (isSingletonCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(
beanName, "FactoryBean which is currently in creation returned null from getObject");
}
object = new NullBean();
}
return object;
}
In this method, we finally see the code we want to see, which is object = factory.getObject()
. We have talked about the calling method of FactoryBean before. If the bean is of type FactoryBean, when extracting the bean, it is not the factoryBean but the return value of the getObject method of the factoryBean.
get singleton
We said before that if there is no already loaded bean in the cache, you need to start the bean loading from scratch. In Spring, the overloaded method of getSingleton is used to realize the bean loading process.
getBean method:
// 实例化依赖的bean后就可以实例化mbd本身了
// 如果BeanDefinition为单例
if (mbd.isSingleton()) {
//创建Bean实例对象,并且注册给所依赖的对象
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
//从单例缓存中删除bean实例
//因为单例模式下为了解决循环依赖,可能它已经存在了,所以将其销毁
destroySingleton(beanName);
throw ex;
}
});
//如果是普通bean,直接返回,如果是FactoryBean,则返回它的getObject
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
Enter the getSingleton method:
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
//加锁
synchronized (this.singletonObjects) {
//首先检查对应的bean是否已经加载过,
Object singletonObject = this.singletonObjects.get(beanName);
//如果为空则需要进行singleton的bean初始化
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 + "'");
}
//代码(1)
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
// 通过回调方式获取bean实例。
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
catch (IllegalStateException ex) {
// Has the singleton object implicitly appeared in the meantime ->
// if yes, proceed with it since the exception indicates that state.
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;
}
//代码(2)
afterSingletonCreation(beanName);
}
if (newSingleton) {
//加入缓存 代码(3)
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
The above code uses the callback method, and does some preparation and processing operations before and after the singleton is created, and the real way to obtain the singleton bean is in the instance singletonFactory of the ObjectFactory type. Let's first look at what the getSingleton method mainly does:
- Check if the cache is already loaded
- If not loaded, record beanName as loading state
- Record the loading state before loading the singleton, code (1)
protected void beforeSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
}
The main purpose of this method is to record the loading status, this.singletonsCurrentlyInCreation.add(beanName)
record the bean currently being created in the cache, so that circular dependencies can be detected.
- get bean instance
- Call the processing method after loading the singleton, code (2)
protected void afterSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
}
}
Similar to above, only here is the loading state with the bean removed from the cache.
- Caches the bean and removes various auxiliary state recorded during the bean loading process.
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
- return processing result
Now that we have seen the logical architecture of the bean, the loading logic of the bean is defined in the singletonFactory passed in as a parameter of type ObjectFactory.
//创建Bean实例对象,并且注册给所依赖的对象
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
//从单例缓存中删除bean实例
//因为单例模式下为了解决循环依赖,可能它已经存在了,所以将其销毁
destroySingleton(beanName);
throw ex;
}
});
We enter the createBean method to continue to see.
ready to create the bean
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
if (logger.isTraceEnabled()) {
logger.trace("Creating instance of bean '" + beanName + "'");
}
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.
// 锁定class,根据设置的class属性或者根据className来解析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 {
mbdToUse.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
beanName, "Validation of method overrides failed", ex);
}
try {
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
//给BeanPostProcessors一个机会来返回代理用于替代真正的实例
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
catch (Throwable ex) {
throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
"BeanPostProcessor before instantiation of bean failed", ex);
}
try {
//代码(1)
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isTraceEnabled()) {
logger.trace("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
// A previously detected exception with proper bean creation context already,
// or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(
mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
}
}
- Parse Class according to the set class attribute or according to className
- Mark and validate the override attribute
We know that there is no configuration similar to override-methdo in Spring's configuration, so what is the role of this method?
We said before that there are lookup-method and replace-method in the Spring configuration. The loading of these two configurations is to uniformly store the configuration in the methodOverrides attribute in the BeanDefinition, and this function is actually for these two configurations.
- Apply the pre-initialization post-processor to resolve whether the specified bean has a pre-initialization short-circuit operation
- create bean
Let's take a look at the logic implementation of override attribute marking and verification
Handling override properties
Enter the prepareMethodOverrides method:
public void prepareMethodOverrides() throws BeanDefinitionValidationException {
// Check that lookup methods exist and determine their overloaded status.
if (hasMethodOverrides()) {
getMethodOverrides().getOverrides().forEach(this::prepareMethodOverride);
}
}
protected void prepareMethodOverride(MethodOverride mo) throws BeanDefinitionValidationException {
// 获取对应类中对应方法名的个数
int count = ClassUtils.getMethodCountForName(getBeanClass(), mo.getMethodName());
if (count == 0) {
throw new BeanDefinitionValidationException(
"Invalid method override: no method with name '" + mo.getMethodName() +
"' on class [" + getBeanClassName() + "]");
}
else if (count == 1) {
// Mark override as not overloaded, to avoid the overhead of arg type checking.
// 标记MethodOverride暂未被覆盖,避免参数类型检查的开销
mo.setOverloaded(false);
}
}
I just mentioned that the two configuration functions of lookup-method and replace-method are stored in the methodOverrides attribute in the BeanDefinition. The current bean generates a proxy and uses the corresponding interceptor to enhance the bean.
It should be mentioned that for method matching, if there are multiple overloaded methods in a class, they need to be matched according to the parameter type. If there is only one method in the class, set the method not to be overloaded, so that the found method can be used directly in the future, without the need for parameter matching verification of the method, and the existence of the method can also be verified in advance, so-called kill two birds with one stone .
Preprocessing of instantiation
Before calling doCreateBean, the resolveBeforeInstantiation(beanName, mbdToUse) method is also used to preprocess the properties in the BeanDefinition.
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
The focus of this code is this if condition. When the processing result is not null, it will skip the creation of subsequent beans and return the result directly. The well-known AOP function is based on this judgment.
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
Object bean = null;
//如果还没被解析过,则解析
if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
// Make sure bean class is actually resolved at this point.
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
Class<?> targetType = determineTargetType(beanName, mbd);
if (targetType != null) {
//代码(1)
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
if (bean != null) {
//代码(2)
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
}
}
mbd.beforeInstantiationResolved = (bean != null);
}
return bean;
}
The focus of this method is these two methods: applyBeanPostProcessorsBeforeInstantiation, applyBeanPostProcessorsAfterInitialization. The implementation of these two methods is very simple, that is, the postProcessBeforeInstantiation method and the postProcessAfterInitialization method of BeanPostProcessor are called to all post-processors of InstantiationAwareBeanPostProcessor type in the post-processor.
1. Post-processor application before instantiation
Called before instantiation of bean, that is, the processing before converting AbstractBeanDefinition to BeanWrapper. Give the subclass an opportunity to modify the BeanDefinition, that is, after calling this method, the bean may change, which may be the processed proxy bean, or it may be generated by cglib. It will be described in detail later, but for now just need to understand that the method of the post-processor will be called before the bean is instantiated.
protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
if (result != null) {
return result;
}
}
}
return null;
}
2. Instantiated post-processor application
Spring's rule is to ensure that the registered post-processor postProcessAfterInitialization method is applied to the bean as much as possible after the bean is initialized. If the returned bean is not empty, there is no need to go through the bean creation process.
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。