源码入口

上篇博文中我们看到了将Spring环境中的 BeanPostProcessor找出来,添加到BeanFactory中的beanPostProcessors中,统一维护,本片博文继续往下拓展,看下Spring如何实例化bean,以及如何实现在bean的实例化通过各种各样的后置处理器完成bean的增强

所以本次的程序入口是AbstractApplicationContext中的finishBeanFactoryInitialization(beanFactory);,源码如下,主要做了如下几件事


protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// Initialize conversion service for this context.
// 为上下文初始化类型转换器
if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
beanFactory.setConversionService(
beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
} // 检查上下文中是否存在类型转换器
if (!beanFactory.hasEmbeddedValueResolver()) {
beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
}
// 尽早初始化LoadTimeWeaverAware bean,以便尽早注册它们的转换器。
// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
for (String weaverAwareName : weaverAwareNames) {
getBean(weaverAwareName);
} // Stop using the temporary ClassLoader for type matching.
// 禁止使用临时类加载器进行类型匹配
beanFactory.setTempClassLoader(null); // Allow for caching all bean definition metadata, not expecting further changes
// 允许缓存所有的bean的定义数据
beanFactory.freezeConfiguration(); // Instantiate all remaining (non-lazy-init) singletons.
// 准备实例化bean
beanFactory.preInstantiateSingletons();
}

我们着重看他是如何创建实例化bean的,跟进beanFactory.preInstantiateSingletons();,调用beanFactory的方法准备实例化bean, 这个beanFactory就是Spring默认是bean工厂, DefaultListableBeanFactory, 源码如下:方法不算很长,逻辑也很清楚, 一开始Spring取出当前上下文中所有的BeanName列表,因为在执行到这里之前,已经完成包扫描了所以说这个盛放beanName的list里面存放的就是所有的需要实例化的对象的全集,包含Spring自己的,和程序员自己添加的还包含Aspectj的

所以说,当前方法的目标很明了,就是遍历这个list中的每一个beanName,然后实例化当前beanName相应的bean

当然,如果想实例化,前提是不能是抽象类,不能是接口,非懒加载, 而且针对FactoryBean还有不同的处理模式

