SpringloC容器的依赖注入源码解析(2)—,mysql事务面试题

}

}

if (!typeCheckOnly) {

markBeanAsCreated(beanName);

}

try {

final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);

checkMergedBeanDefinition(mbd, beanName, args);

// Guarantee initialization of beans that the current bean depends on.

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.

// 如果BeanDefinition为单例

if (mbd.isSingleton()) {

// 这里使用了一个匿名内部类,创建Bean实例对象,并且注册给所依赖的对象

sharedInstance = getSingleton(beanName, () -> {

try {

return createBean(beanName, mbd, args);

}

catch (BeansException ex) {

// Explicitly remove instance from singleton cache: It might have been put there

// eagerly by the creation process, to allow for circular reference resolution.

// Also remove any beans that received a temporary reference to the bean.

destroySingleton(beanName);

throw ex;

}

});

bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);

}

else if (mbd.isPrototype()) {

// It’s a prototype -> create a new instance.

Object prototypeInstance = null;

try {

beforePrototypeCreation(beanName);

prototypeInstance = createBean(beanName, mbd, args);

}

finally {

afterPrototypeCreation(beanName);

}

bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);

}

else {

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.isTraceEnabled()) {

logger.trace(“Failed to convert bean '” + name + “’ to required type '” +

ClassUtils.getQualifiedName(requiredType) + “'”, ex);

}

throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());

}

}

return (T) bean;

}

第一行先将方法传入的name转换成容器真实的beanName,回顾之前,可以通过三种形式获取beanName,一个是原始的beanName,一个是加了&的,一个是别名

final String beanName = transformedBeanName(name);

Object bean;

进入到transformedBeanName方法里面

protected String transformedBeanName(String name) {

return canonicalName(BeanFactoryUtils.transformedBeanName(name));

}

public static String transformedBeanName(String name) {

Assert.notNull(name, “‘name’ must not be null”);

if (!name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {

return name;

}

return transformedBeanNameCache.computeIfAbsent(name, beanName -> {

do {

beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());

}

while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));

return beanName;

});

}

先看看是否是以&前缀开始的,不是的话直接返回name,是的话将&全部去掉。

再进入到canonicalName方法里:

public String canonicalName(String name) {

String canonicalName = name;

// Handle aliasing…

String resolvedName;

do {

// 根据别名获取真正的beanName,传入beanName就啥都获取不到

resolvedName = this.aliasMap.get(canonicalName);

if (resolvedName != null) {

canonicalName = resolvedName;

}

}

while (resolvedName != null);

return canonicalName;

}

如果能在map里找到真名,则证明传入的是别名,为了防止是别名的别名,这里有一个递归操作直到找不到,此时为真名


回到doGetBean,获取到beanName之后就尝试去缓存获得Bean实例

Object sharedInstance = getSingleton(beanName);

进入方法里

public Object getSingleton(String beanName) {

return getSingleton(beanName, true);

}

第二个参数控制是否允许非延迟加载,true表示允许立即加载

protected Object getSingleton(String beanName, boolean allowEarlyReference) {

// 尝试从一级缓存里面获取完备的Bean

Object singletonObject = this.singletonObjects.get(beanName);

// 如果完备的单例还没有创建出来,创建中的Bean的名字会被保存在singletonsCurrentlyInCreation中

// 因此看看是否正在创建

if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {

// 尝试给一级缓存对象加锁,因为接下来就要对缓存对象操作了

synchronized (this.singletonObjects) {

// 尝试从二级缓存earlySingletonObjects这个存储还没进行属性添加操作的Bean实例缓存中获取

singletonObject = this.earlySingletonObjects.get(beanName);

// 如果还没有获取到并且第二个参数为true,为true则表示bean允许被循环引用

if (singletonObject == null && allowEarlyReference) {

// 从三级缓存singletonFactories这个ObjectFactory实例的缓存里尝试获取创建此Bean的单例工厂实例

ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);

// 如果获取到工厂实例

if (singletonFactory != null) {

// 调用单例工厂的getObject方法返回对象实例

singletonObject = singletonFactory.getObject();

// 将实例放入二级缓存里

this.earlySingletonObjects.put(beanName, singletonObject);

// 从三级缓存里移除

this.singletonFactories.remove(beanName);

}

}

}

}

return singletonObject;

}

该方法在DefaultSingletonBeanRegistry类里,负责对容器创建出来的单例进行注册,从一个map (singletonObjects)中尝试获取key为beanName的单例实例,其中singletonObjects就是一级缓存。

if (singletonObject == null && isSingletonCurrentlyInCreation(beanName))

保证从一级缓存里没有获取到相关实例,并且该实例一定是当前正在创建的实例

public boolean isSingletonCurrentlyInCreation(String beanName) {

return this.singletonsCurrentlyInCreation.contains(beanName);

}

isSingletonCurrentlyInCreation方法会去查询一个set,看看正在创建的单例bean名单里是否有beanName,如果此时bean是单例的且正在创建,则会给一级缓存加一个同步锁,之后再操作另外两层缓存。

为了提高性能,二级缓存earlySingletonObjects和三级缓存singletonFactories都是HashMap,因为前面已经对一级缓存加了锁,所以是安全的。

首先尝试从二级缓存里获取Bean实例

singletonObject = this.earlySingletonObjects.get(beanName);

二级缓存里存的是还没有实例化的Bean(没执行populate)

之后又可能从三级缓存singletonFactories里尝试获取,这里存储的是Bean对应的ObjectFactory实例(工厂),后续可以通过getObject()来创建Bean的实例,由于Bean实例的属性可能还没有注入,所以先将其放入二级缓存里,然后从三级缓存里清除(保证三级缓存里只有一级保存Bean实例,避免重复创建Bean实例打破单例),之所以没有注入的Bean也要返回的原因是为了打破循环依赖问题。


回到doGetBean,

请添加图片描述

如果先前已经创建过单例Bean的实例,并且调用的getBean方法传入的参数为空,则执行理面的逻辑,args之所以要求为空是因为,如果有args,则需要做进一步赋值,因此无法直接返回。

无论是否有循环引用,最终都是要调用getObjectForBeanInstance返回Bean实例,但由于我们可能获取到的是工厂而非实例,所以还可能要多一步由工厂创建bean实例的步骤。

protected Object getObjectForBeanInstance(

Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {

// Don’t let calling code try to dereference the factory if the bean isn’t a factory.

if (BeanFactoryUtils.isFactoryDereference(name)) {

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

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

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

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

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

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Java)
img

总结

本文从基础到高级再到实战,由浅入深,把MySQL讲的清清楚楚,明明白白,这应该是我目前为止看到过最好的有关MySQL的学习笔记了,我相信如果你把这份笔记认真看完后,无论是工作中碰到的问题还是被面试官问到的问题都能迎刃而解!

MySQL50道高频面试题整理:

-1712112348519)]
[外链图片转存中…(img-OU4uvfll-1712112348520)]
[外链图片转存中…(img-Ap7Si8eY-1712112348520)]
[外链图片转存中…(img-i0Vt29Ml-1712112348521)]

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

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

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Java)
[外链图片转存中…(img-lFwri9Du-1712112348522)]

总结

本文从基础到高级再到实战,由浅入深,把MySQL讲的清清楚楚,明明白白,这应该是我目前为止看到过最好的有关MySQL的学习笔记了,我相信如果你把这份笔记认真看完后,无论是工作中碰到的问题还是被面试官问到的问题都能迎刃而解!

MySQL50道高频面试题整理:

[外链图片转存中…(img-SfzbrFBo-1712112348522)]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值