beanPostProcessor
我们先从CreateBean方法开始:
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
// Instantiate the bean.
// BeanWrapper对象包裹要被实例化的对象
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
// 创建实例化对象
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
// 得到实例化出来的对象
Object bean = instanceWrapper.getWrappedInstance();
//获取创建好的bean的Class也就是beanType
Class<?> beanType = instanceWrapper.getWrappedClass();
//判断当前创建出来的bean是否为null
if (beanType != NullBean.class) {
//不为null的话就将当前的beanType赋值给RootBeanDefinition
mbd.resolvedTargetType = beanType;
}
// Allow post-processors to modify the merged bean definition. 允许后处理器修改合并的 Bean 定义。
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
// 缓存所有的@AutoWired注解的Member(filed method)
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
} catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
// 急切地缓存单例,以便能够解析循环引用,即使由生命周期接口(如 BeanFactoryAware)触发也是如此。
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references");
}
// 加入到三级缓存中
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance. 初始化 Bean 实例。
Object exposedObject = bean;
try {
// 属性填充
populateBean(beanName, mbd, instanceWrapper);
// 执行Aop代理
exposedObject = initializeBean(beanName, exposedObject, mbd);
} catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
} else {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
} else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(beanName, "Bean with name '" + beanName + "' has been injected into other beans [" + StringUtils.collectionToCommaDelimitedString(actualDependentBeans) + "] in its raw version as part of a circular reference, but has eventually been " + "wrapped. This means that said other beans do not use the final version of the " + "bean. This is often the result of over-eager type matching - consider using " + "'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
// Register bean as disposable.
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
} catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
进入到createBeanInstance方法,该方法就是完成对一个Bean的target对象的实例化,这里涉及到推断构造器的知识我们跳过,总之这里就是会获取到一个被创建好的对象。
if (instanceWrapper == null) {
// 创建实例化对象
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
然后,下面会获取到当前的实例化出来的Bean对象,和实例化对象的类型,并且判断当前对象的类型是否为NullBean.class类型。
Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
如果不是就会进入到同步的流程:
// Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
// 第三次调用后置处理器,通过后置处理器来应用咱们合并之后的BeanDefintion。
// 应用BeanDefintion的什么?BeanDefiniton中的需要被注入的属性。
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
} catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}
为了便于理解上述代码解释的:应用BeanDefintion的什么?BeanDefiniton中的需要被注入的属性。我们使用代码例子来说明情况:
比如现在有 A,Y,Z三个类:
@Component
public class Z {
}
@Component
public class Y {
}
@Component
public class A {
Y y;
@Autowired
Z z;
}
可以看到在A类中通过@Autowired注解完成了注入了,那么对应的在:
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
方法中,便会被扫描出来,并且存入到一个集合中,但是切记这里只是被扫描出来,并不会进行注入的动作。
直到完成属性注入populateBean方法结束后才会完成该Bean的属性注入动作。
下面是applyMergedBeanDefinitionPostProcessors方法的内容:
protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof MergedBeanDefinitionPostProcessor) {
MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
}
}
}
我们点进postProcessMergedBeanDefinition方法中,会发现他是一个接口:
/**
* Post-process the given merged bean definition for the specified bean.
* @param beanDefinition the merged bean definition for the bean
* @param beanType the actual type of the managed bean instance
* @param beanName the name of the bean
* @see AbstractAutowireCapableBeanFactory#applyMergedBeanDefinitionPostProcessors
*/
void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName);
但是不要慌,咱们选择AutowiredAnnotationBeanPostProcessor实现中看。
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
metadata.checkConfigMembers(beanDefinition);
}
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
metadata.checkConfigMembers(beanDefinition);
}
看到在AutowiredAnnotationBeanPostProcessor的实现中,会有一个findAutowiringMetadate方法,该方法的作用就是和名字一样:找出所有添加了@Autowrite注解的元数据。
最后返回出来的是一个叫InjectionMetadata的对象,由于一整个类的篇幅过长,咱们就只看较为关键的地方:
private final Class<?> targetClass;
private final Collection<InjectedElement> injectedElements;
@Nullable
private volatile Set<InjectedElement> checkedElements;
- targetClass:当前被注入的对象的类型。
- injectedElements:存储当前bean需要被注入的元素集合。
- checkedElements:存储当前bean需要被注入时需要校验的元素集合。
但是话说他在applyMergedBeanDefinitionPostProcessors方法中的postProcessMergedBeanDefinition方法中的findAutowiringMetadata方法中已经找了一遍但是spring还是会在属性填充的方法中再次的找一遍需要被注入到当前对象中的被注入的对象的集合。我们可以来看:
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return;
}
}
pvs = pvsToUse;
}
}
在spring开始在属性填充中处理@Autowrite注解的时候调用:
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
进入到实现类AutowriteAnnotationBeanPostProcessor中:
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
try {
metadata.inject(bean, beanName, pvs);
}
catch (BeanCreationException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
}
return pvs;
}
我们看到在方法的开始就调用了:
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
完成对需要被属性填充的二次查找。
private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
// Fall back to class name as cache key, for backwards compatibility with custom callers.
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
// Quick check on the concurrent map first, with minimal locking.
InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
synchronized (this.injectionMetadataCache) {
metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
if (metadata != null) {
metadata.clear(pvs);
}
metadata = buildAutowiringMetadata(clazz);
this.injectionMetadataCache.put(cacheKey, metadata);
}
}
}
return metadata;
}
在该方法中我们会发现,他会先在applyMergedBeanDefinitionPostProcessors方法中找到的injectionMetadataCache集合进行判断,是否能够get出来,也就是说在applyMergedBeanDefinitionPostProcessors中是否找到当前我在属性填充的时候扫描出来的被注入属性。否则就会重新的去找对应的对应的被注入属性,并且构建一个被注入属性对象。
好了到这里我们不继续往下深究,先回头来看applyMergedBeanDefinitionPostProcessors方法的目标:
首先,该方法完成合并后的beanDefiniton的被注入的元数据的寻找,并且存入一个集合中,但是!这里并不只是只能做这点事情,这里最重要的作用是拿来让程序可以进行扩展使用的。
并且深入理解一下 applyMergedBeanDefinitionPostProcessors 方法的话你就会发现,该方法的命名为什么 apply Merged ,都知道这两个单词的意思是应用、合并的含义,但是 spring 在这里的用以和表面上理解的不太一样,怎么说这个事。首先咱们都知道在 spring 中有类似于 Scan...、Annotation...、General......、Root....等等的 BeanDefintion 的包装类,但是他们都只是 BeanDefintion 其中的一种表达方式而已,那么不管你去看哪里正对于 beanDefiniton 最终的描述或者说是定义都是使用 RootBeanDefintion 来完成的,所以说这里也可以说 spring 的作者偷懒了,我们都知道在 spring 中有 BeanDefiniton 是有一个合并的过程,合并完成之后会有一个 MergeBeanDefinition 来描述合并完成后的 BeanDefinition,但是 spring 没有这么做,不管你最后怎么样,spring 我都会采用一个叫做 RootBeanDefinition 的包装类,来完整的描述出当前 BeanDefiniton 的全部信息。
下面咱们来看一段简单代码来理解上述的文字在讲什么东西:
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
RootBeanDefinition rb = new RootBeanDefinition();
rb.setBeanClass(B.class);
rb.getPropertyValues().setPropertyValueAt(new PropertyValue("tt", new B()), 2);
context.registerBeanDefinition("b", rb);
GenericBeanDefinition gb = new GenericBeanDefinition();
gb.setBeanClass(A.class);
gb.setParentName("b");
context.registerBeanDefinition("a", gb);
context.refresh();
}
比如说我们现在有一个GenericBeanDefinition 类型的 beanDefintion,如果这个时候没有设置他的父 BD,那么这个时候将他注入进行 context 中是没有问题的,但是如果说我现在为 GenericBeanDefinition 设置一个父 BD 呢?并且我在父 BD 中设置了一个PropertyValue,那么不进行合并是不是就拿不到父 BD 的相关信息呀!
ok,到这里是不是会一个疑问,那说合并 spring 到底是在什么时候开始合并的呢?
对于 spring 来说,所有的动作都可以分为 解析、创建,好的这里直接给出答案,是在refresh 方法中的finishBeanFactoryInitialization 方法中的:beanFactory.preInstantiateSingletons();方法中“:
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...
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
FactoryBean<?> factory = (FactoryBean<?>) bean;
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());
}
if (isEagerInit) {
getBean(beanName);
}
}
} else {
getBean(beanName);
}
}
}
// Trigger post-initialization callback for all applicable beans... 触发所有适用 bean 的初始化后回调...
for (String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton) {
SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(
(PrivilegedAction<Object>) () -> {
smartSingleton.afterSingletonsInstantiated();
return null;
},
getAccessControlContext()
);
} else {
smartSingleton.afterSingletonsInstantiated();
}
}
}
}
在上述代码的第 10 行中开始合并,为什么在这里进行合并,原因很简单,你可以看作在此之前,spring 所有对于元信息都是进行解析,总有一天到这里开始了通过 BeanDefintion 创建 bean,所以在最后的这一下进行合并是不是很合理。
并且正常人的思想对于合并动作,要么是创建一个新的类比如叫啥 MergedBeanDefinition,或者是将当前的 beanDefiniton 在合并的时候将父 BeanDefinition 中的相关信息拷贝下来到当前的这个 BeanDefintion 中,但是 spring 没有这么做,这里他很聪明,直接扫描所有子类 BeanDefinition,将子类中的信息放到 RootBeanDefintion 中 然后将合并好的 BeanDefiniton 进行实例化完成 bean 的创建。
下面使用一个 demo 来描述什么叫将子类合并到 RootBeanDefiniton 上:
当前有两个类会后面会被注册到 spring 中:
public class RootBeanS {
String name;
String type;
public void setName(String name) {
this.name = name;
}
public void setType(String type) {
this.type = type;
}
}
public class ChildBeanS {
String name;
String type;
public void setName(String name) {
this.name = name;
}
public void setType(String type) {
this.type = type;
}
@Override
public String toString() {
return "name:" + name +"======="+ "type:" + type;
}
}
public class Starter {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
// 父类BD
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition();
rootBeanDefinition.setBeanClass(RootBeanS.class);
rootBeanDefinition.getPropertyValues().add("type", "movie");
rootBeanDefinition.getPropertyValues().add("name", "image");
context.registerBeanDefinition("root", rootBeanDefinition);
// 子类BD
GenericBeanDefinition childBeanDefinition = new GenericBeanDefinition();
childBeanDefinition.setBeanClass(ChildBeanS.class);
childBeanDefinition.setParentName("root");
childBeanDefinition.getPropertyValues().add("name", "wujiandao");
context.registerBeanDefinition("child", childBeanDefinition);
ChildBeanS childBeanS = context.getBean(ChildBeanS.class);
System.out.println(childBeanS.toString());
}
}
分析一下现在的场景,咱们有两个类,分别模拟一个父类和一个子类 BeanDefinition 的关系。
然后在启动类中我们分别创建了两个 BeanDefinition 并且指定对应的 target 对象,并且在指定完成之后还进行了依赖关系的绑定,同时设置上下关系之间的属性,可以看到的是 type 在父类中设置为 movie,name 设置为 image,但是注意一点子类 childBeanDefinition 同时也设置了 name 这个属性,并且指定了值。那么上面咱们说 spring 进行 BeanDefinition 合并的时候会读取子类的信息填充到 rootBeanDefinition 上,那按照这个理论上述的结果是不是为 type=movie,而 name=wujiandao:
结果和我们想的一样,但是下面咱们要走一遍源码来看一下 spring 到底是怎么做的。
- 首先定位到获取合并 BeanDefinition 的地方:
- 在这里还要看一点东西,也就是 GenericBeanDefinition 的 JavaDoc,作者在上面明确的写了 RootBeanDefintion 是直接表明了一个 BeanDefintion 的父子类的关系。
/**
* GenericBeanDefinition is a one-stop shop for standard bean definition purposes.
* Like any bean definition, it allows for specifying a class plus optionally
* constructor argument values and property values. Additionally, deriving from a
* parent bean definition can be flexibly configured through the "parentName" property.
*
* <p>In general, use this {@code GenericBeanDefinition} class for the purpose of
* registering user-visible bean definitions (which a post-processor might operate on,
* potentially even reconfiguring the parent name). Use {@code RootBeanDefinition} /
* {@code ChildBeanDefinition} where parent/child relationships happen to be pre-determined.
*/
- GenericBeanDefinition是用于标准bean定义的一站式服务。
- 像任何bean定义一样,它允许指定一个可选的类构造函数参数值和属性值。
- 另外,从a父bean的定义可以通过“parentName”属性灵活配置。
- 通常,使用{@code GenericBeanDefinition}类的目的是注册用户可见的bean定义(后处理程序可以对其进行操作,甚至可能重新配置父级名称)。
- 使用{@code RootBeanDefinition}{@code ChildBeanDefinition},其中父/子关系碰巧是预先确定的。
- 从上文对于 GenericBeanDefinition 的 JavaDoc 中我们可以分析出作者对于他作用的定义,首先也就是 GenericBeanDefinition 可以作为任何 Bean 定义的描述类,也就是不管你是什么样的 Bean,都可以使用 GenericBeanDefinition 来进行描述,并且通过 GenericBeanDefinition 来灵活的配置你当前的 BeanDefintion 的 父类 BeanDefinition 是谁?等等这些功能。
- 并且在该 JavaDoc 中也明确的提出了,之前使用 ChildBeanDefinition 的话,一对父子关系的 BeanDefintion 的关系是已经存在了的。或者说只要你 new 了一个ChildBeanDefinition 那么你就必须要给他指定一个 parentBeanDefinition。
- 但是放到 GenericBeanDefinition 中其实不太需要,原因是你可以认为他是通用类型的 Bean 的定义类,并且在该类的 JavaDoc 中也说明了 "任何bean定义" ,所以从这一点也可以体现出 GenericBeanDefinition 的通用性。
- 回到当前咱们讨论的问题,也就是说使用 GenericBeanDefinition 他既可以当父 BeanDefintion 也可以充当为 ChildBeanDefinition。
- 然后咱们可以看到在上述获取到 MergedBeanDefinition 方法最后获取到的一个 RootBeanDefintion,注意哈,这里的 RootBeanDefinition 说的并不是单纯的 RootBeanDefinition 就结束了,他指的是一个 bean ,比如他叫 a 这个 BeanDefinition,最后合并结束后,使用 RootBeanDefiniton 来表述当前的 Bean 的 BeanDefinition 是怎么样的。
- 说了这么多,下面咱们看实例的应用图:
- 首先在咱们当前获取 beanDefintion 的时候设置条件只要看的是 chlid 这个 Bean。
- 当程序执行到 getMergedLocalBeanDefinition 方法的时候我们当前执行的情况。
- 首先我们当前执行到了子类,也就是 child BeanDefinition,咱们看看当前他没有被执行 getMergedLocalBeanDefinition 方法的样子:
- 可以看到在当前没有执行 getMergedLocalBeanDefinition 方法之前 chlid 这个 BeanDefinition 中的 propertyValues 属性中只有一个元素,也就是对应着上述代码中我们对 chlid 这个 BeanDefinition 的设置:
GenericBeanDefinition childBeanDefinition = new GenericBeanDefinition();
childBeanDefinition.setBeanClass(ChildBeanS.class);
childBeanDefinition.setParentName("root");
childBeanDefinition.getPropertyValues().add("name", "wujiandao");
context.registerBeanDefinition("child", childBeanDefinition);
- 但是问题来了!我上面还有一段对于父类的设置呢!
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition();
rootBeanDefinition.setBeanClass(RootBeanS.class);
rootBeanDefinition.getPropertyValues().add("type", "movie");
rootBeanDefinition.getPropertyValues().add("name", "image");
context.registerBeanDefinition("root", rootBeanDefinition);
- 那父类中是不是还有一个 propertyValues 属性 key:type,value:movie
- 那按理来说我现在是不是在 中设置了一个父类的 BeanDefinition:
childBeanDefinition.setParentName("root");
- 那是不是意味我继承于父类的子类也要有propertyValues 属性 key:type,value:movie 呢?
- 没错这肯定是必须要有的,不然是不是和用户最终的构思不一样呀!
- 那下面咱们就来看一下 spring 是如何实现的父子 BeanDefinition 的合并的。
- 现在咱们先进入到 getMergedLocalBeanDefinition 方法中:
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));
}
- 仔细的看上述作者对第三行高亮的代码的注释:Quick check on the concurrent map first, with minimal locking.
- 翻译一下:首先快速检查并发映射,使用最少的锁。
- 也就是说快速的获取并且使用最少量的锁来加开获取的时间。
- 这里说一点,当程序执行到这里的时候其实不管怎么样,最后通过this.mergedBeanDefinitions.get(beanName)方法调用之后都不是空,来解释一下这个原因:
-
- 我们通过栈调用的链路来看,会发现 spring 至始至终都没有将一个 beanDefinition 合并之后放入到 mergedBeanDefinitions 这个集合中的动作,那咱们上面为什么说通过 get 方法拿出来的mbd 绝对不会为空呢?
- 这个问题咱们衍生开来就会在想,这个 BeanDefinition spring 是在什么时候给咱们合并然后 put 到 mergedBeanDefinitions 中的呢?
- 我们可以通过 Idea 的一个功能,来查找全局哪里使用 mergedBeanDefinitions.put(),这个方法。
-
- 咱们发现整个 spring 源码中只有一个地方,就是在 getMergedBeanDefinition(beanName, getBeanDefinition(beanName)) 方法才会有 put 的动作。
- 好的,问题来了,那 spring 是在什么时候调用 getMergedBeanDefinition 方法的呢?
- 我们把断点打在该方法上,然后执行,查看他的调用栈,前提是咱们现在要将其他的断点都去掉,不然的话会影响观察的效果。
-
- 可以看到在当前执行的断点是在咱们 put 方法上,并且下面咱们也可以看到当前断点下的所有的调用栈。
- 咱们直接看调用栈从下往上的第 4 个:
-
- 我们首先来说一下该方法的作用是啥,其实看的出来,其实就是获取当前 BeanDefinitionRegistryPostProcessor 的名字的集合。
- 然后通过这个 BeanDefinitionRegistryPostProcessor 的名字来实例化一个 BeanDefinitionRegistryPostProcessor 。
- 但是程序执行到这里,spring 是没有实例化 beanDefinitionMap 当中的 BeanDefintion。
- 并且在这里扯一下,我们说 spring 中有 6 个 "开天辟地" 的类,其中最重要的一个是 ConfigurationClassPostProcessor ,那么我们要调用这个对象的方法,是不是一定要实例化这个 ConfigurationClassPostProcessor ,那么这个时候是不是就会进入到获取 BeanDefinition 的流程中了。
- 但是要获取到 BeanDefinition 是不是要 MergeBeanDefinition 的才行,因为有可能会存在父子 beanDefinition 的关系,所以这里会走一次 getMergedBeanDefinition 方法。
-
- 但是当前在获取 ConfigurationClassPostProcessor 的时候是没有将我们程序员手动注册到 BeanDefinitionMap 的 beanDefinition 也参与到扫描中的。
- 而是在getBeanNamesForType()方法下面的另一个getBeanNamesForType()方法中,来获取到程序员注入的 BeanDefinition,那么也同样的道理,也会去通过 getMergedBeanDefinition 方法来完成一次 BeanDefiniton 的合并工作。
- 并且 spring 不同版本中启动就会注册的 bean 的个数是有差异的,这次说明一下,在 5.1 版本之后启动就会注册的是 6 个,在此之前是 7 个,被丢弃掉的是RequiredAnnotationBeanPostProcessor
- 咱们可以 spring 对他的 JavaDoc:
/**
* {@link org.springframework.beans.factory.config.BeanPostProcessor} implementation
* that enforces required JavaBean properties to have been configured.
* Required bean properties are detected through a Java 5 annotation:
* by default, Spring's {@link Required} annotation.
*
* <p>The motivation for the existence of this BeanPostProcessor is to allow
* developers to annotate the setter properties of their own classes with an
* arbitrary JDK 1.5 annotation to indicate that the container must check
* for the configuration of a dependency injected value. This neatly pushes
* responsibility for such checking onto the container (where it arguably belongs),
* and obviates the need (<b>in part</b>) for a developer to code a method that
* simply checks that all required properties have actually been set.
*
* <p>Please note that an 'init' method may still need to be implemented (and may
* still be desirable), because all that this class does is enforcing that a
* 'required' property has actually been configured with a value. It does
* <b>not</b> check anything else... In particular, it does not check that a
* configured value is not {@code null}.
*
* <p>Note: A default RequiredAnnotationBeanPostProcessor will be registered
* by the "context:annotation-config" and "context:component-scan" XML tags.
* Remove or turn off the default annotation configuration there if you intend
* to specify a custom RequiredAnnotationBeanPostProcessor bean definition.
*
* @author Rob Harrop
* @author Juergen Hoeller
* @since 2.0
* @see #setRequiredAnnotationType
* @see Required
* @deprecated as of 5.1, in favor of using constructor injection for required settings
* (or a custom {@link org.springframework.beans.factory.InitializingBean} implementation)
*/
- 最后一句话是关键。
- 好的,这个是题外话我们下面来具体看一下 spring 是如何完成 Mergerd 的。
- 首先还是进入到 PostProcessorRegistrationDelegate 中的 invokeBeanFactoryPostProcessors 方法:
String[] postProcessorNames = beanFactory.getBeanNamesForType(
BeanDefinitionRegistryPostProcessor.class,
true,
false
);
- 然后走到 getBeanNameForType 方法中调用 doGetBeanNamesForType 方法:
if (!isConfigurationFrozen() || type == null || !allowEagerInit) {
return doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, allowEagerInit);
}
- 再继续走到 doGetBeanNamesForType 方法中的 getMergedLocalBeanDefinition 方法:
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
- 再继续就是老面孔了:
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));
}
- 但是在这里我们可以看到因为是第一次,所以这会儿是真的没有任何的 mergedBeanDefinition 存在。
- 就会走下面的getMergedBeanDefinition(beanName, getBeanDefinition(beanName));方法来完成 mergedBeanDefinition 的逻辑。
- ok,当前往下走的话会调用 getMergedBeanDefinition 方法,但是我们先去看看 getBeanDefinition(beanName) 方法中的内容:
public BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {
BeanDefinition bd = this.beanDefinitionMap.get(beanName);
if (bd == null) {
if (logger.isTraceEnabled()) {
logger.trace("No bean named '" + beanName + "' found in " + this);
}
throw new NoSuchBeanDefinitionException(beanName);
}
return bd;
}
- 那这个 beanDefinitionMap 集合中肯定是有的:
- 所以将当前需要被 merged 的 BeanDefinition 拿出来。
- 好的当前从 beanDefinitionMap 集合拿出来的 BeanDefinition,肯定是一个还没有执行合并的 bd ,所以下面开始走 bd 合并的逻辑了。
- 回到 getMergedBeanDefinition 方法:
- 继续走:
protected RootBeanDefinition getMergedBeanDefinition(String beanName, BeanDefinition bd) throws BeanDefinitionStoreException {
return getMergedBeanDefinition(beanName, bd, null);
}
- 接着走就真的到了咱们完成 Merge 的地方了:
- getMergedBeanDefinition 的完整方法:
protected RootBeanDefinition getMergedBeanDefinition(String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd)
throws BeanDefinitionStoreException {
synchronized (this.mergedBeanDefinitions) {
RootBeanDefinition mbd = null;
RootBeanDefinition previous = null;
// Check with full lock now in order to enforce the same merged instance.
if (containingBd == null) {
mbd = this.mergedBeanDefinitions.get(beanName);
}
if (mbd == null || mbd.stale) {
previous = mbd;
if (bd.getParentName() == null) {
// Use copy of given root bean definition.
if (bd instanceof RootBeanDefinition) {
mbd = ((RootBeanDefinition) bd).cloneBeanDefinition();
} else {
mbd = new RootBeanDefinition(bd);
}
} else {
// Child bean definition: needs to be merged with parent.
BeanDefinition pbd;
try {
String parentBeanName = transformedBeanName(bd.getParentName());
if (!beanName.equals(parentBeanName)) {
pbd = getMergedBeanDefinition(parentBeanName);
} else {
BeanFactory parent = getParentBeanFactory();
if (parent instanceof ConfigurableBeanFactory) {
pbd = ((ConfigurableBeanFactory) parent).getMergedBeanDefinition(parentBeanName);
} else {
throw new NoSuchBeanDefinitionException(parentBeanName,
"Parent name '" + parentBeanName + "' is equal to bean name '" + beanName +
"': cannot be resolved without a ConfigurableBeanFactory parent");
}
}
} catch (NoSuchBeanDefinitionException ex) {
throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName,
"Could not resolve parent bean definition '" + bd.getParentName() + "'", ex);
}
// Deep copy with overridden values.
mbd = new RootBeanDefinition(pbd);
mbd.overrideFrom(bd);
}
// Set default singleton scope, if not configured before.
if (!StringUtils.hasLength(mbd.getScope())) {
mbd.setScope(SCOPE_SINGLETON);
}
// A bean contained in a non-singleton bean cannot be a singleton itself.
// Let's correct this on the fly here, since this might be the result of
// parent-child merging for the outer bean, in which case the original inner bean
// definition will not have inherited the merged outer bean's singleton status.
if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) {
mbd.setScope(containingBd.getScope());
}
// Cache the merged bean definition for the time being
// (it might still get re-merged later on in order to pick up metadata changes)
if (containingBd == null && isCacheBeanMetadata()) {
this.mergedBeanDefinitions.put(beanName, mbd);
}
}
if (previous != null) {
copyRelevantMergedBeanDefinitionCaches(previous, mbd);
}
return mbd;
}
}
- 咱们稍微梳理一下他的流程:
- 首先上了一个同步锁。
- 然后两个变量:
-
- RootBeanDefinition mbd:合并之后的 bd 变量
- RootBeanDefinition previous:不知道干啥的
- 下面判断判断 containingBd 是否为空,这个肯定为空,因为上方的参数传递就是为 null,所以肯定会进入到 mergedBeanDefinitions.get(beanName) 方法中。
- 那么这时候肯定是获取不到的,也就是为 null,进入到第 10 行的逻辑。
- 那么再往下走就是判断当前的 BeanDefintion 是否有父类,会开始分两个逻辑线走了。
- 如果没有父类,就很简单,直接 new 一个 RootBeanDefintion,完成 bd 的 copy 然后赋值给 mbd 变量就完成的 BD 的合并。
- 但是如果有父类就同步子类信息到父类中的逻辑了。
- 具体到现在是合并咱们在代码中注册的有父类的 BD -->> child 这个 BD。
- 可以看到当前 bd.getParentName() == null 最后的结果为 false,也就是会进入到 else 块中。
- 然后通过 transformedBeanName 方法来获取当前当前 BD 的父类 BD 的名称。
- 那么下一步就是判断当前的 BD 的名称是否和父类的 BD 相同:
-
- 一般是不会相同的,所以走到这个 if 中,这个时候又会调用 getMergedBeanDefinition 方法。
- 那流程和上述 getMergedBeanDefinition 方法的流程是一样的了。
- 但是这里的 rootBD 是拿的出来的:
-
- 这是为啥,原因很简单,咱们自己写的代码里面不是先将 root BD 先 register 进 spring 容器中的嘛。
- 并且所有的 BD 都会走到这个 getMergedBeanDefinition 方法中,那么按照上面说的逻辑,他是不是没有父类,那么是不是就是 copy,完了赋值一个 RootBeanDefintion 对象,放入到 MergerBeanDefinitionMap 中。
- 那你当前 ChildBD 想要去获取到 合并后的 RootBD 当然是拿的到的了。
-
- 然后在获取到父类的 BD 之后,就会直接跳到 41~42 行代码了。
- 很简单昂:
// Deep copy with overridden values.
mbd = new RootBeanDefinition(pbd);
mbd.overrideFrom(bd);
- 将当前合并好的 bd 放入 RootBeanDefinition 的构造器中:
RootBeanDefinition(BeanDefinition original) {
super(original);
}
/**
* Create a new AbstractBeanDefinition as a deep copy of the given
* bean definition.
* @param original the original bean definition to copy from
*/
protected AbstractBeanDefinition(BeanDefinition original) {
setParentName(original.getParentName());
setBeanClassName(original.getBeanClassName());
setScope(original.getScope());
setAbstract(original.isAbstract());
setFactoryBeanName(original.getFactoryBeanName());
setFactoryMethodName(original.getFactoryMethodName());
setRole(original.getRole());
setSource(original.getSource());
copyAttributesFrom(original);
if (original instanceof AbstractBeanDefinition) {
AbstractBeanDefinition originalAbd = (AbstractBeanDefinition) original;
if (originalAbd.hasBeanClass()) {
setBeanClass(originalAbd.getBeanClass());
}
if (originalAbd.hasConstructorArgumentValues()) {
setConstructorArgumentValues(new ConstructorArgumentValues(original.getConstructorArgumentValues()));
}
if (originalAbd.hasPropertyValues()) {
setPropertyValues(new MutablePropertyValues(original.getPropertyValues()));
}
if (originalAbd.hasMethodOverrides()) {
setMethodOverrides(new MethodOverrides(originalAbd.getMethodOverrides()));
}
Boolean lazyInit = originalAbd.getLazyInit();
if (lazyInit != null) {
setLazyInit(lazyInit);
}
setAutowireMode(originalAbd.getAutowireMode());
setDependencyCheck(originalAbd.getDependencyCheck());
setDependsOn(originalAbd.getDependsOn());
setAutowireCandidate(originalAbd.isAutowireCandidate());
setPrimary(originalAbd.isPrimary());
copyQualifiersFrom(originalAbd);
setInstanceSupplier(originalAbd.getInstanceSupplier());
setNonPublicAccessAllowed(originalAbd.isNonPublicAccessAllowed());
setLenientConstructorResolution(originalAbd.isLenientConstructorResolution());
setInitMethodName(originalAbd.getInitMethodName());
setEnforceInitMethod(originalAbd.isEnforceInitMethod());
setDestroyMethodName(originalAbd.getDestroyMethodName());
setEnforceDestroyMethod(originalAbd.isEnforceDestroyMethod());
setSynthetic(originalAbd.isSynthetic());
setResource(originalAbd.getResource());
}
else {
setConstructorArgumentValues(new ConstructorArgumentValues(original.getConstructorArgumentValues()));
setPropertyValues(new MutablePropertyValues(original.getPropertyValues()));
setLazyInit(original.isLazyInit());
setResourceDescription(original.getResourceDescription());
}
}
- 其实就是一个赋值,那就是咱们的 copy 过程嘛。
- 然后就是到 mbd.overrideFrom(bd); 方法:
public void overrideFrom(BeanDefinition other) {
if (StringUtils.hasLength(other.getBeanClassName())) {
setBeanClassName(other.getBeanClassName());
}
if (StringUtils.hasLength(other.getScope())) {
setScope(other.getScope());
}
setAbstract(other.isAbstract());
if (StringUtils.hasLength(other.getFactoryBeanName())) {
setFactoryBeanName(other.getFactoryBeanName());
}
if (StringUtils.hasLength(other.getFactoryMethodName())) {
setFactoryMethodName(other.getFactoryMethodName());
}
setRole(other.getRole());
setSource(other.getSource());
copyAttributesFrom(other);
if (other instanceof AbstractBeanDefinition) {
AbstractBeanDefinition otherAbd = (AbstractBeanDefinition) other;
if (otherAbd.hasBeanClass()) {
setBeanClass(otherAbd.getBeanClass());
}
if (otherAbd.hasConstructorArgumentValues()) {
getConstructorArgumentValues().addArgumentValues(other.getConstructorArgumentValues());
}
if (otherAbd.hasPropertyValues()) {
getPropertyValues().addPropertyValues(other.getPropertyValues());
}
if (otherAbd.hasMethodOverrides()) {
getMethodOverrides().addOverrides(otherAbd.getMethodOverrides());
}
Boolean lazyInit = otherAbd.getLazyInit();
if (lazyInit != null) {
setLazyInit(lazyInit);
}
setAutowireMode(otherAbd.getAutowireMode());
setDependencyCheck(otherAbd.getDependencyCheck());
setDependsOn(otherAbd.getDependsOn());
setAutowireCandidate(otherAbd.isAutowireCandidate());
setPrimary(otherAbd.isPrimary());
copyQualifiersFrom(otherAbd);
setInstanceSupplier(otherAbd.getInstanceSupplier());
setNonPublicAccessAllowed(otherAbd.isNonPublicAccessAllowed());
setLenientConstructorResolution(otherAbd.isLenientConstructorResolution());
if (otherAbd.getInitMethodName() != null) {
setInitMethodName(otherAbd.getInitMethodName());
setEnforceInitMethod(otherAbd.isEnforceInitMethod());
}
if (otherAbd.getDestroyMethodName() != null) {
setDestroyMethodName(otherAbd.getDestroyMethodName());
setEnforceDestroyMethod(otherAbd.isEnforceDestroyMethod());
}
setSynthetic(otherAbd.isSynthetic());
setResource(otherAbd.getResource());
}
else {
getConstructorArgumentValues().addArgumentValues(other.getConstructorArgumentValues());
getPropertyValues().addPropertyValues(other.getPropertyValues());
setLazyInit(other.isLazyInit());
setResourceDescription(other.getResourceDescription());
}
}
- 该方法就是一个意思,将父子类的 BD 的定义属性进行合并,具体的内容咱们不需要细看。
- 最后在完成子类的到父类的拷贝之后,放入到单例池中,完成合并:
if (containingBd == null && isCacheBeanMetadata()) {
this.mergedBeanDefinitions.put(beanName, mbd);
}
- 好的,上述大致的流程都已经讲完了,下面咱们再重新来回归的梳理一下流程:
- 在上述的讲解中,我们说在 preInstantiateSingletons() 方法中去获取一个 BD 的合并 BD,绝对不会为空,这是为什么,其实答案咱们在上面走流程的时候已经说过了。
- 上图就是在获取到 child BD 的断点处,发现是有值的。
- 但是有一些情况下是拿不到的,也就是 BD 实现不同的 BeanPostProcessor 接口之后,spring 对他做后置的处理的时机是不同的。
- 比如当前,咱们的 child 这个 BD,他虽然在上述截图中是取的出值的,但是你会继续下去你会发现,他由于不是 FactoryBean,所以会走 getBean 的逻辑。
- 继续走会在 doGetBean 方法中也调用一次getMergedLocalBeanDefinition 方法来合并一下当前的 BD。
- 还是会调用到 getMergedLocalBeanDefinition 方法中。
- 不过这里要注意的是,你仔细看当前的 mbd.stale 值为 true,并且前面有一个!表示取反,那么就为 false。
- 所以最后是不会直接 return 的,而是调用下面的那个 return 方法中getMergedBeanDefinition(beanName, getBeanDefinition(beanName)),有一次的完成合并 BD。
- 奇怪这是为啥?
- 其实对于这个 mbd.stale ,咱们之前小小的扯过,就是判断该 BD 是否被冻结。那么没有被冻结说明该 BD 还有一些生命周期没有走过。
- 那么这些生命周期的实现,spring 其实是通过各种不同的 BeanPostProcessor 接口的子实现来完成的。
- 那么就意味着虽然咱们在 invokeBeanFactoryPostProcessors(beanFactory); 方法中完成了对 BeanDefinitionRegistryPostProcessor 接口实现的 BD 的合并,但是其他的呢?就不执行了嘛?
String[] postProcessorNames = beanFactory.getBeanNamesForType(
BeanDefinitionRegistryPostProcessor.class,
true,
false
);
- 显然这是不可能的。
- 所以这里的为什么会走第一个 return 的原因很明显了吧,显然是因为 chlid 的 BD 还有没走完的 BeanPostProcessor 接口的子实现。
- 下面可以画个图来理解,其中我们稍稍的据一些可能实现的接口子实现类。
- 到这里位置咱们对应 spring 中的 BeanDefinition 合并的事情就将完成了。
- 下面咱们开始讲一个方法 applyMergedBeanDefinitionPostProcessors() ,该方法是在 doCreateBean() 方法中。
- 简单来说他的作用是缓存所有的关于当前 BD 的被添加了@Autowrite 注解的 Member,简单来说就是完成属性注入的。
- 当前我们的实验 dome 涉及到的类为:
@Configurable
@ComponentScan("com.lukp.beanPostProcessor.test02.bean")
public class Config {
}
@Component
public class X {
@Autowired
Y y;
}
@Component
public class Y{
}
public class Stater {
public static void main(String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(Config.class);
context.refresh();
}
}
- 可以看到上述的例子所用到的类很简单就几个,但还是稍微说一下具体涉及到那些:配置类扫描指定包下的 Bean,发现有添加 @Component 注解,同时 X 类中完成对 Y 类的属性注入。
- 那么现在我们启动程序看看当被执行的 X 类的时候会发生什么。
- 上述是直接点到 applyMergedBeanDefinitionPostProcessors 内部了,当前的情况是当前被执行 doCreateBean() 方法的是 x ,并且他要被执行 BeanPostProcessor 有 6 个。
- 下面会开始一个循环并且逐个进行类型的判断,当前的 BeanPostProcessor 是否直接或者间接实现了 MergedBeanDefinitionPostProcessor 。
- 我们接着往下走,可以看到的是第一个进入 if 中的是 CommonAnnotationBeanPostProcessor。
public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessor
implements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable {
public class InitDestroyAnnotationBeanPostProcessor
implements DestructionAwareBeanPostProcessor, MergedBeanDefinitionPostProcessor, PriorityOrdered, Serializable {
间接实现了 MergedBeanDefinitionPostProcessor。
- 然后进行强制转化,并且执行了 postProcessMergedBeanDefinition() 方法,我们看看具体执行了啥:
- 首先第一步到 CommonAnnotationBeanPostProcessor 中:
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName);
InjectionMetadata metadata = findResourceMetadata(beanName, beanType, null);
metadata.checkConfigMembers(beanDefinition);
}
- 然后调用父类的 postProcessMergedBeanDefinition() 方法:
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
LifecycleMetadata metadata = findLifecycleMetadata(beanType);
metadata.checkConfigMembers(beanDefinition);
}
- 这个动作其实是在寻找当前的 bean 是否有注册初始化和销毁的方法:但是我们是没有给他指定的,所以这个的初始化和销毁方法的 size 都是 0。
- 那么在这里是调用的我们的第三次的后置回调处理,在这里 spring 使用了 CommonAnnotationBeanPostProcess 来完成对当前 Bean 初始化方法和销毁方法的注册。
- 下面我们继续回到 postProcessMergedBeanDefinition() 方法中:
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName);
InjectionMetadata metadata = findResourceMetadata(beanName, beanType, null);
metadata.checkConfigMembers(beanDefinition);
}
- 在第一行完成了初始化方法和销毁方法之后,执行到了第二行代码,findResourceMetadata,可以简单的从方法名就可以看出他的作用:找出当前 BD 的所有资源的元数据,啥意思呢?可以看到该方法的返回值是 InjectionMetadata ,从这个放回值,我们是可以很直观的得知,findResourceMetadata 方法的作用就是找到需要被注入到当前 BD 的 Bean。
- 咱们可以可以稍微的过一下 InjectionMetadata 这个类,其实这也是 spring 对于一个对象的包装只不过他包装的是一个被注入的 Bean 罢了。
- 该类中最重要的两个属性是:
// 处理Bean的元对象
private final Class<?> targetClass;
// 存储当前bean需要被注入的元素集合
private final Collection<InjectedElement> injectedElements;
- 看到上述的解释也很明白了,其实该对象存放的最重要的两个东西,就两个,一个是 targetClass 当前需要被处理的 bean 的元类型。一个是 injectedElements 当前被处理的 Bean 中他需要被注入的是那些 bean 也可以看到他是一个 Collection 也符合一个 Bean 会被注入多个 Bean 的逻辑。
- 那我们现在来看一下执行完 findResourceMetadata 后的结果是不是和我们想的是一样的呢?按道理来说应该是一个被注入对象的:y。
- 看到上述的图是不是很奇怪,为什么呢?按理来说应该是有一个 y 的呀?咋没有呢?ok,这里要注意 spring 在这里使用了策略模式,也就是对应的不同后置处理器处理的是不同的东西,那么当前执行的策略或者说当前执行的后置处理器是:CommonAnnotationBeanPostProcessor。那么对于这个后置处理器而言是不负责处理一个 Bean 添加了@Autowrite 注解的。
- 那到底是那个后置处理器会处理自动注入呢?我们接着往下走。
- 现在执行的策略是 AutowriteAnnotationBeanPostProcessor 后置处理器,我们走到对应的实现中。
- 在上述的图片我们也不难看出,其中就有我们上面说的执行的其中一个策略,CommonAnntationBeanPostProcessor。
- 好的我们现在跳到 AutowriteAnnotationBeanPostProcessor 后置处理器中:
- 可以很明显的看到当前的在 AutowriteAnnotationBeanPostProcessor 后置处理器中是完成对应 X 这个 Bean 的被注入对象的扫描工作,扫描出了一个 y,是满足我们的预期的。
- 这里稍微的补充一句就是 CommonAnntationBeanPostProcessor 后置处理器来说他是处理@Resource 注解的:
private InjectionMetadata findResourceMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
// Fall back to class name as cache key, for backwards compatibility with custom callers.
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
// Quick check on the concurrent map first, with minimal locking.
InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
synchronized (this.injectionMetadataCache) {
metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
if (metadata != null) {
metadata.clear(pvs);
}
metadata = buildResourceMetadata(clazz);
this.injectionMetadataCache.put(cacheKey, metadata);
}
}
}
return metadata;
}
private InjectionMetadata buildResourceMetadata(Class<?> clazz) {
if (!AnnotationUtils.isCandidateClass(clazz, resourceAnnotationTypes)) {
return InjectionMetadata.EMPTY;
}
List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
Class<?> targetClass = clazz;
do {
final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
ReflectionUtils.doWithLocalFields(targetClass, field -> {
if (webServiceRefClass != null && field.isAnnotationPresent(webServiceRefClass)) {
if (Modifier.isStatic(field.getModifiers())) {
throw new IllegalStateException("@WebServiceRef annotation is not supported on static fields");
}
currElements.add(new WebServiceRefElement(field, field, null));
}
else if (ejbClass != null && field.isAnnotationPresent(ejbClass)) {
if (Modifier.isStatic(field.getModifiers())) {
throw new IllegalStateException("@EJB annotation is not supported on static fields");
}
currElements.add(new EjbRefElement(field, field, null));
}
else if (field.isAnnotationPresent(Resource.class)) {
if (Modifier.isStatic(field.getModifiers())) {
throw new IllegalStateException("@Resource annotation is not supported on static fields");
}
if (!this.ignoredResourceTypes.contains(field.getType().getName())) {
currElements.add(new ResourceElement(field, field, null));
}
}
});
...........
- 回到正题,那么 AutowriteAnnotationBeanPostProcessor 后置处理器又是如何处理@Autowrite 注解的呢?
- 咱们进入到 findAutowiringMetadata 方法内部:
private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
// Fall back to class name as cache key, for backwards compatibility with custom callers.
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
// Quick check on the concurrent map first, with minimal locking.
InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
synchronized (this.injectionMetadataCache) {
metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
if (metadata != null) {
metadata.clear(pvs);
}
metadata = buildAutowiringMetadata(clazz);
this.injectionMetadataCache.put(cacheKey, metadata);
}
}
}
return metadata;
}
- 上述代码的逻辑:
-
- 先获取当前 beanName,通过 cacheKey 来找到对应的 InjectionMetadata 。
- 这个时候会发现 X 这个为 null。
-
- 然后接着走下面的逻辑,其实第六行的逻辑就是判断当前的 injectionMetadataCache 中是否有我要寻找的那个 Bean。
- 没有就会走到 if 块中。
- 并且一直走到 buildAutowiringMetadata 方法中。
-
- 在这个方法中完成对 X 的属性扫描。
private InjectionMetadata buildAutowiringMetadata(Class<?> clazz) {
if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {
return InjectionMetadata.EMPTY;
}
List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
Class<?> targetClass = clazz;
do {
final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
ReflectionUtils.doWithLocalFields(targetClass, field -> {
MergedAnnotation<?> ann = findAutowiredAnnotation(field);
if (ann != null) {
if (Modifier.isStatic(field.getModifiers())) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation is not supported on static fields: " + field);
}
return;
}
boolean required = determineRequiredStatus(ann);
currElements.add(new AutowiredFieldElement(field, required));
}
});
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
return;
}
MergedAnnotation<?> ann = findAutowiredAnnotation(bridgedMethod);
if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
if (Modifier.isStatic(method.getModifiers())) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation is not supported on static methods: " + method);
}
return;
}
if (method.getParameterCount() == 0) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation should only be used on methods with parameters: " + method);
}
}
boolean required = determineRequiredStatus(ann);
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
currElements.add(new AutowiredMethodElement(method, required, pd));
}
});
elements.addAll(0, currElements);
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class);
return InjectionMetadata.forElements(elements, clazz);
}
-
- 对于上述的代码逻辑,我们只需要简单分析一个是对于字段的解析一个是对应方法的解析即可,最后完成当前 BD 的扫描工作。
- 但是上述的两个方法一个是对于当前的 Bean 的字段的推断一个对于当前 Bean 的方法的推断,两者都只是对字段或者是方法进行推断,注意我这里说的"只是",代表着还有别的含义,什么意思呢?在 Java 语言中,对于方法的定义,不管是无参构造器还是有参构造器都是构造器,那么构造器算不算是方法呢?
- 算,因为构造器的作用是用来完成对一个 Java 类的基本定义的工作,也起到一个函数式的定义,那么上述中的doWithLocalMethods 方法只会对比如 set 方法进行处理,那为什么不对构造器进行处理呢?并且咱们说 spring 是可以通过构造器来完成属性注入的,就比如加一个@Autowrite 注解。
- 还记不记得 spring 是如何完成一个 Bean 的实例化的?是不是有一个过程叫做:推断构造器。
- spring 会在这个过程完成构造器上你如果添加@Autowrite 注解的属性注入动作,那在 doWithLocalMethods 方法中为什么没有对构造器完成属性注入呢?
- 一句话,在完成推断构造器的时候把这件事情做掉了。
- 所以咱们在 doWithLocalMethods 方法没有看到 spring 对当前 Bean 的构造器操作。
- 在把 applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName); 方法讲解完成之后,下面要来说说 spring 中的属性填充。
- 进入到 populateBean 方法中:
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
if (bw == null) {
if (mbd.hasPropertyValues()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
} else {
// Skip property population phase for null instance.
return;
}
}
// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
// state of the bean before properties are set. This can be used, for example,
// to support styles of field injection.
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
// 当某一个bean程序员如果不想完成postProcessorAfter的处理可以实现
// InstantiationAwareBeanPostProcessor中的postProcessAfterInstantiation方法
// 并选中你想要的跳过的那个Bean
return;
}
}
}
}
/**
* 填充属性所有的逻辑
*/
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
int resolvedAutowireMode = mbd.getResolvedAutowireMode();
if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// Add property values based on autowire by name if applicable.
if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// Add property values based on autowire by type if applicable.
if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
PropertyDescriptor[] filteredPds = null;
if (hasInstAwareBpps) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
/*============================ 开始处理@Autowrite属性 ============================*/
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return;
}
}
pvs = pvsToUse;
}
}
/*============================ 结束处理@Autowrite属性 ============================*/
}
if (needsDepCheck) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
checkDependencies(beanName, mbd, filteredPds, pvs);
}
if (pvs != null) {
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
- 在 13~26 中,判断当前的 bean 是否实现了 InstantiationAwareBeanPostProcessors 接口 并且去执行 postProcessAfterInstantiation 方法,该方法也是一个策略模式:
- 但是该方法的原接口方法定义为:
/**
* Perform operations after the bean has been instantiated, via a constructor or factory method,
* but before Spring property population (from explicit properties or autowiring) occurs.
* <p>This is the ideal callback for performing custom field injection on the given bean
* instance, right before Spring's autowiring kicks in.
* <p>The default implementation returns {@code true}.
* @param bean the bean instance created, with properties not having been set yet
* @param beanName the name of the bean
* @return {@code true} if properties should be set on the bean; {@code false}
* if property population should be skipped. Normal implementations should return {@code true}.
* Returning {@code false} will also prevent any subsequent InstantiationAwareBeanPostProcessor
* instances being invoked on this bean instance.
* @throws org.springframework.beans.BeansException in case of errors
* @see #postProcessBeforeInstantiation
*/
default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
return true;
}
- 那如果你实现了该方法,但是并没有修改任何的逻辑,直接返回的话,默认是 true,所以该方法就会直接返回 true,再加上一个!就是 false,那么就跳出当前的循环了。
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
return;
}
- 那么其实该实现该方法的本意就是想让人为的操作某一个 Bean 的生命周期,让他不要去完成属性注入的过程,但是一般没人会这么做。
- 咱们接着走到下面完成当前 bean 属性填充的部分。
// 1.获取当前bean属性,通过PropertyValues的形式来进行设置,如果有则采用用户给定的值,如果没有则为null
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
// 2.获取当前Bean的注入模式
int resolvedAutowireMode = mbd.getResolvedAutowireMode();
// 3.这里的判断不是1就是2,其实讲白了就是判断你当前的注入模式是否为自动注入
if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// Add property values based on autowire by name if applicable.
// 如果适用,请按名称添加基于自动连线的属性值。
if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// Add property values based on autowire by type if applicable.
// 如果适用,请按类型添加基于自动连线的属性值。
if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
PropertyDescriptor[] filteredPds = null;
if (hasInstAwareBpps) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
/*============================ 开始处理@Autowrite属性 ============================*/
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return;
}
}
pvs = pvsToUse;
}
}
/*============================ 结束处理@Autowrite属性 ============================*/
}
if (needsDepCheck) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
checkDependencies(beanName, mbd, filteredPds, pvs);
}
// 如果当前的pvs不为null就表述通过ByType的形式有两种可能性:
// 1.是用户提供的:PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
// 2.通过ByType或者是ByName使用spring封装的Bean内省机制来获取到当前实体中用户提供的write方法,其实就是set方法,然后完成自动注入,
// 但是这里是要找到合适的自动注入的write方法,不然假如你当前的set方法,set的根本是一个不存在的实体那spring咋找?
if (pvs != null) {
applyPropertyValues(beanName, mbd, bw, pvs);
}
- 首先咱们重点要看的就是如下的这段代码:
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return;
}
}
pvs = pvsToUse;
}
}
- 咱们首先看到的是 getBeanPostProcesseors 方法的结果,有如下的这些后置处理器需要被执行。
- 下面我们就看重要的几个后置处理器执行的过程即可,首先执行的是 ConfigurationClassPostProcessor 后置处理器的任务,但是执行完后,发现被填充属性 y 并没有填充完成。
- 然后到 CommonAnnotationBeanPostProcessor 后置处理器,该后置处理的完成的是对@Resource 注解的扫描处理,但是这个处理其实在之前 BeanDefinition 合并的时候就已经完成了,所以这个时候执行 CommonAnnotationBeanPostProcessor 后置处理器时,会从前面找到的添加了@Resource 注解字段的缓存。当然完成该后置处理之后是没有结果,因为我们没有添加@Resouce 注解标注如何字段。
- 好的,下面再执行就到 AutowiredAnnotationBeanPostProcess 后置处理器的处理流程了,该后置处理器在上述也说过了,他是处理 @Autowirte 注解的。
- 那在本次的测试用例中,我们使用@Autowirte 注解完成了对 y 的属性注入。
- 所以 AutowiredAnnotationBeanPostProcess 后置处理器完成 postProcessProperties 方法后 y 就会被注入进来了。
- 具体下来我们可以进入到 postProcessProperties 方法中,但是注意要进入到的策略是 AutowiredAnnotationBeanPostProcess。
- 详细的执行过程咱们就不看了,但是可以看到 findAutowiringMetadata(beanName, bean.getClass(), pvs) 方法的返回值:
- 从上图中可以很明显的看出来找到了 X 这个 Bean 的被注入属性 y。
- 然后调用 inject 方法完成属性注入,注意昂,上述的 findAutowireMetadate 方法中的过程只是在寻找并不是完成了注入,真正的完成注入是在下面的 inject 方法中。
- 首先我们进入到 inject 方法中:
public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Collection<InjectedElement> checkedElements = this.checkedElements;
Collection<InjectedElement> elementsToIterate = (checkedElements != null ? checkedElements : this.injectedElements);
if (!elementsToIterate.isEmpty()) {
for (InjectedElement element : elementsToIterate) {
element.inject(target, beanName, pvs);
}
}
}
- 下面走进 inject 方法中,完成具体的主要流程:
- 进入到上述标红的方法中:
- 可以看到上述的 cached 的为 false,当整个属性注入完成之后才会变成 true。
- 那么有缓存和没有缓存最大的区别在于是否需要对当前需要被注入的属性,进行解析。
- 备注一下,上述当方法走到上述断点处的这里,其实是版本的不同会有些许差异,在当前的 5.2.x 这个版本中 spring 是采用切了一个版本来完成的,在 5.1.x 中 spring 是采用直接写在一整个方法中,也就是直接写在当前的这个方法中。
- 好的,下面咱们继续走,进入 resolveFieldValue 方法中:
private Object resolveFieldValue(Field field, Object bean, @Nullable String beanName) {
DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
desc.setContainingClass(bean.getClass());
Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
Assert.state(beanFactory != null, "No BeanFactory available");
TypeConverter typeConverter = beanFactory.getTypeConverter();
Object value;
try {
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
}
catch (BeansException ex) {
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
}
synchronized (this) {
if (!this.cached) {
Object cachedFieldValue = null;
if (value != null || this.required) {
cachedFieldValue = desc;
registerDependentBeans(beanName, autowiredBeanNames);
if (autowiredBeanNames.size() == 1) {
String autowiredBeanName = autowiredBeanNames.iterator().next();
if (beanFactory.containsBean(autowiredBeanName) &&
beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
cachedFieldValue = new ShortcutDependencyDescriptor(
desc, autowiredBeanName, field.getType());
}
}
}
this.cachedFieldValue = cachedFieldValue;
this.cached = true;
}
}
return value;
}
}
- 咱们来描述一下该方法的过程:
- 首先可以看到的是创建了一个叫做 DependencyDescriptor 的对象,从字面意思中可以解读出,该类是对一个注入模型的描述。
- 接着到第二行中,设置当前需要被注入的对象,也就是 y。
- 从上述的两张图中就可以看出来,需要完成注入的是 x,被注入的是 y。
- 然后创建了一个 set 集合存放当前注入的 bean 的 name 的集合。
- 下面继续执行到:
TypeConverter typeConverter = beanFactory.getTypeConverter();
- 该方法我们不做过多的赘述,因为他设计 spring 中对于一些类型转换的东西,和现在讨论的 bean 注入没有很大的关系。
- 再往下就到了,解析注入属性的方法 resolveDependency 。
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
- 可以看到在执行完 resolveDependency 方法后,最后的结果 value 的值是不是就是 Y,也就是 X 需要注入的对象。
- 这里寻找 X 中被注入的对象 Y,调用 resolveDependency 方法的其实还是那句话,有则直接返回,没有创建一个返回给你,同理 resolveDependency 方法也是如此。
- 下面就到 synchronized 代码块中的内容了,但是当中的内容咱们不需要关注(当前),我们只需要关注的是该方法的最后一行,将 cached 设置为 true。
synchronized (this) {
if (!this.cached) {
Object cachedFieldValue = null;
if (value != null || this.required) {
cachedFieldValue = desc;
registerDependentBeans(beanName, autowiredBeanNames);
if (autowiredBeanNames.size() == 1) {
String autowiredBeanName = autowiredBeanNames.iterator().next();
if (beanFactory.containsBean(autowiredBeanName) &&
beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
cachedFieldValue = new ShortcutDependencyDescriptor(
desc, autowiredBeanName, field.getType());
}
}
}
this.cachedFieldValue = cachedFieldValue;
this.cached = true;
}
}
- 寻找注入对象的工作在 resolveDependency 方法执行结束之后,回到 inject 方法中,你会发现原来 spring 对于注入的工作如此简单。
- 就是最后的一个 set 就结束了,把当前的 bean == x,和当前需要注入的属性 y,set 一下,完成!
- 我们总结一下 spring 对于添加了@Autowrite 注解后完成注入的流程:
- 其实简单来说就是假如我要解析一个 Bean 就会扫描该 bean 上的所有添加了 @Autowrite 注解的字段,并且进行扫描,然后一个一个的去注入,调用 set 方法完成。
下面来讲 resolveDependency 方法,该方法是如何获取到被注入对象的(重点)
- 首先我们当前的断点还是要打到 x 在完成属性注入的过程中。
- 因为我们要看 resolveDependency 方法,所以直接到该位置即可:同时可以看到的是当前要寻找的就是 y.class 类型的 Bean。
- 代码如下:
public Object resolveDependency(DependencyDescriptor descriptor,
@Nullable String requestingBeanName,
@Nullable Set<String> autowiredBeanNames,
@Nullable TypeConverter typeConverter) throws BeansException {
descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
if (Optional.class == descriptor.getDependencyType()) {
return createOptionalDependency(descriptor, requestingBeanName);
} else if (ObjectFactory.class == descriptor.getDependencyType() || ObjectProvider.class == descriptor.getDependencyType()) {
return new DependencyObjectProvider(descriptor, requestingBeanName);
} else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
} else {
Object result = getAutowireCandidateResolver()
.getLazyResolutionProxyIfNecessary(descriptor, requestingBeanName);
if (result == null) {
result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
}
return result;
}
}
- 首先对于一件事情肯定存在正常的情况和非正常的情况,我们当前是在讨论 spring 是怎么去找到一个 Bean 需要被注入的属性对象的过程。
- 所以再看到上述 resolveDependency 方法的代码,其实我们最重要的是看到最后一块高光的地方,那块地方是正常情况,也就是正真在完成依赖对象的寻找。
- 至于上面剩余的各种 if 或者是 else 都是异常情况,我们先不看,等把正常的流程看完了之后再回过头来思考。
- 首先我们将代码执行到 16 行上,执行 doResolveDependency 方法上:
public Object doResolveDependency(DependencyDescriptor descriptor,
@Nullable String beanName,
@Nullable TypeConverter typeConverter,
@Nullable Set<String> autowiredBeanNames) throws BeansException {
InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
try {
Object shortcut = descriptor.resolveShortcut(this);
if (shortcut != null) {
return shortcut;
}
Class<?> type = descriptor.getDependencyType();
Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
if (value != null) {
if (value instanceof String) {
String strVal = resolveEmbeddedValue((String) value);
BeanDefinition bd = (beanName != null && containsBean(beanName) ? getMergedBeanDefinition(beanName) : null);
value = evaluateBeanDefinitionString(strVal, bd);
}
TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
try {
return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());
} catch (UnsupportedOperationException ex) {
// A custom TypeConverter which does not support TypeDescriptor resolution...
return (descriptor.getField() != null ?
converter.convertIfNecessary(value, type, descriptor.getField()) :
converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
}
}
Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
if (multipleBeans != null) {
return multipleBeans;
}
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
if (matchingBeans.isEmpty()) {
if (isRequired(descriptor)) {
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
return null;
}
String autowiredBeanName;
Object instanceCandidate;
if (matchingBeans.size() > 1) {
autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
if (autowiredBeanName == null) {
if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);
} else {
// In case of an optional Collection/Map, silently ignore a non-unique case:
// possibly it was meant to be an empty collection of multiple regular beans
// (before 4.3 in particular when we didn't even look for collection beans).
return null;
}
}
instanceCandidate = matchingBeans.get(autowiredBeanName);
} else {
// We have exactly one match.
Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
autowiredBeanName = entry.getKey();
instanceCandidate = entry.getValue();
}
if (autowiredBeanNames != null) {
autowiredBeanNames.add(autowiredBeanName);
}
if (instanceCandidate instanceof Class) {
instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
}
Object result = instanceCandidate;
if (result instanceof NullBean) {
if (isRequired(descriptor)) {
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
result = null;
}
if (!ClassUtils.isAssignableValue(type, result)) {
throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass());
}
return result;
} finally {
ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
}
}
- doResolveDependency 方法当中也有很多的不正常情况的处理,我们当前也都先跳过,先执行到 36 行高光的地方,也就是 findAutowireCandidates 方法。
- 我们将这个方法贴出来:
/**
* Find bean instances that match the required type.
* Called during autowiring for the specified bean.
*
* @param beanName the name of the bean that is about to be wired
* @param requiredType the actual type of bean to look for
* (may be an array component type or collection element type)
* @param descriptor the descriptor of the dependency to resolve
* @return a Map of candidate names and candidate instances that match the required type (never {@code null})
* @throws BeansException in case of errors
* @see #autowireByType
* @see #autowireConstructor
*/
protected Map<String, Object> findAutowireCandidates(@Nullable String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {
String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this, requiredType, true, descriptor.isEager());
Map<String, Object> result = new LinkedHashMap<>(candidateNames.length);
for (Map.Entry<Class<?>, Object> classObjectEntry : this.resolvableDependencies.entrySet()) {
Class<?> autowiringType = classObjectEntry.getKey();
if (autowiringType.isAssignableFrom(requiredType)) {
Object autowiringValue = classObjectEntry.getValue();
autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType);
if (requiredType.isInstance(autowiringValue)) {
result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue);
break;
}
}
}
for (String candidate : candidateNames) {
if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
if (result.isEmpty()) {
boolean multiple = indicatesMultipleBeans(requiredType);
// Consider fallback matches if the first pass failed to find anything...
DependencyDescriptor fallbackDescriptor = descriptor.forFallbackMatch();
for (String candidate : candidateNames) {
if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, fallbackDescriptor) &&
(!multiple || getAutowireCandidateResolver().hasQualifier(descriptor))) {
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
if (result.isEmpty() && !multiple) {
// Consider self references as a final pass...
// but in the case of a dependency collection, not the very same bean itself.
for (String candidate : candidateNames) {
if (isSelfReference(beanName, candidate) &&
(!(descriptor instanceof MultiElementDescriptor) || !beanName.equals(candidate)) &&
isAutowireCandidate(candidate, fallbackDescriptor)) {
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
}
}
return result;
}
- 首先执行第一行代码,获取到当前需要被注入的 beanNames,现在只有一个也就是 y。
- 然后接着走到一个 for 循环中,在循环中会判断当前需要被执行的注入对象是不是满足如下实现:
- 显然我们当前的 y 并不满足这个条件,所以接着往下走:
for (String candidate : candidateNames) {
if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
- isSelfReference(beanName, candidate):判断当前的注入对象是不是自己;isAutowireCandidate(candidate, descriptor):去重别名;
- 这个两个判断的方法先放在一边,我们先看 addCandidateEntry()方法。
/**
* Add an entry to the candidate map: a bean instance if available or just the resolved
* type, preventing early bean initialization ahead of primary candidate selection.
*/
private void addCandidateEntry(String candidateName,
Class<?> requiredType,
Map<String, Object> candidates,
DependencyDescriptor descriptor) {
if (descriptor instanceof MultiElementDescriptor) {
Object beanInstance = descriptor.resolveCandidate(candidateName, requiredType, this);
if (!(beanInstance instanceof NullBean)) {
candidates.put(candidateName, beanInstance);
}
} else if (containsSingleton(candidateName) ||
(descriptor instanceof StreamDependencyDescriptor &&
((StreamDependencyDescriptor) descriptor).isOrdered())) {
Object beanInstance = descriptor.resolveCandidate(candidateName, requiredType, this);
candidates.put(candidateName, (beanInstance instanceof NullBean ? null : beanInstance));
} else {
candidates.put(candidateName, getType(candidateName));
}
}
- 该方法先判断的是,你注入的属性是不是一个对象包含多个对象的那种?
- 当前肯定不是,所以继续往下走。
if (containsSingleton(candidateName) ||
(descriptor instanceof StreamDependencyDescriptor &&
((StreamDependencyDescriptor) descriptor).isOrdered())) {
Object beanInstance = descriptor.resolveCandidate(candidateName, requiredType, this);
candidates.put(candidateName, (beanInstance instanceof NullBean ? null : beanInstance));
}
- 对于该判断咱们只看第一个方法,是否存在于单例池中,那么当前的 singloten 中肯定是不存在 y 这个 bean 的。
- 所以这个判断也走不进去,再继续走到最后一个 if 中:
candidates.put(candidateName, getType(candidateName));
- 我们点进到 getType 方法中,在 getType 方法中只是完成了对于当前注入 bean 的 Class 类型的寻找。
public Class<?> getType(String name, boolean allowFactoryBeanInit) throws NoSuchBeanDefinitionException {
String beanName = transformedBeanName(name);
// Check manually registered singletons.
Object beanInstance = getSingleton(beanName, false);
if (beanInstance != null && beanInstance.getClass() != NullBean.class) {
if (beanInstance instanceof FactoryBean && !BeanFactoryUtils.isFactoryDereference(name)) {
return getTypeForFactoryBean((FactoryBean<?>) beanInstance);
} else {
return beanInstance.getClass();
}
}
// No singleton instance found -> check bean definition.
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// No bean definition found in this factory -> delegate to parent.
return parentBeanFactory.getType(originalBeanName(name));
}
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
// Check decorated bean definition, if any: We assume it'll be easier
// to determine the decorated bean's type than the proxy's type.
BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();
if (dbd != null && !BeanFactoryUtils.isFactoryDereference(name)) {
RootBeanDefinition tbd = getMergedBeanDefinition(dbd.getBeanName(), dbd.getBeanDefinition(), mbd);
Class<?> targetClass = predictBeanType(dbd.getBeanName(), tbd);
if (targetClass != null && !FactoryBean.class.isAssignableFrom(targetClass)) {
return targetClass;
}
}
Class<?> beanClass = predictBeanType(beanName, mbd);
// Check bean class whether we're dealing with a FactoryBean.
if (beanClass != null && FactoryBean.class.isAssignableFrom(beanClass)) {
if (!BeanFactoryUtils.isFactoryDereference(name)) {
// If it's a FactoryBean, we want to look at what it creates, not at the factory class.
return getTypeForFactoryBean(beanName, mbd, allowFactoryBeanInit).resolve();
} else {
return beanClass;
}
} else {
return (!BeanFactoryUtils.isFactoryDereference(name) ? beanClass : null);
}
}
- 然后在获取完类型之后就返回到 addCandidateEntry 方法中,将当前的被注入对象的名称和类型 put 进去:candidates.put(candidateName, getType(candidateName));
- 接着回到 findAutowireCandidates 方法中找完了所有的需要被注入的对象的名称和类型都 addCandidateEntry 完成之后,最终跳回到 doResolveDependency 方法中。
- 可以看到符合我们的预期返回了一个也就是 y,和他的类型。
- 下面就比较关键但是也比较基础了:spring 会判断找出来的被注入对象的个数是否大于 1 表明当前被注入对象的存在别名的情况,所以就会进入到 matchingBeans.get(autowiredBeanName)方法中,get 方法其实调用的就是 getBean 方法,还是那句话有直接返回,没有就去给你 create 一个。
- 然后下面继续由于当前的 y 是没有别名的,所以他的 size == 1,所以会走到 else 中:
else {
// We have exactly one match.
Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
autowiredBeanName = entry.getKey();
instanceCandidate = entry.getValue();
}
- 可以发现很简单昂,就是遍历取出 matchingBeans 中的元素,进行赋值。
- 赋值之后会判断你是否不等于空,并且判断被注入对象的类型是否为 Class 类型。
if (autowiredBeanNames != null) {
autowiredBeanNames.add(autowiredBeanName);
}
if (instanceCandidate instanceof Class) {
instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
}
- 上述的两个条件都是满足的,就会直接走到第 5 行,resolveCandidate 方法其实也是 getBean 的逻辑:
- 下面 getBean 的实现咱们不看了,已经看烂了。
- 那么最后会把得到的被注入对象的类型返回回去,就结束了:
- 这里还要说明一个现象:当一个接口,有两个实现类,都实现了该接口,我在完成属性注入的时候,如果不指定其中一个实现,那么 spring 就会报错,但是我指定了其中一个子实现,那么 spring 并不会报错,这是为啥呢?
- 首先咱们都知道一点就是 spring 在完成属性注入的过程中,首先是寻找类型,如果类型寻找不到的话,就会通过 beanName 去寻找对应的 Bean 然后再完成属性注入。
- 举例:
public interface I {
}
@Component
public class Y implements I{
}
@Component
public class Z implements I{
}
上述的两个子类,Y 和 Z 都实现了 I 这个接口并且添加了 @Component 注解将来会被注入到 spring 容器中,还有一个 X 他会依赖注入 I 接口:
@Component
public class X{
@Autowired
I i;
public void setI(I i) {
System.out.println("i--" + i);
}
}
- 可以看到在 X 中我们并没有执行到底是注入 I 接口下的那个实现子类,所以现在执行肯定会报错,并且意思大致是我 spring 找到了两个实现子类,但是不是你要的是那个?
- 得到的结果 spring 给我们提供的更加详细,连实现子类都和我们说了是那个两个!
- 但是我们将代码改一下,明确的执行是 I 接口下的某个实现子类,比如说是 Z,就不会报错了:
@Component
public class X{
@Autowired
I z;
public void setI(I i) {
System.out.println("i--" + i);
}
}
- spring 是正常运行的,我就不截图了。
- 下面我们就看源码,来知晓 spring 是如何做的,其实执行的流程上面都已经说了,这里只是为上面的这些东西做一个例子,来做支撑。
- 首先就是我们可以看到 spring 在使用类型完成被注入属性的查询之后找到两个,和我们的预期是相符的。
- 然后接着往下走,使用 determineAutowireCandidate 方法开始推断 到底是注入那个 bean:
- 推断过后的结果也和我们的预期是相符的就是 z。
- 最后再通过上述找到的两个符合要求的 bean 集合中也就是 matchingBean 集合,通过 get 的方式获取到,很简单,就是 BeanName 为 key ,beanClass 为 Value。
- 从上述的图片中也可以得出结论,最终会被注入的 bean 是 z。
- 那下面就不多阐述了,其实也就是那个原则,有则 getBean,没有 createBean。
- 但是在这里需要纠正一个点:以前我们会说 spring 中针对于,一个 bean 的寻找是先通过 Type,再通过 Name,来获取到对应的 Bean,其实这样的观点是错误的,或者说是存在偏差的,假如说和上述的情况一下是一个接口,并且该接口下有很多的实现子类,并且这些实现子类,都可以被注入到 spring 容器中,那么 spring 的做法是这样的:
- 首先会通过当前被注入类的类型来寻找对应符合要求的子类 bean,就例如接口 I 就是如此,在寻找被注入类的核心方法 findAutowireCandidates 具体的代码如下:
- 可以看到当前在被寻找的是 I 接口,我们将该方法执行完成就会发现 candidateNames 的结果就是 y 和 z:
- 然后下面就会寻找到这两符合条件的具体的 class,结果可以看 findAutowirteCandidates 的返回:
- 然后才会根据下面中的 instanceCandidate = matchingBeans.get(autowiredBeanName); 方法来获取到当前需要注入的 bean:
- 自此就完成了 bean 的注入,在此并没有用到什么 type 找不到会使用 name 去找。
- 下面我们来看看 spring 是完成延迟加载的,其实也就是所谓的 @Lazy 注解。
@Component
public class X{
@Lazy
@Autowired
Z z;
public void setZ(Z z) {
System.out.println("z--" + z);
}
}
- 在最开始的时候用我们先走完正常的流程,那其实对于 spring 来说添加@Lazy 注解就是一个不太正常的过程,所以我们当时是直接跳过了其中的一行代码:
- 可以看到的是我们上述讲的其实都是下面标黄线的方法:doResolveDependency 方法,而红线的就是完成懒加载的地方。
- 这里我们进入到 ContextAnnotationAutowirteCandidateResolver 方法中:
public Object getLazyResolutionProxyIfNecessary(DependencyDescriptor descriptor, @Nullable String beanName) {
return (isLazy(descriptor) ? buildLazyResolutionProxy(descriptor, beanName) : null);
}
- 看到的是一个三元表达式,首先就是 isLazy(descriptor) 判断当前被注入对象是否是一个懒加载对象?
- 显然 z 是的:
- 如果是则进入到 buildLazyResolutionProxy 方法中,我们只需要看到该方法最后一行创建出来一个代理对象即可:
- 最后跳回到方法执行懒加载方法的最开始的地方:
- ok,到此就完成了懒加载的执行,最后返回的是一个 CGLib 的代理对象。