public void preInstantiateSingletons() throws BeansException {
if (logger.isDebugEnabled()) {
logger.debug("Pre-instantiating singletons in " + this);
}
//所有bean的名字
// 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.
//todo 遍历一个副本以允许init方法,而init方法反过来注册新的bean定义。
// todo 盛放所有的beanName,所有的需要实例化的beanName都在这里,包括Spring断断续续添加的, Aspectj的, 程序员通过注解标识的
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames); // Trigger initialization of all non-lazy singleton beans...
// todo 触发所有非延迟加载单例beans的初始化,主要步骤为调用getBean
for (String beanName : beanNames) { // todo 合并父类BeanDefinition,可以进入查看
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName); //todo 三个条件,抽象,单例,非懒加载
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) { if (isFactoryBean(beanName)) {
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
// todo 如果是FactoryBean则加上&
// todo 检验是否是 FactoryBean 类型的对象
if (bean instanceof FactoryBean) {
final 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 {
// todo 因为我们没有添加FactoryBean类型的对象, 一般都会进入这个getBean
getBean(beanName);
}
}
}

下面接着跟进getBean(beanName);方法,顾名思义获取Bean,再往下跟下去,就算是本文的正文开始部分了,但是我想在这里提醒自己,一个比较有分量的剧透吧,当前的getBean(beanName)它是有返回值的,一会当我们往下跟进的是时候会发现会存在递归的现象,这一点巧妙的实现了@Autowired处理setter方式实现循环引用

ok,现在继续看代码,经过了几个空方法的传递,我们来到下面的代码中,它主要做了如下几件事

首先将传递进来的name转换成了beanName

原因1: FactoryBean的实现类的存储方式和其他的类完全相同,添加上&是获取不到的, 因此我们将&去掉 原因2: 解决别名的问题

为什么在创建bean之前先调用getSingleton()?

回想一下,现在是Spring启动的过程中,是在准备实例化bean,为什么一开始就来getSingleton(),跟进源码查看这个方法,它最终实现中有一行代码是这样的Object singletonObject = this.singletonObjects.get(beanName);而这个singletonObjects就是微观层面的IOC容器,循环创建刚开始时,IOC确实是空的,但是我前面存在剧透,一开始的getBean()方法是存在递归调用现象的,直接举2个例子: 第一:假如现在在实例化A,结果有发现需要给A注入B, 那Spring是不是得获得B,怎么获得呢? 递归使用getBean(BName)完成, 第二个例子: A被添加上了@Lazy注解,是懒加载的,但是终究有一个会通过getBean(AName)获取A,这是发现A是实例化需要B,B肯定已经实例化完事了,同样是通过递归getBean(BName)实现注入, 在这两个过程中就是getSingleton()保证不会重复创建已经存在的实例

我们关注的重点其实是第二个getSingleton(beanName()->{xxx})

在第二个getSingleton()方法中才是真正的去实例化bean的方法

最后,在当前的方法最后将bean返回了

前面我就是说过了,getBean(beanName)存在递归调用的情况,为什么我会一直说这个事呢,因为如果不知道这个事的话,这些代码看起来是没有头绪的,但是明白这个事,看代码就变得很有逻辑,我在简单总结一下怎个玩这个递归呢? 假设现在通过getBean(AName)来注入A对象,但是呢发现了A依赖B对象,于是在getBean(AName)里面调用getBean(BName),通过这个方法返回出B对象完成A的注入

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException { // 将传递进来的name
final String beanName = transformedBeanName(name);
Object bean; // Eagerly check singleton cache for manually registered singletons.
// 及早的检查一下有没有已经注册了的单例对象
Object sharedInstance = getSingleton(beanName);// todo ::: name=myService时,这次来调用的就是 DefaultSingletonBeanRegistry中的 getSingleton() , 不同之处是多传递了一个true
if (sharedInstance != null && args == null) {
// 如果存在的话,将其取出赋值给bean,后续直接返回这个bean
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
} else {
// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
// 来到这里就说明要获取的bean还没有实例化过
// 于是检验一下,如果是原形,直接抛异常
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
} // Check if bean definition exists in this factory.
// 检查是否存在默认的父工厂
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 {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
} if (!typeCheckOnly) {
// 将当前的beanName存放到AlreadeyCreated这个set集中,标识这个bean被创建了
markBeanAsCreated(beanName);
} try {
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args); // Guarantee initialization of beans that the current bean depends on.
// 确保当前bean所依赖的bean都已经初始化好了
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
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);
}
}
} // Create bean instance.
if (mbd.isSingleton()) {
// 实例化bean
sharedInstance = getSingleton(beanName, () -> {
// 真正的完成bean的创建
return createBean(beanName, mbd, args); }); 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 {
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);
}
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
} // Check if required type matches the type of the actual bean instance.
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.isDebugEnabled()) {
logger.debug("Failed to convert bean '" + name + "' to required type '" +
ClassUtils.getQualifiedName(requiredType) + "'", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;
}

经过了上面一顿扯,然后我们继续往下跟,看看createBean(beanName, mbd, args)方法中是如何实例化我们的Bean的, 上面的方法是在AbstractBeanFactory中,createBean(beanName, mbd, args)是它的抽象方法, 那实现类是哪个呢?

AbstractAutowireCapableBeanFactory,隆重的夸一下这个类,Spring都称赞这个类是有有才华的

todo 总结这个类

在这个方法中,主要做了两件事:两件大事!!!

第一件大事:

在实例化Bean前,第一次调用后置处理器, 这件大事绝对是有历史意义的!!!为啥呢?大家想想,bean还没有创建呢!就已经可以插手bean的创建过程了,不是很刺激吗?接着看回调了什么后置处理器呢? Spring会循环所有的处理器检查当前被遍历的处理器是否是InstantiationAwareBeanPostProcessor类型的,如果是的话呢,就执行这个后置处理器的postProcessBeforeInstantiation(beanClass, beanName);方法

这个postProcessBeforeInstantiation()是允许有返回值的,大家可以想想,这一点是不是有点可怕? 事实也是这样,后置处理器的目的是为了增强对象,而我们却可以在这里返回一个任何东西,狸猫换台子替换掉原始的,还没有被创建的对象,还有一点,就是一旦我们在这里真的是没有返回null,那后续Spring就没有义务在去为我们创建本来应该创建的对象了,代码通过if-else的选择分支会使得当前的对象不再经历其他后置处理器的增强,最终执行它父类的postProcessorAfterInitialization()

补充一点,我们通过@EnableAspectjAutoProxy添加到Spring上下文中的AnnotationAwareAspectjAutoProxyCreator对象其实就是这个类型InstantiationAwareBeanPostProcessor,也就是说在这里这个接口的相关方法会被回调,下面看看他的实现类AbstractAutoProxyCreator对这个before()方法的重写实现,源码如下:

主要逻辑就是找出需要产生代理增强的bean(切面类),和普通的bean, 需要增强的bean放在advisedBeans里面,因为需要增强的bean是需要动态植入其他逻辑的,所以不放在一起

判断当前bean是否是基础类型的,比如: Advice PointCut Advisor AopInfrastructureBean 或者是 切面Aspectj 都算是基础类型,标注这些信息的类,是不会被增强的,标记false

主意啊,上面说的都是作用都是进行了一下标记

//todo 跟进来
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
Object cacheKey = getCacheKey(beanClass, beanName); if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
if (this.advisedBeans.containsKey(cacheKey)) {
return null;
}
// todo 亮点就是在这里, 如果是我们切面类来到这里,条件是满足的
// todo advicedBeans 见名知意: 通知beans
// todo Spring用它标识, 被放在这个方法中的类,全部都不会被增强
// todo 满足什么条件时,通过检查呢? 就是检查是否标记有 @Aspectj @Before ... 等注解 // todo 说的再直接一点, 就是返回了null, 表示当前的切面仍然需要按照正常的流程创建出来,但是这里进行标记了
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
} // Create proxy here if we have a custom TargetSource. todo 如果我们有一个自定义的TargetSource,在这里创建代理
// Suppresses unnecessary default instantiation of the target bean: // todo 抑制不必要的目标bean的默认实例化:
// The TargetSource will handle target instances in a custom fashion. todo TargetSource将以自定义方式处理目标实例。
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
if (targetSource != null) {
if (StringUtils.hasLength(beanName)) {
this.targetSourcedBeans.add(beanName);
}
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
} return null;
}

