SpringloC容器的依赖注入源码解析(4)

catch (LinkageError err) {

throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), err);

}

}

如果是注解方式定义的话,会执行

if (mbd.hasBeanClass()) {

return mbd.getBeanClass();

}

如果是xml方式定义的话,会执行来做解析的工作

doResolveBeanClass(mbd, typesToMatch);

doResolveBeanClass方法里有很多classLoader,即调用事先保存的各种各样的类加载器去尝试加载class对象,由于class对象和类加载器一一对应,所以class对象会存在于其中的一个类加载器中,通过该加载器找到了对应的class对象之后,就会用对应的classLoader加载出对象来


回到createBean,下面如果获取到的class对象不为空,并且当前的BeanDefinition在解析之前没有class对象,但是却有className时(对应xml方式),此时就会拷贝一个RootBeanDefinition的副本,然后给这个副本设置上先前解析出来的class对象实例。

这样做的目的是不希望将解析的class绑定到缓存里的BeanDefinition,因为class有可能是每次都需要动态解析出来的。

if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {

mbdToUse = new RootBeanDefinition(mbd);

mbdToUse.setBeanClass(resolvedClass);

}


注解方式不会执行上面那个if,所以会来到下面这个逻辑

mbdToUse.prepareMethodOverrides();

该方法判断BeanDefinition是否有定义方法的覆盖

public void prepareMethodOverrides() throws BeanDefinitionValidationException {

// Check that lookup methods exist and determine their overloaded status.

if (hasMethodOverrides()) {

getMethodOverrides().getOverrides().forEach(this::prepareMethodOverride);

}

}

prepareMethodOverride先获取需要覆盖的方法数量,如果count==1则不存在重载,在使用CGLIB增强阶段就不需要进行校验了,直接找到某个方法进行增强即可,否则在增强阶段还需要做特殊的处理

protected void prepareMethodOverride(MethodOverride mo) throws BeanDefinitionValidationException {

int count = ClassUtils.getMethodCountForName(getBeanClass(), mo.getMethodName());

if (count == 0) {

throw new BeanDefinitionValidationException(

“Invalid method override: no method with name '” + mo.getMethodName() +

“’ on class [” + getBeanClassName() + “]”);

}

else if (count == 1) {

// Mark override as not overloaded, to avoid the overhead of arg type checking.

mo.setOverloaded(false);

}

}

样例:

对于replaced-method,会去验证一下MyTestBean里是否有changedMethod这个即将被替换的方法,对于lookup-method,如果该属性存在,则会去判断一下Teacher这个bean里是否有getUserBean这个方法,没有则报错。


回到createBean,通过方法覆盖验证之后来到

Object bean = resolveBeforeInstantiation(beanName, mbdToUse);

主要是执行某些类型的后置处理器的操作。

@Nullable

protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {

Object bean = null;

// 如果beforeInstantiationResolved还没有设置或者是false(说明还没有进行需要在实例化前执行的操作)

if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {

// Make sure bean class is actually resolved at this point.

// mbd.isSyntheticO默认是false

// 如果注册了InstantiationAwareBeanPostProcessors类型的BeanPostProcessor

if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {

Class<?> targetType = determineTargetType(beanName, mbd);

if (targetType != null) {

bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);

if (bean != null) {

bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);

}

}

}

mbd.beforeInstantiationResolved = (bean != null);

}

return bean;

}

Spring在AOP过程中产生的中间代理类就是isSynthetic的,此时的targetType是自己定义的WelcomeController,进入到applyBeanPostProcessorsBeforeInstantiation方法里:

protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {

for (BeanPostProcessor bp : getBeanPostProcessors()) {

if (bp instanceof InstantiationAwareBeanPostProcessor) {

InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;

Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);

if (result != null) {

return result;

}

}

}

return null;

}

这里使用了责任链模式(Spring中的后置器基本都会使用责任链模式来处理),依次遍历实现了InstantiationAwareBeanPostProcessor接口的BeanPostProcessor实现类,并调用类里面的postProcessBeforeInstantiation看看谁来负责对bean实例的创建,如果去处理了并有了结果,就会立即返回,只要某一个后置处理器返回了结果,就会阻止后面后置处理器的执行。

只要

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

最后总结我的面试经验

2021年的金三银四一眨眼就到了,对于很多人来说是跳槽的好机会,大厂面试远没有我们想的那么困难,摆好心态,做好准备,你也可以的。

另外,面试中遇到不会的问题不妨尝试讲讲自己的思路,因为有些问题不是考察我们的编程能力,而是逻辑思维表达能力;最后平时要进行自我分析与评价,做好职业规划,不断摸索,提高自己的编程能力和抽象思维能力。

BAT面试经验

实战系列:Spring全家桶+Redis等

其他相关的电子书:源码+调优

面试真题:


《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门即可获取!
]

BAT面试经验

实战系列:Spring全家桶+Redis等

[外链图片转存中…(img-2LoVmyfT-1712218514831)]

其他相关的电子书:源码+调优

[外链图片转存中…(img-XNXKvF39-1712218514831)]

面试真题:

[外链图片转存中…(img-ss5hjEl2-1712218514832)]

[外链图片转存中…(img-D41pxP4E-1712218514832)]
《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门即可获取!

  • 29
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值