前言
本文旨在分析在Spring容器启动之时,如何将注册类bean注入IOC容器中,意义重大,详细看以下源码:
(1)BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
(2)definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
(3)BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
----该段代码位于org.springframework.context.annotation.AnnotatedBeanDefinitionReader#doRegisterBean内
1.1 BeanDifinitionHolder的意义与作用
(1)这行代码是BeanDifinitionHolder类的构造器,其内部结构为:
public BeanDefinitionHolder(BeanDefinition beanDefinition, String beanName) {
this(beanDefinition, beanName, null);
}
很明显,这是调用了本类的另一个重载的构造器,源码为:
public BeanDefinitionHolder(BeanDefinition beanDefinition, String beanName, @Nullable String[] aliases) {
//beanDefinition的非空判断,为空抛出一个运行时异常
Assert.notNull(beanDefinition, "BeanDefinition must not be null");
//beanName的非空判断,为空抛出一个运行时异常
Assert.notNull(beanName, "Bean name must not be null");
this.beanDefinition = beanDefinition;
this.beanName = beanName;
this.aliases = aliases;
}
说了这么多,不禁想问BeanDifinitionHolder类到底是用来干嘛的呢?下面这段英文应该会给你答案。
Holder for a BeanDefinition with name and aliases.
Can be registered as a placeholder for an inner bean
Can also be used for programmatic registration of inner bean
definitions. If you don't care about BeanNameAware and the like,
registering RootBeanDefinition or ChildBeanDefinition is good enough.
粗略翻译一下:BeanDifinitionHolder这个类是一个包含name和aliases(别名)的BeanDifinition的拥有者。
它可以注册为一个内部bean的占位符,也可以用来对内部bean定义的编程注册。
另外,如果你不关心BeanNameAware,则注册为RootBeanDefinition或ChildBeanDefinition就足够了。
1.2
对代码(2)进行分析,下沉底层:
//scopeMetadata来自于之前对Scope标签处理中产生的数据
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
--->
static BeanDefinitionHolder applyScopedProxyMode(
ScopeMetadata metadata, BeanDefinitionHolder definition, BeanDefinitionRegistry registry) {
//获得在前面处理@Scope注释代码块中写入的proxyMode值,也就是获取其代理模式
ScopedProxyMode scopedProxyMode = metadata.getScopedProxyMode();
// 如果是没有代理的模式,直接返回definition
if (scopedProxyMode.equals(ScopedProxyMode.NO)) {
return definition;
}
//proxyTargetClass是用来判断是不是使用了CGLIB这种代理方式
boolean proxyTargetClass = scopedProxyMode.equals(ScopedProxyMode.TARGET_CLASS);
//下面这个方法将会进入Spring-AOP包中,应用相应的代理,其实这个地方可以判断出待注入的
//bean中到底使用了哪种代理方式,因为这个时候可以排除三个,只能剩下一种方式。详见1.3
//该方法返回一个BeanDefinitionHolder实例对象,而且该对象包装了待注入的bean
return ScopedProxyCreator.createScopedProxy(definition, registry, proxyTargetClass);
}
注释:ScopedProxyMode为一个枚举,定义如下:
public enum ScopedProxyMode {
/**
* Default typically equals {@link #NO}, unless a different default
* has been configured at the component-scan instruction level.
*/
DEFAULT, //默认方式,同没代理的方式
/**
* Do not create a scoped proxy.
* <p>This proxy-mode is not typically useful when used with a
* non-singleton scoped instance, which should favor the use of the
* {@link #INTERFACES} or {@link #TARGET_CLASS} proxy-modes instead if it
* is to be used as a dependency.
*/
NO, //没有代理
/**
* Create a JDK dynamic proxy implementing <i>all</i> interfaces exposed by
* the class of the target object.
*/
INTERFACES, //java自带的jdk提供的动态代理方式
/**
* Create a class-based proxy (uses CGLIB).
*/
TARGET_CLASS; //CGLIB代理
}
1.3
org.springframework.aop.scope.ScopedProxyUtils#createScopedProxy源码:
/**
* Generate a scoped proxy for the supplied target bean, registering the target
* bean with an internal name and setting 'targetBeanName' on the scoped proxy.
* @param definition the original bean definition
* @param registry the bean definition registry
* @param proxyTargetClass whether to create a target class proxy
* @return the scoped proxy definition
*/
public static BeanDefinitionHolder createScopedProxy(BeanDefinitionHolder definition,
BeanDefinitionRegistry registry, boolean proxyTargetClass) {
//获取待注册bean的名称,比如我这边是MyConfig这样的注册类,则名字为:MyConfig
String originalBeanName = definition.getBeanName();
//获得包装bean的BeanDifinition
BeanDefinition targetDefinition = definition.getBeanDefinition();
//获取目标bean的名称,规则是:“scopedTarget.”+originalBeanName
String targetBeanName = getTargetBeanName(originalBeanName);
// Create a scoped proxy definition for the original bean name,
// "hiding" the target bean in an internal target definition.
// 生成一个代理工厂bean,并把它包装进RootBeanDefinition中
RootBeanDefinition proxyDefinition = new RootBeanDefinition(ScopedProxyFactoryBean.class);
// 为proxyDefinition添加设置属性
proxyDefinition.setDecoratedDefinition(new BeanDefinitionHolder(targetDefinition, targetBeanName));
proxyDefinition.setOriginatingBeanDefinition(targetDefinition);
proxyDefinition.setSource(definition.getSource());
proxyDefinition.setRole(targetDefinition.getRole());
proxyDefinition.getPropertyValues().add("targetBeanName", targetBeanName);
if (proxyTargetClass) {
targetDefinition.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
// ScopedProxyFactoryBean's "proxyTargetClass" default is TRUE, so we don't need to set it explicitly here.
}
else {
proxyDefinition.getPropertyValues().add("proxyTargetClass", Boolean.FALSE);
}
// Copy autowire settings from original bean definition.
proxyDefinition.setAutowireCandidate(targetDefinition.isAutowireCandidate());
proxyDefinition.setPrimary(targetDefinition.isPrimary());
if (targetDefinition instanceof AbstractBeanDefinition) {
proxyDefinition.copyQualifiersFrom((AbstractBeanDefinition) targetDefinition);
}
// The target bean should be ignored in favor of the scoped proxy.
targetDefinition.setAutowireCandidate(false);
targetDefinition.setPrimary(false);
// Register the target bean as separate bean in the factory.
registry.registerBeanDefinition(targetBeanName, targetDefinition);
// Return the scoped proxy definition as primary bean definition
// (potentially an inner bean).
//返回一个BeanDefinitionHolder实例对象,这个实例对象包装了proxyDefinition、originalBeanName
//等信息
return new BeanDefinitionHolder(proxyDefinition, originalBeanName, definition.getAliases());
}
1.4
对代码(3)进行分析,下沉底层:
/**
* Register the given bean definition with the given bean factory.
//将给定的bean definition 注册进入给定的bean工厂中
* @param definitionHolder the bean definition including name and aliases
* @param registry the bean factory to register with
* @throws BeanDefinitionStoreException if registration failed
*/
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
// Register bean definition under primary name.
//获取待注册bean的名称,比如注册类为MyConfig.class,则beanName为MyConfig
String beanName = definitionHolder.getBeanName();
//下面这行代码总得来说,逻辑为:
//(1)先判断beanDefinitionMap的key为beanName的value为空?
//(2)不为空,进行一些检查即可
//(3)为空,则需要插入beanName与beanDifinition这条数据
//经过上述(1)(2)(3)完成了将待注入bean注入Spring容器的工作
//该段逻辑详细分析见1.5
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
//处理别名
// Register aliases for bean name, if any.
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}
1.5
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
---->
void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException;
---->
查看其实现:
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException
源码如下:
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
//非空检查
Assert.hasText(beanName, "Bean name must not be empty");
Assert.notNull(beanDefinition, "BeanDefinition must not be null");
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
//获取beanDefinitionMap中的beanNanme的key对象的vaule
BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
//不为空,则说明容器中已经存在了待注入的bean
if (existingDefinition != null) {
if (!isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
}
else if (existingDefinition.getRole() < beanDefinition.getRole()) {
// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
if (logger.isInfoEnabled()) {
logger.info("Overriding user-defined bean definition for bean '" + beanName +
"' with a framework-generated bean definition: replacing [" +
existingDefinition + "] with [" + beanDefinition + "]");
}
}
else if (!beanDefinition.equals(existingDefinition)) {
if (logger.isDebugEnabled()) {
logger.debug("Overriding bean definition for bean '" + beanName +
"' with a different definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
else {
if (logger.isTraceEnabled()) {
logger.trace("Overriding bean definition for bean '" + beanName +
"' with an equivalent definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
this.beanDefinitionMap.put(beanName, beanDefinition);
}
else {
//不存在,则需要进行插入
//注意,在维护beanDefinitionMap这样的Map结构同时,
//还会维护beanDefinitionNames这样一个List结构,其中存放的是bean的名字
if (hasBeanCreationStarted()) {
// Cannot modify startup-time collection elements anymore (for stable iteration)
//同步锁
synchronized (this.beanDefinitionMap) {
this.beanDefinitionMap.put(beanName, beanDefinition);
List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
if (this.manualSingletonNames.contains(beanName)) {
Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
updatedSingletons.remove(beanName);
this.manualSingletonNames = updatedSingletons;
}
}
}
else {
// Still in startup registration phase
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
this.manualSingletonNames.remove(beanName);
}
this.frozenBeanDefinitionNames = null;
}
if (existingDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}
}
@Override
public void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {
Assert.hasText(beanName, "'beanName' must not be empty");
BeanDefinition bd = this.beanDefinitionMap.remove(beanName);
if (bd == null) {
if (logger.isTraceEnabled()) {
logger.trace("No bean named '" + beanName + "' found in " + this);
}
throw new NoSuchBeanDefinitionException(beanName);
}
if (hasBeanCreationStarted()) {
// Cannot modify startup-time collection elements anymore (for stable iteration)
synchronized (this.beanDefinitionMap) {
List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames);
updatedDefinitions.remove(beanName);
this.beanDefinitionNames = updatedDefinitions;
}
}
else {
// Still in startup registration phase
this.beanDefinitionNames.remove(beanName);
}
this.frozenBeanDefinitionNames = null;
resetBeanDefinition(beanName);
}
需要特别注意的是,到此仅仅是完成了待注入bean的注入工作,并没有对bean进行实例化,所以到现在为止我们还不能获取实实在在的bean实例,该工作将在org.springframework.context.support.AbstractApplicationContext#refresh方法中完成。另,spring源码过于复杂,本人能力有限,不足之处,还望指正,在此谢过。
1.6 参考文献
【1】https://segmentfault.com/a/1190000017413393?utm_source=tag-newest
【2】https://www.bilibili.com/video/BV1tx411o77Z?p=5
【3】《Spring源码解析》
本文深入探讨了Spring框架中Bean注册的过程,包括BeanDefinitionHolder的构造与使用、ScopedProxy的创建方式及其对Bean作用域的影响,以及BeanDefinition在IOC容器中的注册逻辑。
4727

被折叠的 条评论
为什么被折叠?