经过上面的标记,在哪里产生的代理对象呢?其实是在AbstractAutowireCapeableBeanFactory中的initializeBean()方法中实现的postProcessAfterInitialization()实现的,在本文的末尾展开讨论


第二件大事: 实例化对象, 继续跟进

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException { if (logger.isDebugEnabled()) {
logger.debug("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.
// todo 做各种各样的属性值的赋值, 比如这种 通过Spring的Bean传递给Spring框架的值 ==> bd.setPropertyValue("aaa")
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
} // Prepare method overrides.
// todo 处理 lookup-method 和 replace-method 配置,Spring 将这两个配置统称为 override method
try {
mbdToUse.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
beanName, "Validation of method overrides failed", ex);
} try {
// todo 在实例化之前完成一次解析操作,这也是
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 {
//todo 调用 doCreateBean 创建bean
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isDebugEnabled()) {
logger.debug("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
}

我们继续跟进doCreateBean(beanName, mbdToUse, args);方法, 同样是本类AbstarctAutowireCapableBeanFactory的方法,源码如下: 这个方法也是无与伦比的重要,那这个方法中做了什么事情呢?如下

  • 创建一个 BeanWrapper,用来存放bean+其他属性
  • 创建bean的实例,封装进上面的BeanWrapper中
  • 分两次调用处理处理器
  • 设置属性,填充属性
  • 经过AOP处理,将原生对象转换成Proxy
  • 返回BeanWrapper

因为这个方法简直太重要了,上面列举的每一点都值得我们仔细分析,我们每一条的分析都写在下面代码的下面

	protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException { // Instantiate the bean.
// todo BeanWrapper 用来包装bean
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
// todo 一开始 factoryBeanInstanceCache 这个map中是没有值的, 所以进入下面的if
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) { instanceWrapper = createBeanInstance(beanName, mbd, args);
}
// todo !!!!!!!!这里获取出来的对象是原生对象!!!!!!!!!!!!
final 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 { 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.
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isDebugEnabled()) {
logger.debug("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
} addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
} // Initialize the bean instance.
Object exposedObject = bean; // todo 到目前为止还是原生对象 //todo 用来填充属性
//设置属性,非常重要
populateBean(beanName, mbd, instanceWrapper); // todo 经过AOP处理,原生对象转换成了代理对象,跟进去
//执行后置处理器,aop就是在这里完成的处理
exposedObject = initializeBean(beanName, exposedObject, mbd); return exposedObject;
}

实例化对象

我把源码贴在了下面,下面方法的目的就是选出一个策略来实例化一个对象, 那有什么策略呢? 这就看程序员是怎么配置的了, 程序员可以配置工厂方法,指定构造方法,或者是程序员没有做出任何干涉,让Spring按自己的方式去实例化

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
// Make sure bean class is actually resolved at this point.
Class<?> beanClass = resolveBeanClass(mbd, beanName); /**
* todo 检测一个类的访问权限, Spring默认是 允许访问非public类型的方法
*/
if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
} /**
* 创建一个bean的快捷方式
*/
boolean resolved = false;
boolean autowireNecessary = false; // todo 是否是必须自动装配
if (args == null) {
synchronized (mbd.constructorArgumentLock) { // todo
if (mbd.resolvedConstructorOrFactoryMethod != null) {
resolved = true;
//如果已经解析了构造方法的参数,则必须要通过一个带参构造方法来实例
autowireNecessary = mbd.constructorArgumentsResolved;
}
}
} if (resolved) {
if (autowireNecessary) {// todo 如果是需要自动注入的,就使用构造方法自动注入
// 通过构造方法自动装配的方式构造 bean 对象
return autowireConstructor(beanName, mbd, null, null);
}
else {
//通过默认的无参构造方法进行
//todo 通过默认的无参构造方法
return instantiateBean(beanName, mbd);
}
} Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
// todo 使用特定的构造方法完成自动装配
return autowireConstructor(beanName, mbd, ctors, args);
} // No special handling: simply use no-arg constructor.
//todo 使用默认的无参构造方法进行初始化
return instantiateBean(beanName, mbd);
}

我们主要关注上面代码的 determineConstructorsFromBeanPostProcessors(beanClass, beanName)这个方法的目的就是推测实例化需要的构造方法, 为什么需要先推测构造方法呢? 因为Spring实例化对象时,需要使用特定的构造方法才能反射出对象,这时如果程序员指定了带参数的构造方法,spring就会使用这个构造方法实例化对象,如果程序员提供了一个不带任何参数的默认构造方法,Spring会忽略它,按自己的逻辑使用默认的无参构造

所以上面的if-else分支目的很明确,先是尝试获取全部的构造方法,然后看看有没有解析出来构造方法, 解析出来的话,就使用第一种逻辑,按照 特殊的构造方法模式进行处理,有解析出来,就使用默认的构造方法

我们进一步跟进这个determineConstructorsFromBeanPostProcessors(beanClass, beanName)方法,可以发现方法里面又是一波后置处理器的回调工作,这次选出的后置处理器的类型是SmartInstantiationAwareBeanPostProcessor,见名知意,这种处理器可以感知到心仪的构造方法,它的主要实现逻辑就是,查看这个将被实例化的对象中有没有添加了@Lookup注解的方法,有的话为这种方法生成代理,循环遍历所有的构造方法,看看这些构造方法上存在不存在@Value或者@Autowired注解,因为这些注解中存在required=true,只要存在这种注解,Spring就将他当成候选的构造方法,但是如果存在多个的话,Spring也不知道到底用哪一个,但是在这里Spring会将所有符合条件的都选出来,但是一般情况下,都可以正确的选出合适的构造

选择出合适构造方法之后,就根据不同的构造方法,选择使用不同的方式去实例化对象, 都有什么方式呢? 两种方式

方式1:

这是比较复杂的方式,此时Spring需要在这个方法内存比较好几个候选的构造方法,计算它们的差异值,最终值最小的构造函数就是将要用来实例化对象的构造函数,当然很可能是选不出合适的构造函数的,于是Spring没有立即抛出异常,而是将异常添加进bean工厂的suppressedExceptions这个set集合中

如果成功的选择出来一个构造函数,就会使用jdk原生的反射机制,实例化一个对象

 autowireConstructor(beanName, mbd, ctors, args);

方式2:

直接使用JDK原生的反射机制,实例化一个对象

instantiateBean(beanName, mbd);

小结:

代码看到这里,方才说的有才华的那个类AbstactAutowiredCapatableBeanFactory中的doCreateBean()方法的 instanceWrapper = createBeanInstance(beanName, mbd, args); 也就看完了, 到这里也就知道了,Spring会先把所有满足条件的bean全部实例化存放起来,这里的对象是百分百原生java对象,不掺水不含糖

接着往下看,我把代码重写贴出来, 下面还有五件大事,这四件大事说完了,本文就结束了

第一: 是applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName); 回调后置处理器,进行有关注解的缓存操作

第二: 是getEarlyBeanReference(beanName, mbd, bean) 获取一个提早暴露的beanDefinition对象,用于解决循环依赖问题

第三: 将刚才创建原生java对象存放一个叫singletonFactories的map中,这也是为了解决循环依赖而设计的数据结构,举个例子: 现在准备创建A实例, 然后将A实例添加到这个singletonFactories中, 继续运行发现A实例依赖B实例,于是在创建B实例,接着又发现B实例依赖A实例,于是从singletonFactories取出A实例完成装配,再将B返回给A,完成A的装配


synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try { 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.
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isDebugEnabled()) {
logger.debug("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
} // todo 重点再来看这个 addSingleFactory
// todo 将原始对象new出来之后放到了 这个方法中的map中
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
} // Initialize the bean instance.
Object exposedObject = bean; // todo 到目前为止还是原生对象
try {
//todo 用来填充属性
//设置属性,非常重要
populateBean(beanName, mbd, instanceWrapper); // todo 经过AOP处理,原生对象转换成了代理对象,跟进去
//执行后置处理器,aop就是在这里完成的处理
exposedObject = initializeBean(beanName, exposedObject, mbd);
}

接着看 populateBean(beanName, mbd, instanceWrapper);方法,这个方法很重要,就是在这个方法中进行bean属性的装配工作,啥意思呢? 比如现在装配A实例,结果发现A实例中存在一个属性是B实例,这是就得完成自动装配的工作,源码如下:

如果仔细看,就会发现两个事:

第一: 如果不出意外,就会出现两次后置处理器的回调,第一后置处理器的回调是判断当前的bean中是否存在需要装配的属性,而第二波后置处理器的回调就是实打实的去完成装配的动作

第二: 下面的第一个处理器其实就是spring启动过程中第一个回调的处理器,只不过调用了这个处理器的不同的方法postProcessAfterInstantiation(),默认返回ture表示按照正常的流程装配对象的属性,返回false,表示不会继续装配对象中的任何属性

而我们则继续关注下面方法中的第二个后置处理器的,看看Spring是如何完成属性的自动装配的,关于这部分的跟踪,我写在下面代码的后面

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.
boolean continueWithPropertyPopulation = true; if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
//todo 进行了强转, InstantiationAwareBeanPostProcessor这个接口前面说过
// todo 只要是通过这个接口返回出来的bean Spring不在管这个bean,不给他装配任何属性
//todo 当前这里没有用它这个变态的特性
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
// todo postProcessAfterInstantiation()默认是返回true, 加上! 表示false
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
continueWithPropertyPopulation = false;
break;
}
}
}
} if (!continueWithPropertyPopulation) {
return;
}
// todo Spring内部可以对BeanDefinition进行设置值, 参照自定义的 BeanFactory中获取到BeanDefinition.getPropertyValue().addXXX();
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null); // todo 判断当前bean的解析模型是 byName 还是 byType
// todo 再次验证了::: 当程序员直接使用@Autowired注解时, 既不是ByName 也不是ByType, 而是No
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME || mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// Add property values based on autowire by name if applicable.
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// Add property values based on autowire by type if applicable.
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
} boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE); if (hasInstAwareBpps || needsDepCheck) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
//todo 获取出对象的所有set get方法,现在是有一个 getClass()方法,因为继承了Object, 没什么其他卵用
PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
if (hasInstAwareBpps) { for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) { pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvs == null) {
return;
}
}
}
}
if (needsDepCheck) {
checkDependencies(beanName, mbd, filteredPds, pvs);
}
} if (pvs != null) {
applyPropertyValues(beanName, mbd, bw, pvs);
}
}

好,继续跟进 pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(),,看看spring如何完成属性的自动装配,当然,还是那句话,如果我们直接跟进去这个方法进入的是InstantiationAwareBeanPostProcessor抽象接口抽象方法,而我们关注的是它的实现类AutowiredAnnotationBeanDefinitionPostProcessor的实现,打上断点依次跟进

	@Override
public PropertyValues postProcessPropertyValues(
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException { InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
try {
// todo 跟进来, 目的是 为 beanName 填充上属性 bean
metadata.inject(bean, beanName, pvs);

跟进

metadata.inject(bean, beanName, pvs);

源码如下:

可以这样理解,在下面的方法中遍历当前对象中所有可能需要依赖注入的属性字段

	public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
// todo 这里的 InjectedElement 表示单个的需要注入的元素对象
Collection<InjectedElement> checkedElements = this.checkedElements;
Collection<InjectedElement> elementsToIterate = (checkedElements != null ? checkedElements : this.injectedElements);
if (!elementsToIterate.isEmpty()) {
for (InjectedElement element : elementsToIterate) {
if (logger.isDebugEnabled()) {
logger.debug("Processing injected element of bean '" + beanName + "': " + element);
}
//todo 跟进 AutowiredAnnotationBeanPostProcessor 对这个方法的实现, 在600多行处
element.inject(target, beanName, pvs);
}
}
}

跟进这个inject() 我是手动删除了这个方法中其他的很多判断,仅仅保存下来了下面我们关注的逻辑,逻辑很清楚,上面的代码中不是在遍历所有需要自动装配的field吗?如果找到了的话,就得完成自动装配,自动装配什么呢? 其实就是自动装配上当前对象依赖的其他的对象而已,因为我们使用的后置处理器是AutowireAnnotationBeanPostProcessor通过下面的代码就能得出结论就是@Autowired默认情况下是通过反射实现的自动装配

	// todo 来到这里
@Override
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Field field = (Field) this.member;
Object value;
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
if (value != null) {
ReflectionUtils.makeAccessible(field);
field.set(bean, value);
}
}
}

我们一路往下跟进resolveDependency()我们关注这个方法如下代码:

if (instanceCandidate instanceof Class) {// todo !!!!!当运行到这行代码时, myService还没有被实例化(singletonObjects中没有) 执行完这一个行代码之后, IndexDao1完成了对myService的装配
instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
}

跟进这个resolveCandidate()源码如下:

很直接发现,出现的递归的现象,这其实解析清楚了Spring是如何完成属性注入的,就是只不过前前后后很多接口很多类,会扰乱这个阅读的过程

public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory)
throws BeansException {
// todo 从bean工厂的获取, beanName = myService requiredType = com.changwu...OrderService2 , 跟进去这个方法, 他调用了AbstractBeanFactory中的getBean(){ doGetBean();}
return beanFactory.getBean(beanName);
}

完成装配后,其实现在的对象依然是原生的java对象 回到AbstractAutowireCapableBeanFactory中的initializeBean()方法,源码如下, 看了下面的代码就是知道了为什么applyBeanPostProcessorsBeforeInitializationinit()applyBeanPostProcessorsAfterInitialization()之间的调用顺序了

还有最后一个秘密需要揭开: Spring的AOP不是产生了代理对象? 那什么时候完成的代理呢?毕竟从我开始写这篇文章到最后都没有看到,其实AOP的实现就在下面的代码中

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean);
} Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
//todo 执行全部的后置处理器的 Before方法
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
} try {
// todo 执行所有的init方法
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
// todo 执行所有的后置处理器的 after方法
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
} return wrappedBean;
}

我们在前面知道当遇到这个AbstractAutoProxyCreator时,回调它的before()方法时,仅仅是标记哪些对象需要进行增强哪些对象不需增强,而没有立即生成代理对象

现在我们关注这行代码 wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); ,生成代理对象的逻辑就在这里面

@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
// todo 进入
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}

看这个方法wrapIfNecessary(bean, beanName, cacheKey);最终会进入这个实现中

大家可以看到Spring为bean生成了代理对象,默认会先检查被代理的对象有没有实现接口,如果实现了接口,就是用jdk动态代理,否则就看看有没有cglib的相关依赖,如果存在的相关依赖而没有实现接口,就会使用cglib的代理模式

另外,补充通过编码的方式控制 下面的if条件

  • config.isOptimize() -> 可以通过XMl配置, 默认false
  • config.isProxyTargetClass() -> @EnableAspectjAutoPeoxy(true) 默认也是false
@SuppressWarnings("serial")
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
//todo 目标对象是一个接口, 同样是使用jdk的动态代理
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
// todo 所以默认使用的是 jdk的动态代理
return new JdkDynamicAopProxy(config);
}
}

Spring 源码阅读之 深入理解 finishBeanFactoryInitialization的更多相关文章

  1. 初始化IoC容器(Spring源码阅读)

    初始化IoC容器(Spring源码阅读) 我们到底能走多远系列(31) 扯淡: 有个问题一直想问:各位你们的工资剩下来会怎么处理?已婚的,我知道工资永远都是不够的.未婚的你们,你们是怎么分配工资的? ...

  2. Spring源码阅读-ApplicationContext体系结构分析

    目录 继承层次图概览 ConfigurableApplicationContext分析 AbstractApplicationContext GenericApplicationContext Gen ...

  3. Spring源码阅读笔记02:IOC基本概念

    上篇文章中我们介绍了准备Spring源码阅读环境的两种姿势,接下来,我们就要开始探寻这个著名框架背后的原理.Spring提供的最基本最底层的功能是bean容器,这其实是对IoC思想的应用,在学习Spr ...

  4. Spring源码阅读 之 配置的读取,解析

    在上文中我们已经知道了Spring如何从我们给定的位置加载到配置文件,并将文件包装成一个Resource对象.这篇文章我们将要探讨的就是,如何从这个Resouce对象中加载到我们的容器?加载到容器后又 ...

  5. Bean实例化(Spring源码阅读)-我们到底能走多远系列(33)

    我们到底能走多远系列(33) 扯淡: 各位:    命运就算颠沛流离   命运就算曲折离奇   命运就算恐吓着你做人没趣味   别流泪 心酸 更不应舍弃   ... 主题: Spring源码阅读还在继 ...

  6. Sping学习笔记(一)----Spring源码阅读环境的搭建

    idea搭建spring源码阅读环境 安装gradle Github下载Spring源码 新建学习spring源码的项目 idea搭建spring源码阅读环境 安装gradle 在官网中下载gradl ...

  7. 搭建 Spring 源码阅读环境

    前言 有一个Spring源码阅读环境是学习Spring的基础.笔者借鉴了网上很多搭建环境的方法,也尝试了很多,接下来总结两种个人认为比较简便实用的方法.读者可根据自己的需要自行选择. 方法一:搭建基础 ...

  8. Spring源码阅读笔记

    前言 作为一个Java开发者,工作了几年后,越发觉力有点不从心了,技术的世界实在是太过于辽阔了,接触的东西越多,越感到前所未有的恐慌. 每天捣鼓这个捣鼓那个,结果回过头来,才发现这个也不通,那个也不精 ...

  9. (转) Spring源码阅读 之 Spring整体架构

    标签(空格分隔): Spring 声明:本文系转载,原地地址:spring framework 4 源码阅读 Spring骨架 Spring的骨架,也是Spring的核心包.主要包含三个内容 cont ...

随机推荐

  1. WordPress对接微信小程序遇到的问题

    1.文章内容中的“<”和“>”字符显示问题 小程序是使用“wxPares工具来实现html转wxml的,如果你的文本包含了代码比如xml会携带<>符号,程序会将其转化,造成解析 ...

  2. 生产环境轻量级dns服务器dnsmasq搭建文档

    dnsmasq搭建文档 一.生产环境域名解析问题 之前生产环境设备较少,是通过维护master(192.168.1.1)设备的hosts文件实现的.每次新增设备后,需要在master的hosts文件中 ...

  3. Android Studio [RecyclerView/列表视图]

    LinearRecyclerViewActivity.java package com.xdw.a122.recyclerview; import android.graphics.Rect; imp ...

  4. grep 命令使用

    grep是Linux中最常用的"文本处理工具"之一,用于在文本中查找指定的字符串. 语法: grep [OPTION]... PATTERN [FILE]... 参数: -i:在搜 ...

  5. nginx的ngx_http_geoip2模块以精准禁止特定地区IP访问

    要求:对网站的信息,比如某个访问节点不想国内或者国外的用户使用,禁止国内或者国外或者精确到某个城市的那种情况. 解决方式:1.Cloudfalre来实现禁止特定国家的ip访问,比较简单,但是需要mon ...

  6. windows下查看进程及结束进程命令

    windows下查看进程及结束进程命令 1)查看占用8080端口的进程号 >netstat –aon | findstr “8080” 结果:TCP    0.0.0.0:8080        ...

  7. php使用正则表达式提取字符串中尖括号、小括号、中括号、大括号中的字符串

    $str="你好<我>(爱)[北京]{天安门}"; echo f1($str); //返回你好 echo f2($str); //返回我 echo f3($str); ...

  8. ELK 学习笔记之 elasticsearch环境搭建

    ELK概述: ElasticSearch是个开源分布式搜索引擎,它的特点有:分布式,零配置,自动发现,索引自动分片,索引副本机制,restful风格接口,多数据源,自动搜索负载等 Logstash是一 ...

  9. markdown + 七牛云,让写文更容易

    常常写博文的人, 总有这样的烦恼: * 文章格式问题,各种文本编辑器格式不统一,在一处写好的文章复制到其他编辑器中格式错乱 * 图片问题,在不同的平台的图片需要重复上传,如果多平台发布很繁琐 由于这样 ...

  10. Dubbo学习系列之十五(Seata分布式事务方案TCC模式)

    上篇的续集. 工具: Idea201902/JDK11/Gradle5.6.2/Mysql8.0.11/Lombok0.27/Postman7.5.0/SpringBoot2.1.9/Nacos1.1 ...