说说Spring如何加载注册BeanDefinition
BeanDefinition定义
Bean的定义信息是Spring容器的一个核心概念,核心接口是BeanDefinition。
Spring容器启动的过程中,会将Bean解析成Spring内部的BeanDefinition结构。
不管是是通过xml配置文件的<Bean>标签,还是通过注解配置的@Bean,它最终都会被解析成一个Bean定义信息(对象),最后我们的Bean工厂就会根据这份Bean的定义信息,对bean进行实例化、初始化等等操作。
BeanDefinition源码分析
总体的类图:
因为它继承了AttributeAccessor,和BeanMetadataElement,所以我们先有必要来了解下这两个接口:
AttributeAccessor:定义了对对象元数据访问的抽象接口
// 接口都比较简单 就是定义了对对象属性的一些访问方法
//说明它可以持有Bean元数据元素,作用是可以持有XML文件的一个bean标签对应的Object(或者@Configuration元配置对象)
public interface AttributeAccessor {
void setAttribute(String name, @Nullable Object value);
@Nullable
Object getAttribute(String name);
@Nullable
Object removeAttribute(String name);
boolean hasAttribute(String name);
String[] attributeNames();
}
AttributeAccessorSupport是唯一抽象实现,内部基于LinkedHashMap实现了所有的接口,供其他子类继承使用 主要针对属性CRUD操作。
BeanMetadataElement:具有访问source(配置源)的能力
这个方法在@Configuration中使用较多,因为它会被代理。
//接口提供了一个getResource()方法,用来传输一个可配置的源对象。
public interface BeanMetadataElement {
/**
* Return the configuration source {@code Object} for this metadata element
* (may be {@code null}).
* 返回元数据元素配置元对象
*/
@Nullable
Object getSource();
}
BeanDefinition:定义了Bean的各种信息
一个BeanDefinition描述了一个bean的实例,包括属性值,构造方法参数值和继承自它的类的更多信息。
BeanDefinition仅仅是一个最简单的接口,主要功能是允许BeanFactoryPostProcessor能够检索并修改属性值和别的bean的元数据,例如:PropertyPlaceHolderConfigurer
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
// 单例Bean还是原型Bean
String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;
String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;
// Bean角色
int ROLE_APPLICATION = 0; //应用程序重要组成部分
int ROLE_SUPPORT = 1; //做为大量配置的一部分(支持、扩展类) 实际上就是说,我这个Bean是用户的,是从配置文件中过来的。
int ROLE_INFRASTRUCTURE = 2; //指内部工作的基础构造 实际上是说我这Bean是Spring自己的,和你用户没有一毛钱关系
// Modifiable attributes
//parent definition(若存在父类的话,就设置进去)
void setParentName(@Nullable String parentName);
@Nullable
String getParentName();
// 指定Class类型。需要注意的是该类型还有可能被改变在Bean post-processing阶段
// 若是getFactoryBeanName getFactoryMethodName这种情况下会改变
void setBeanClassName(@Nullable String beanClassName);
@Nullable
String getBeanClassName();
//SCOPE_SINGLETON或者SCOPE_PROTOTYPE两种
void setScope(@Nullable String scope);
@Nullable
String getScope();
// @Lazy 是否需要懒加载(默认都是立马加载的)
void setLazyInit(boolean lazyInit);
boolean isLazyInit();
// 此Bean定义需要依赖的Bean(显然可以有多个)
void setDependsOn(@Nullable String... dependsOn);
@Nullable
String[] getDependsOn();
// 这个Bean是否允许被自动注入到别的地方去(默认都是被允许的)
// 注意:此标志只影响按类型装配,不影响byName的注入方式的~~~~
void setAutowireCandidate(boolean autowireCandidate);
boolean isAutowireCandidate();
// 是否是首选的 @Primary
void setPrimary(boolean primary);
boolean isPrimary();
// 指定使用的工厂Bean(若存在)的名称~
void setFactoryBeanName(@Nullable String factoryBeanName);
@Nullable
String getFactoryBeanName();
//指定工厂方法~
void setFactoryMethodName(@Nullable String factoryMethodName);
@Nullable
String getFactoryMethodName();
// 获取此Bean的构造函数参数值们 ConstructorArgumentValues:持有构造函数们的
// 绝大多数情况下是空对象 new ConstructorArgumentValues出来的一个对象
// 当我们Scan实例化Bean的时候,可能用到它的非空构造,这里就会有对应的值了,然后后面就会再依赖注入了
ConstructorArgumentValues getConstructorArgumentValues();
default boolean hasConstructorArgumentValues() {
return !getConstructorArgumentValues().isEmpty();
}
// 获取普通属性集合~~~~
MutablePropertyValues getPropertyValues();
default boolean hasPropertyValues() {
return !getPropertyValues().isEmpty();
}
// Read-only attributes
boolean isSingleton();
boolean isPrototype();
boolean isAbstract();
// 对应上面的role的值
int getRole();
//@Description
@Nullable
String getDescription();
// 返回该Bean定义来自于的资源的描述(用于在出现错误时显示上下文)
@Nullable
String getResourceDescription();
//返回原始BeanDefinition,如果没有则返回@null
// 若这个Bean定义被代理、修饰过 这个方法可以返回原始的
@Nullable
BeanDefinition getOriginatingBeanDefinition();
}
子接口:AnnotatedBeanDefinition
public interface AnnotatedBeanDefinition extends BeanDefinition {
//获取该bean definition的注解元数据
AnnotationMetadata getMetadata();
//@since 4.1.1
//Obtain metadata for this bean definition's factory method(如果不存在就返回null)
@Nullable
MethodMetadata getFactoryMethodMetadata();
}
AnnotationMetadata定义了访问特定类的注解的抽象接口,它不需要加载该类即可访问。
该注解Bean定义旗下三大实现类:ScannedGenericBeanDefinition、ConfigurationClassBeanDefinition、AnnotatedGenericBeanDefinition
抽象实现:AbstractBeanDefinition
AbstractBeanDefinition实现了BeanDefinition定义的一系列操作,定义了描述Bean画像的一系列属性,在AbstractBeanDefinition的基础上,Spring衍生出了一系列具有特殊用途的BeanDefinition。
实现的代码特别多:
public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor
implements BeanDefinition, Cloneable {
//=====================定义众多常量。这一些常量会直接影响到spring实例化Bean时的策略
// 个人觉得这些常量的定义不是必须的,在代码里判断即可。Spring定义这些常量的原因很简单,便于维护,让读代码的人知道每个值的意义(所以以后我们在书写代码时,也可以这么来搞)
//默认的SCOPE,默认是单例
public static final String SCOPE_DEFAULT = "";
// 自动装配的一些常量
public static final int AUTOWIRE_NO = AutowireCapableBeanFactory.AUTOWIRE_NO;
public static final int AUTOWIRE_BY_NAME = AutowireCapableBeanFactory.AUTOWIRE_BY_NAME;
public static final int AUTOWIRE_BY_TYPE = AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE;
public static final int AUTOWIRE_CONSTRUCTOR = AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR;
@Deprecated
public static final int AUTOWIRE_AUTODETECT = AutowireCapableBeanFactory.AUTOWIRE_AUTODETECT;
//检查依赖是否合法,在本类中,默认不进行依赖检查
public static final int DEPENDENCY_CHECK_NONE = 0; // 不进行检查
public static final int DEPENDENCY_CHECK_OBJECTS = 1; //如果依赖类型为对象引用,则需要检查
public static final int DEPENDENCY_CHECK_SIMPLE = 2; //对简单属性的依赖进行检查
public static final int DEPENDENCY_CHECK_ALL = 3; //对所有属性的依赖进行检查
//若Bean未指定销毁方法,容器应该尝试推断Bean的销毁方法的名字,目前来说,推断的销毁方法的名字一般为close或是shutdown
//(即未指定Bean的销毁方法,但是内部定义了名为close或是shutdown的方法,则容器推断其为销毁方法)
public static final String INFER_METHOD = "(inferred)";
//=====================属性:基本囊括了Bean实例化需要的所有信息
//Bean的class对象或是类的全限定名
@Nullable
private volatile Object beanClass;
//默认的scope是单例
@Nullable
private String scope = SCOPE_DEFAULT;
//默认不为抽象类
private boolean abstractFlag = false;
//默认不进行自动装配
private boolean lazyInit = false;
//默认不是懒加载
private int autowireMode = AUTOWIRE_NO;
//默认不进行依赖检查
private int dependencyCheck = DEPENDENCY_CHECK_NONE;
// @@DependsOn 默认没有
@Nullable
private String[] dependsOn;
// autowire-candidate属性设置为false,这样容器在查找自动装配对象时,将不考虑该bean,
// 备注:并不影响本身注入其它的Bean
private boolean autowireCandidate = true;
// 默认不是首选的
private boolean primary = false;
//用于记录Qualifier,对应子元素qualifier=======这个字段有必要解释一下
// 唯一向这个字段放值的方法为本类的:public void addQualifier(AutowireCandidateQualifier qualifier) copyQualifiersFrom这个不算,那属于拷贝
// 调用处:AnnotatedBeanDefinitionReader#doRegisterBean 但是Spring所有调用处,qualifiers字段传的都是null~~~~~~~~~尴尬
// 通过我多放跟踪发现,此处这个字段目前【永远】不会被赋值(除非我们手动调用对应方法为其赋值) 但是有可能我才疏学浅,若有知道的 请告知,非常非常感谢 我考虑到它可能是预留字段~~~~
// 我起初以为这样可以赋值:
//@Qualifier("aaa")
//@Service
//public class HelloServiceImpl 没想到,也是不好使的,Bean定义里面也不会有值
// 因此对应的方法getQualifier和getQualifiers 目前应该基本上都返回null或者[]
private final Map<String, AutowireCandidateQualifier> qualifiers = new LinkedHashMap<>(0);
//我理解为通过这个函数的逻辑初始化Bean,而不是构造函数或是工厂方法(相当于自己去实例化,而不是交给Bean工厂)
@Nullable
private Supplier<?> instanceSupplier;
//是否允许访问非public方法和属性,应用于构造函数、工厂方法、init、destroy方法的解析 默认是true,表示啥都可以访问
private boolean nonPublicAccessAllowed = true;
// 是否以一种宽松的模式解析构造函数,默认为true(宽松和严格体现在类型匹配上)
private boolean lenientConstructorResolution = true;
//工厂类名(注意是String类型,不是Class类型) 对应bean属性factory-method
@Nullable
private String factoryBeanName;
//工厂方法名(注意是String类型,不是Method类型)
@Nullable
private String factoryMethodName;
//记录构造函数注入属性,对应bean属性constructor-arg
@Nullable
private ConstructorArgumentValues constructorArgumentValues;
//Bean属性的名称以及对应的值,这里不会存放构造函数相关的参数值,只会存放通过setter注入的依赖
@Nullable
private MutablePropertyValues propertyValues;
//方法重写的持有者,记录lookup-method、replaced-method元素 @Lookup等
@Nullable
private MethodOverrides methodOverrides;
//init函数的名字
@Nullable
private String initMethodName;
//destory函数的名字
@Nullable
private String destroyMethodName;
//是否执行init-method,程序设置
private boolean enforceInitMethod = true;
private boolean enforceDestroyMethod = true;
//是否是合成类(是不是应用自定义的,例如生成AOP代理时,会用到某些辅助类,这些辅助类不是应用自定义的,这个就是合成类)
//创建AOP时候为true
private boolean synthetic = false;
//Bean的角色,为用户自定义Bean
private int role = BeanDefinition.ROLE_APPLICATION;
// Bean的描述信息
@Nullable
private String description;
//the resource that this bean definition came from
// 这个Bean哪儿来的
@Nullable
private Resource resource;
//=====================方法:就不逐一解释了,大部分都是get、set 只贴出一些特殊的
// 其实就是给reource赋值了,使用了BeanDefinitionResource
public void setOriginatingBeanDefinition(BeanDefinition originatingBd) {
this.resource = new BeanDefinitionResource(originatingBd);
}
// 上面有赋值,所以get的时候就是返回上面set进来的值
public BeanDefinition getOriginatingBeanDefinition() {
return (this.resource instanceof BeanDefinitionResource ?
((BeanDefinitionResource) this.resource).getBeanDefinition() : null);
}
//克隆Bean的定义信息
@Override
public Object clone() {
return cloneBeanDefinition();
}
public abstract AbstractBeanDefinition cloneBeanDefinition();
}
AbstractBeanDefinition定义了一系列描述Bean画像的属性,通过这个类,可以窥见Bean的某些默认设置(例如默认为单例等)。
接下来需要看具体衍生出来的实现类了,先看RootBeanDefinition、ChildBeanDefinition、GenericBeanDefinition。它们都是AbstractBeanDefinition的直接实现类。
GenericBeanDefinition:标准bean definition,通用的
除了具有指定类、可选的构造参数值和属性参数这些其它bean definition一样的特性外,它还具有通过parenetName属性来灵活(动态)设置parent bean definition,而非硬编码作为root bean definition。
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(RootConfig.class);
// 向工厂里注册Bean信息
GenericBeanDefinition parentBeanDef = new GenericBeanDefinition();
parentBeanDef.setBeanClass(Parent.class);
parentBeanDef.setBeanClassName(Parent.class.getName());
parentBeanDef.setScope(BeanDefinition.SCOPE_SINGLETON);
// 就这样,我们可以动态的给子Bean 设置一个父Bean进去
GenericBeanDefinition childBeanDef = new GenericBeanDefinition();
childBeanDef.setParentName(parentBeanDef.getBeanClassName());
childBeanDef.setBeanClass(Child.class);
applicationContext.registerBeanDefinition("parent", parentBeanDef);
applicationContext.registerBeanDefinition("child", childBeanDef);
System.out.println(applicationContext.getBeanDefinition("parent"));
System.out.println(applicationContext.getBeanDefinition("child")); //Generic bean with parent 'com.fsx.bean.Parent': class [com.fsx.bean.Child]; scope=;...
}
GenericBeanDefinition源码实现非常的的简单,只增加了一个parentName的属性值,其余的实现都在父类AbstractBeanDefinition里。
若你是xml配置,最初被加载进来都是一个GenericBeanDefinition,之后再逐渐解析的。
ChildBeanDefinition:子Bean定义信息,依赖于父类RootBeanDefinition
ChildBeanDefinition是一种bean definition,它可以继承它父类的设置,即ChildBeanDefinition对RootBeanDefinition有一定的依赖关系。
RootBeanDefinition
一个RootBeanDefinition定义表明它是一个可合并的bean definition:即在spring beanFactory运行期间,可以返回一个特定的bean。但在Spring2.5以后,我们绝大多数情况还是可以使用GenericBeanDefinition来做。
我们非常熟悉的final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);这句代码,就是去合并parent的属性进来,这样体现了继承的强大,属性也才完整。
在 配置文件中可以定义父和子,父用RootBeanDefinition表示, 而子用ChildBeanDefiniton表示,而没有父的就使用 RootBeanDefinition表示。下面看看源码:
//简单的说:在多继承体系中,RootBeanDefinition代表的是当前初始化类的父类的BeanDefinition 若没有父类,那就是它自己嘛
public class RootBeanDefinition extends AbstractBeanDefinition {
//BeanDefinitionHolder存储有Bean的名称、别名、BeanDefinition
@Nullable
private BeanDefinitionHolder decoratedDefinition;
// AnnotatedElement 是java反射包的接口,通过它可以查看Bean的注解信息
@Nullable
private AnnotatedElement qualifiedElement;
//允许缓存
boolean allowCaching = true;
//从字面上理解:工厂方法是否唯一
boolean isFactoryMethodUnique = false;
//封装了java.lang.reflect.Type,提供了泛型相关的操作,具体请查看:
// ResolvableType 可以专题去了解一下子,虽然比较简单 但常见
@Nullable
volatile ResolvableType targetType;
//缓存class,表明RootBeanDefinition存储哪个类的信息
@Nullable
volatile Class<?> resolvedTargetType;
//缓存工厂方法的返回类型
@Nullable
volatile ResolvableType factoryMethodReturnType;
/** Common lock for the four constructor fields below */
final Object constructorArgumentLock = new Object();
//缓存已经解析的构造函数或是工厂方法,Executable是Method、Constructor类型的父类
@Nullable
Executable resolvedConstructorOrFactoryMethod;
//表明构造函数参数是否解析完毕
boolean constructorArgumentsResolved = false;
//缓存完全解析的构造函数参数
@Nullable
Object[] resolvedConstructorArguments;
//缓存待解析的构造函数参数,即还没有找到对应的实例,可以理解为还没有注入依赖的形参
@Nullable
Object[] preparedConstructorArguments;
/** Common lock for the two post-processing fields below */
final Object postProcessingLock = new Object();
//表明是否被MergedBeanDefinitionPostProcessor处理过
boolean postProcessed = false;
//在生成代理的时候会使用,表明是否已经生成代理
@Nullable
volatile Boolean beforeInstantiationResolved;
//实际缓存的类型是Constructor、Field、Method类型
@Nullable
private Set<Member> externallyManagedConfigMembers;
//InitializingBean中的init回调函数名——afterPropertiesSet会在这里记录,以便进行生命周期回调
@Nullable
private Set<String> externallyManagedInitMethods;
//DisposableBean的destroy回调函数名——destroy会在这里记录,以便进行生命周期回调
@Nullable
private Set<String> externallyManagedDestroyMethods;
//===========方法(只例举部分)
// 由此看出,RootBeanDefiniiton是木有父的
@Override
public String getParentName() {
return null;
}
@Override
public void setParentName(@Nullable String parentName) {
if (parentName != null) {
throw new IllegalArgumentException("Root bean cannot be changed into a child bean with parent reference");
}
}
// 拿到class类型
@Nullable
public Class<?> getTargetType() {
if (this.resolvedTargetType != null) {
return this.resolvedTargetType;
}
ResolvableType targetType = this.targetType;
return (targetType != null ? targetType.resolve() : null);
}
@Override
public RootBeanDefinition cloneBeanDefinition() {
return new RootBeanDefinition(this);
}
}
可以看到许多与反射相关的对象,这说明spring底层采用的是反射机制。
总结一下,RootBeanDefiniiton保存了以下信息:
- 定义了id、别名与Bean的对应关系(BeanDefinitionHolder)
- Bean的注解(AnnotatedElement)
- 具体的工厂方法(Class类型),包括工厂方法的返回类型,工厂方法的Method对象
- 构造函数、构造函数形参类型
- Bean的class对象
可以看到,RootBeanDefinition与AbstractBeanDefinition是互补关系,RootBeanDefinition在AbstractBeanDefinition的基础上定义了更多属性,初始化Bean需要的信息基本完善。
接下来,再在看看AnnotatedBeanDefinition的三个子类:
ScannedGenericBeanDefinition:存储@Component、@Service、@Controller等注解注释的类
它的源码很简单,就是多了一个属性:private final AnnotationMetadata metadata用来存储扫描进来的Bean的一些注解信息。
// 实现了AnnotatedBeanDefinition 也继承了GenericBeanDefinition
public class ScannedGenericBeanDefinition extends GenericBeanDefinition implements AnnotatedBeanDefinition {
private final AnnotationMetadata metadata;
...
// 它只有一个构造函数:必须传入MetadataReader
public ScannedGenericBeanDefinition(MetadataReader metadataReader) {
Assert.notNull(metadataReader, "MetadataReader must not be null");
this.metadata = metadataReader.getAnnotationMetadata();
setBeanClassName(this.metadata.getClassName());
}
}
AnnotatedGenericBeanDefinition
在基于注解驱动的Spring应用,它使用得非常的多。因为获取注解信息非常的方便~
AnnotatedGenericBeanDefinition只能用于已经被注册或被扫描到的类(否则你手动new一个,它就不在容器里了,那就脱离管理了)
使用案例:
public static void main(String[] args) {
AnnotatedBeanDefinition beanDefinition = new AnnotatedGenericBeanDefinition(RootConfig.class);
// 就这么一下子,就把注解们都拿到了,简直不要太方便,简直可以当工具类来用
Set<String> annotationTypes = beanDefinition.getMetadata().getAnnotationTypes();
System.out.println(annotationTypes); //[org.springframework.context.annotation.ComponentScan, org.springframework.context.annotation.Configuration]
System.out.println(beanDefinition.isSingleton()); //true
System.out.println(beanDefinition.getBeanClassName()); //com.config.RootConfig
}
源码参考:
public class AnnotatedGenericBeanDefinition extends GenericBeanDefinition implements AnnotatedBeanDefinition {
private final AnnotationMetadata metadata;
@Nullable
private MethodMetadata factoryMethodMetadata;
/**
* Create a new AnnotatedGenericBeanDefinition for the given bean class.
* @param beanClass the loaded bean class 注意官方这个注释:已经加载进来了的Bean的Class
*/
public AnnotatedGenericBeanDefinition(Class<?> beanClass) {
setBeanClass(beanClass);
this.metadata = new StandardAnnotationMetadata(beanClass, true);
}
//@since 3.1.1 此处传入AnnotationMetadata ,也得保证对应的class已经被loaded
public AnnotatedGenericBeanDefinition(AnnotationMetadata metadata) {
Assert.notNull(metadata, "AnnotationMetadata must not be null");
if (metadata instanceof StandardAnnotationMetadata) {
setBeanClass(((StandardAnnotationMetadata) metadata).getIntrospectedClass());
}
else {
setBeanClassName(metadata.getClassName());
}
this.metadata = metadata;
}
//@since 4.1.1 可以由指定的工厂方法产生这个Bean
public AnnotatedGenericBeanDefinition(AnnotationMetadata metadata, MethodMetadata factoryMethodMetadata) {
this(metadata);
Assert.notNull(factoryMethodMetadata, "MethodMetadata must not be null");
setFactoryMethodName(factoryMethodMetadata.getMethodName());
this.factoryMethodMetadata = factoryMethodMetadata;
}
@Override
public final AnnotationMetadata getMetadata() {
return this.metadata;
}
@Override
@Nullable
public final MethodMetadata getFactoryMethodMetadata() {
return this.factoryMethodMetadata;
}
}
ConfigurationClassBeanDefinition
首先需要注意的是,它是ConfigurationClassBeanDefinitionReader的一个私有的静态内部类:这个类负责将@Bean注解的方法转换为对应的ConfigurationClassBeanDefinition类(非常的重要)
// 它直接继承自RootBeanDefinition
private static class ConfigurationClassBeanDefinition extends RootBeanDefinition implements AnnotatedBeanDefinition {
//... 源码和之前的差得不是太多,此处就不解释了
}
它有一些默认的设置处理如下:
- 如果@Bean注解没有指定bean的名字,默认会用方法的名字命名bean
- @Configuration注解的类会成为一个工厂类,而所有的@Bean注解的方法会成为工厂方法,通过工厂方法实例化Bean,而不是直接通过构造函数初始化(所以我们方法体里面可以很方便的书写逻辑)
Spring初始化时,会用GenericBeanDefinition或是ConfigurationClassBeanDefinition(用@Bean注解注释的类)存储用户自定义的Bean,在初始化Bean时,又会将其转换为RootBeanDefinition。
BeanDefinitionBuilder:快速创建一个Bean定义
使用它的好处是,可以进行方法的连缀。
没有特殊指明,创建的都是GenericBeanDefinition,源码非常的简单,下面只用个Demo看看即可:
public class BeanDefinitionBuilder {
//=================创建一个Builder 没特殊指明,都是GenericBeanDefinition
public static BeanDefinitionBuilder genericBeanDefinition() {
return new BeanDefinitionBuilder(new GenericBeanDefinition());
}
....
public static BeanDefinitionBuilder rootBeanDefinition(String beanClassName) {
return rootBeanDefinition(beanClassName, null);
}
public static BeanDefinitionBuilder childBeanDefinition(String parentName) {
return new BeanDefinitionBuilder(new ChildBeanDefinition(parentName));
}
}
Demo:
public static void main(String[] args) {
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(Child.class)
.setRole(BeanDefinition.ROLE_APPLICATION)
.setScope(BeanDefinition.SCOPE_SINGLETON)
.addPropertyValue("name", "fsx")
.setLazyInit(false)
//Spring5.0后提供的,可以自己书写函数,在里面做任意事情
//bdf是个AbstractBeanDefinition
.applyCustomizers((bdf) -> {
AbstractBeanDefinition abdf = (AbstractBeanDefinition) bdf;
abdf.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_NO);
}).getRawBeanDefinition();
System.out.println(beanDefinition); //Generic bean: class [com.fsx.maintest.Child]; scope=singleton; abstract=false; lazyInit=false; autowireMode=0; d...
}
BeanDefinitionReader:该接口的作用就是加载 Bean
在 Spring 中,Bean 一般来说都在配置文件中定义。而配置的路径由在 web.xml 中定义(还有全注解的方式)。所以加载 Bean 的步骤大致就是:
- 加载资源,通过配置文件的路径(Location)加载配置文件(Resource)
- 解析资源,通过解析配置文件的内容得到 Bean。
public interface BeanDefinitionReader {
// 得到Bean定义的register
BeanDefinitionRegistry getRegistry();
// 返回用于加载资源的 ResourceLoader(可以为null)
@Nullable
ResourceLoader getResourceLoader();
// 加载Bean的类加载器
@Nullable
ClassLoader getBeanClassLoader();
// 生成Bean名称的名字生成器(若没有指定名称的话,会调用它生成)
BeanNameGenerator getBeanNameGenerator();
// 核心方法,loadbean定义进来,然后注册到上面的register 里面去
int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException;
int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException;
int loadBeanDefinitions(String location) throws BeanDefinitionStoreException;
int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException;
}
它的继承结构非常简单,一个抽象实现+3个具体实现
AbstractBeanDefinitionReader
它实现了一些基本的方法,但是核心方法loadBeanDefinitions肯定是交给子类实现了
public abstract class AbstractBeanDefinitionReader implements EnvironmentCapable, BeanDefinitionReader {
private final BeanDefinitionRegistry registry;
@Nullable
private ResourceLoader resourceLoader;
@Nullable
private ClassLoader beanClassLoader;
// 会有环境变量
private Environment environment;
// 默认的名字生成器(类名首字母小写)
private BeanNameGenerator beanNameGenerator = new DefaultBeanNameGenerator();
// 此构造函数,会完成一些参数的初始化
protected AbstractBeanDefinitionReader(BeanDefinitionRegistry registry) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
this.registry = registry;
// Determine ResourceLoader to use.
if (this.registry instanceof ResourceLoader) {
this.resourceLoader = (ResourceLoader) this.registry;
} else {
// 注意这个处理~~~~
this.resourceLoader = new PathMatchingResourcePatternResolver();
}
// Inherit Environment if possible
// 如果注册器里有环境变量,就用它的 否则new一个标准的~~~~ 它下面也提供了set方法可以设置
if (this.registry instanceof EnvironmentCapable) {
this.environment = ((EnvironmentCapable) this.registry).getEnvironment();
} else {
this.environment = new StandardEnvironment();
}
}
public void setEnvironment(Environment environment) {
Assert.notNull(environment, "Environment must not be null");
this.environment = environment;
}
public void setBeanNameGenerator(@Nullable BeanNameGenerator beanNameGenerator) {
this.beanNameGenerator = (beanNameGenerator != null ? beanNameGenerator : new DefaultBeanNameGenerator());
}
//...
}
XmlBeanDefinitionReader:从xml中加载Bean定义信息
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
//...
}
我们注解配置中@Configuration上也可以加上@ImportResource导入外置的xml配置文件。它由此方法ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsFromImportedResources处理,内部借助的就是XmlBeanDefinitionReader去解析它的。
PropertiesBeanDefinitionReader:直接从properties文件或者Map里加载Bean
可能有人会问:我们注解的@Bean以及@Component的这么些bean定义都是谁去加载的呢?
其实,@Bean都是@Configuration配置类里,统一由ConfigurationClassParser#parse()里去处理的(直接执行Method就行)
@Component这种组件统一由解析@ComponentScan的处理器的ComponentScanAnnotationParser(借助ClassPathBeanDefinitionScanner) 。
如何加载bean定义信息
Spring IOC容器启动过程中,会加载BeanDefinition。
spring beanDefinition加载,在方法obtainFreshBeanFactory中完成(org.springframework.context.support.AbstractApplicationContext#refresh)
org.springframework.context.support.AbstractRefreshableApplicationContext#refreshBeanFactory方法
createBeanFactory:创建容器,会获取parent容器作为参数传入
xml配置的使用org.springframework.web.context.support.XmlWebApplicationContext#loadBeanDefinitions
注解的使用org.springframework.web.context.support.AnnotationConfigWebApplicationContext#loadBeanDefinitions
这里先以 xml 配置为例,创建beanDefinitionReader
获取resource,也就是配置的xml文件
将resource读入,解析成document对象
主要方法在这,传入doc节点,开始解析
parseDefaultElement方法解析标签import、alias、bean、beans四种
接下来,我们将着重讲解两个非常关键的类:AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner。它俩完成对Bean信息的加载。
AnnotationConfigApplicationContext(spring-context包下)的继承图谱如下:
需要注意的是,我们在Tomcat等web环境下的容器类为:AnnotationConfigWebApplicationContext,它在spring-web包下
那到底是什么时候创建了AnnotationConfigWebApplicationContext实例呢?可以参考 :聊聊Spring容器(含父子容器)的启动过程分析
org.springframework.web.context.support.AnnotationConfigWebApplicationContext#loadBeanDefinitions
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {
AnnotatedBeanDefinitionReader reader = getAnnotatedBeanDefinitionReader(beanFactory);
ClassPathBeanDefinitionScanner scanner = getClassPathBeanDefinitionScanner(beanFactory);
BeanNameGenerator beanNameGenerator = getBeanNameGenerator();
if (beanNameGenerator != null) {
reader.setBeanNameGenerator(beanNameGenerator);
scanner.setBeanNameGenerator(beanNameGenerator);
beanFactory.registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, beanNameGenerator);
}
ScopeMetadataResolver scopeMetadataResolver = getScopeMetadataResolver();
if (scopeMetadataResolver != null) {
reader.setScopeMetadataResolver(scopeMetadataResolver);
scanner.setScopeMetadataResolver(scopeMetadataResolver);
}
if (!this.componentClasses.isEmpty()) {
if (logger.isDebugEnabled()) {
logger.debug("Registering component classes: [" +
StringUtils.collectionToCommaDelimitedString(this.componentClasses) + "]");
}
reader.register(ClassUtils.toClassArray(this.componentClasses)); //①
}
if (!this.basePackages.isEmpty()) {
if (logger.isDebugEnabled()) {
logger.debug("Scanning base packages: [" +
StringUtils.collectionToCommaDelimitedString(this.basePackages) + "]");
}
scanner.scan(StringUtils.toStringArray(this.basePackages)); //②
}
String[] configLocations = getConfigLocations();
if (configLocations != null) {
for (String configLocation : configLocations) {
try {
Class<?> clazz = ClassUtils.forName(configLocation, getClassLoader());
if (logger.isTraceEnabled()) {
logger.trace("Registering [" + configLocation + "]");
}
reader.register(clazz);
}
catch (ClassNotFoundException ex) {
if (logger.isTraceEnabled()) {
logger.trace("Could not load class for config location [" + configLocation +
"] - trying package scan. " + ex);
}
int count = scanner.scan(configLocation);
if (count == 0 && logger.isDebugEnabled()) {
logger.debug("No component classes found for specified class/package [" + configLocation + "]");
}
}
}
}
}
AnnotatedBeanDefinitionReader初始化,构造器如下:
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
Assert.notNull(environment, "Environment must not be null");
this.registry = registry;
//ConditionEvaluator完成条件注解的判断,在后面的Spring Boot中有大量的应用
this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
//这句会把一些自动注解处理器加入到AnnotationConfigApplicationContext下的BeanFactory的BeanDefinitions中 具体见下面
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
AnnotationConfigUtils#registerAnnotationConfigProcessors()
我们要用一些注解比如:@Autowired/@Required/@Resource都依赖于各种各样的BeanPostProcessor来解析(AutowiredAnnotation、RequiredAnnotation、CommonAnnotationBeanPostProcessor等等)。
但是像这种非常常用的,让调用者自己去申明,显然使用起来就过重了。所以Spring为我们提供了一种极为方便注册这些BeanPostProcessor的方式(若是xml方式,配置<context:annotation-config/>,若是全注解驱动的ApplicationContext,就默认会执行)
public static void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {
registerAnnotationConfigProcessors(registry, null);
}
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
BeanDefinitionRegistry registry, @Nullable Object source) {
// 把我们的beanFactory从registry里解析出来
DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
if (beanFactory != null) {
if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
}
// 相当于如果没有这个AutowireCandidateResolver,就给设置一份ContextAnnotationAutowireCandidateResolver
if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
}
}
//这里初始长度放4 是因为大多数情况下,我们只会注册4个BeanPostProcessor 如下(不多说了)
// BeanDefinitionHolder解释:持有name和aliases,为注册做准备
// Spring 4.2之后这个改成6我觉得更准确点
Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(4);
if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
}
if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
}
if (!registry.containsBeanDefinition(REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(RequiredAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
}
// Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
// 支持JSR-250的一些注解:@Resource、@PostConstruct、@PreDestroy等
if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
}
// Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
// 若导入了对JPA的支持,那就注册JPA相关注解的处理器
if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition();
try {
def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
AnnotationConfigUtils.class.getClassLoader()));
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
}
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
}
// 下面两个类,是Spring4.2之后加入进来的,为了更好的使用Spring的事件而提供支持
// 支持了@EventListener注解,我们可以通过此注解更方便的监听事件了(Spring4.2之后)
// 具体这个Processor和ListenerFactory怎么起作用的,且听事件专题分解
if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
}
if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
}
return beanDefs;
}
我们发现:内部定义的class都是带internal的:
(1) ConfigurationClassPostProcessor是一个BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor处理器,BeanDefinitionRegistryPostProcessor的处理方法能处理@Configuration等注解。ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry()方法内部处理@Configuration,@Import,@ImportResource和类内部的@Bean。
ConfigurationClassPostProcessor类继承了BeanDefinitionRegistryPostProcessor。BeanDefinitionRegistryPostProcessor类继承了BeanFactoryPostProcessor。
通过BeanDefinitionRegistryPostProcessor可以创建一个特别后置处理器来将BeanDefinition添加到BeanDefinitionRegistry中。它和BeanPostProcessor不同,BeanPostProcessor只是在Bean初始化的时候有个钩子让我们加入一些自定义操作;而BeanDefinitionRegistryPostProcessor可以让我们在BeanDefinition中添加一些自定义操作。在Mybatis与Spring的整合中,就利用到了BeanDefinitionRegistryPostProcessor来对Mapper的BeanDefinition进行了后置的自定义处理。
(2) AutowiredAnnotationBeanPostProcessor是用来处理@Autowired注解和@Value注解的
(3) RequiredAnnotationBeanPostProcessor这是用来处理@Required注解
(4) CommonAnnotationBeanPostProcessor提供对JSR-250规范注解的支持@javax.annotation.Resource、@javax.annotation.PostConstruct和@javax.annotation.PreDestroy等的支持。
(5) EventListenerMethodProcessor提供@PersistenceContext的支持。
(6) EventListenerMethodProcessor提供@ EventListener 的支持。@ EventListener实在spring4.2之后出现的,可以在一个Bean的方法上使用@EventListener注解来自动注册一个ApplicationListener。
到此AnnotatedBeanDefinitionReader初始化完毕。
总结一下,AnnotatedBeanDefinitionReader读取器用来加载class类型的配置,在它初始化的时候,会预先注册一些BeanPostProcessor和BeanFactoryPostProcessor,这些处理器会在接下来的spring初始化流程中被调用。
ClassPathBeanDefinitionScanner的初始化:
跟踪构造函数的重载,最终都到这里:
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
Environment environment, @Nullable ResourceLoader resourceLoader) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
this.registry = registry;
//useDefaultFilters为true,所以此处一般都会执行
// 当然我们也可以设置为false,比如@ComponentScan里就可以设置为false,只扫描指定的注解/类等等
if (useDefaultFilters) {
registerDefaultFilters();
}
// 设置环境
setEnvironment(environment);
// 详情如下: 这里resourceLoader传值,还是我们的工厂。否则为null
setResourceLoader(resourceLoader);
}
registerDefaultFilters()
protected void registerDefaultFilters() {
// 这里需要注意,默认情况下都是添加了@Component这个注解的
//(相当于@Service @Controller @Respository等都会扫描,因为这些注解都属于@Component) 另外@Configuration也属于哦
this.includeFilters.add(new AnnotationTypeFilter(Component.class));
ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
//下面两个 是兼容JSR-250的@ManagedBean和330的@Named注解
try {
this.includeFilters.add(new AnnotationTypeFilter(
((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));
logger.debug("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
} catch (ClassNotFoundException ex) {
// JSR-250 1.1 API (as included in Java EE 6) not available - simply skip.
}
try {
this.includeFilters.add(new AnnotationTypeFilter(
((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));
logger.debug("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
} catch (ClassNotFoundException ex) {
// JSR-330 API not available - simply skip.
}
// 所以,如果你想Spring连你自定义的注解都扫描,自己实现一个AnnotationTypeFilter就可以啦
}
ClassPathBeanDefinitionScanner继承于ClassPathScanningCandidateComponentProvider,它内部维护有两个final类型的List:这两个对象在执行本类的scanCandidateComponents()方法时就会起作用。
//includeFilters中的就是满足过滤规则的
private final List<TypeFilter> includeFilters = new LinkedList<>();
//excludeFilters则是不满足过滤规则的
private final List<TypeFilter> excludeFilters = new LinkedList<>();
ClassPathScanningCandidateComponentProvider#setResourceLoader
为ResourcePatternResolver,MetadataReaderFactory和CandidateComponentsIndex设定初始值。
@Override
public void setResourceLoader(@Nullable ResourceLoader resourceLoader) {
this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
this.metadataReaderFactory = new CachingMetadataReaderFactory(resourceLoader);
// Spring5以后才有这句,优化了bean扫描
this.componentsIndex = CandidateComponentsIndexLoader.loadIndex(this.resourcePatternResolver.getClassLoader());
}
说明:若要使用Spring5 的这个功能,需要添加如下包。这样子当工程重新编译的时候(编译期),会在自动生成META-INF/spring-components。然后我们在启动用@ComponentScan扫描时,直接读取这个文件即可,极大的提高了Spring启动的速度。而这期间,可以使用Spring5.0最新提供的注解@Indexed来配合使用。
需要注意的是:这种方式也是存在缺陷的,具体缺陷请参考官方文档:https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-scanning-index
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-indexer</artifactId>
<version>5.0.7.RELEASE</version>
<optional>true</optional>
</dependency>
然后在运行后会生成一个 META-INF/spring.components 的文件,之后只要运行工程发现这个文件都会直接使用它。可以通过环境变量或工程根目录的spring.properties中设置spring.index.ignore=ture来禁用这个功能 (这个功能如果没有什么明确的需求,慎重使用,会提高工程的管理成本。)
- ResourcePatternResolver是一个接口,继承了ResourceLoader,可以用来获取Resource 实例。返回的实例为PathMatchingResourcePatternResolver类型
- MetadataReaderFactory用于解析资源信息对应的元数据,这里返回的实例为:CachingMetadataReaderFactory,带有缓存
- CandidateComponentsIndexLoader.loadIndex () 方法是spring5.0以后加入的新特性,Spring Framework 5 改进了扫描和识别组件的方法,使大型项目的性能得到提升。(具体是通过编译器完成扫描,并且往本地写索引,然后启动的时候再去扫描索引即可的思路)
至此,ClassPathBeanDefinitionScanner初始化完毕,总结一下:
ClassPathBeanDefinitionScanner是一个扫描指定类路径中注解Bean定义的扫描器,在它初始化的时候,会初始化一些需要被扫描的注解,初始化用于加载包下的资源的Loader。
AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner的初始化是spring上线文初始化的起点,很多预加载的类会在spring接下来的初始化中发挥重要作用。
实际逻辑在doRegisterBean()此方法上:org.springframework.context.annotation.AnnotatedBeanDefinitionReader#doRegisterBean
private <T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,
@Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {
// 先把此实体类型转换为一个BeanDefinition
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
//abd.getMetadata() 元数据包括注解信息、是否内部类、类Class基本信息等等
// 此处由conditionEvaluator#shouldSkip去过滤,此Class是否是配置类。
// 大体逻辑为:必须有@Configuration修饰。然后解析一些Condition注解,看是否排除~
if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
return;
}
abd.setInstanceSupplier(instanceSupplier);
// 解析Scope
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
abd.setScope(scopeMetadata.getScopeName());
// 得到Bean的名称 一般为首字母小写(此处为AnnotationBeanNameGenerator)
String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
// 设定一些注解默认值,如lazy、Primary等等
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
// 解析qualifiers,若有此注解 则primary都成为true了
if (qualifiers != null) {
for (Class<? extends Annotation> qualifier : qualifiers) {
if (Primary.class == qualifier) {
abd.setPrimary(true);
}
else if (Lazy.class == qualifier) {
abd.setLazyInit(true);
}
else {
abd.addQualifier(new AutowireCandidateQualifier(qualifier));
}
}
}
// 自定义定制信息(一般都不需要)
for (BeanDefinitionCustomizer customizer : definitionCustomizers) {
customizer.customize(abd);
}
// 下面位解析Scope是否需要代理,最后把这个Bean注册进去
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}
包扫描: org.springframework.context.annotation.ClassPathBeanDefinitionScanner#scan
下面就是重点看看doScan()方法:
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
// 装载扫描到的Bean
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
for (String basePackage : basePackages) {
// 这个方法是最重点,把扫描到的Bean就放进来了(比如此处只有RootConfig一个Bean定义,是个配置类)
// 这个是重点,会把该包下面所有的Bean都扫描进去。Spring5和一下的处理方式不一样哦~
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
for (BeanDefinition candidate : candidates) {
// 拿到Scope元数据:此处为singleton
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
// 生成Bean的名称,默认为首字母小写。此处为"rootConfig"
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
// 此处为扫描的Bean,为ScannedGenericBeanDefinition,所以肯定为true
// 因此进来,执行postProcessBeanDefinition(对Bean定义信息做) 如下详解
// 注意:只是添加些默认的Bean定义信息,并不是执行后置处理器~~~
if (candidate instanceof AbstractBeanDefinition) {
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
// 显然,此处也是true 也是完善比如Bean上的一些注解信息:比如@Lazy、@Primary、@DependsOn、@Role、@Description @Role注解用于Bean的分类分组,没有太大的作用
if (candidate instanceof AnnotatedBeanDefinition) {
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
// 检查这个Bean 比如
//如果dao包(一般配置的basePakage是这个)下的类是符合mybaits要求的则向spring IOC容器中注册它的BeanDefinition 所以这步检查第三方Bean的时候有必要检查一下
if (checkCandidate(beanName, candidate)) {
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
//AnnotationConfigUtils类的applyScopedProxyMode方法根据注解Bean定义类中配置的作用域@Scope注解的值,为Bean定义应用相应的代理模式,主要是在Spring面向切面编程(AOP)中使用
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
// 注意 注意 注意:这里已经吧Bean注册进去工厂了,所有doScan()方法不接收返回值,也是没有任何问题的。。。。
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
ClassPathScanningCandidateComponentProvider#findCandidateComponents
public Set<BeanDefinition> findCandidateComponents(String basePackage) {
// 上面说过了CandidateComponentsIndex是Spring5提供的优化扫描的功能
// 显然这里编译器我们没有写META-INF/spring.components索引文件,所以此处不会执行Spring5 的扫描方式,所以我暂时不看了(超大型项目才会使用Spring5的方式)
if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
} else {
// Spring 5之前的方式(绝大多数情况下,都是此方式)
return scanCandidateComponents(basePackage);
}
}
scanCandidateComponents:根据basePackage扫描候选的组件们(非常重要)
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
Set<BeanDefinition> candidates = new LinkedHashSet<>();
try {
// 1.根据指定包名 生成包搜索路径
//通过观察resolveBasePackage()方法的实现, 我们可以在设置basePackage时, 使用形如${}的占位符, Spring会在这里进行替换 只要在Enviroment里面就行
// 本次值为:classpath*:com/fsx/config/**/*.class
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + '/' + this.resourcePattern;
//2. 资源加载器 加载搜索路径下的 所有class 转换为 Resource[]
// 拿着上面的路径,就可以getResources获取出所有的.class类,这个很强大~~~
// 真正干事的为:PathMatchingResourcePatternResolver#getResources方法
// 此处能扫描到两个类AppConfig(普通类,没任何注解标注)和RootConfig。所以接下里就是要解析类上的注解,以及过滤掉不是候选的类(比如AppConfig)
// 注意:这里会拿到类路径下(不包含jar包内的)的所有的.class文件 可能有上百个,然后后面再交给后面进行筛选~~~~~~~~~~~~~~~~(这个方法,其实我们也可以使用)
// 当然和getResourcePatternResolver和这个模版有关
Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
// 记录日志(下面我把打印日志地方都删除)
boolean traceEnabled = logger.isTraceEnabled();
boolean debugEnabled = logger.isDebugEnabled();
// 接下来的这个for循环:就是把一个个的resource组装成
for (Resource resource : resources) {
//文件必须可读 否则直接返回空了
if (resource.isReadable()) {
try {
//读取类的 注解信息 和 类信息 ,两大信息储存到 MetadataReader
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
// 根据TypeFilter过滤排除组件。因为AppConfig没有标准@Component或者子注解,所以肯定不属于候选组件 返回false
// 注意:这里一般(默认处理的情况下)标注了默认注解的才会true,什么叫默认注解呢?就是@Component或者派生注解。还有javax....的,这里省略啦
if (isCandidateComponent(metadataReader)) {
//把符合条件的 类转换成 BeanDefinition
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
sbd.setResource(resource);
sbd.setSource(resource);
// 再次判断 如果是实体类 返回true,如果是抽象类,但是抽象方法 被 @Lookup 注解注释返回true (注意 这个和上面那个是重载的方法)
// 这和上面是个重载方法 个人觉得旨在处理循环引用以及@Lookup上
if (isCandidateComponent(sbd)) {
candidates.add(sbd);
}
}
}
}
}
}
return candidates;
}
// 备注:此时ComponentScan这个注解还并没有解析
ClassPathBeanDefinitionScanner#postProcessBeanDefinition
protected void postProcessBeanDefinition(AbstractBeanDefinition beanDefinition, String beanName) {
// 位Bean定义 执行些默认的信息
// BeanDefinitionDefaults是个标准的javaBean,有一些默认值
beanDefinition.applyDefaults(this.beanDefinitionDefaults);
// 自动依赖注入 匹配路径(此处为null,不进来)
if (this.autowireCandidatePatterns != null) {
beanDefinition.setAutowireCandidate(PatternMatchUtils.simpleMatch(this.autowireCandidatePatterns, beanName));
}
}
//AbstractBeanDefinition#applyDefaults:
public void applyDefaults(BeanDefinitionDefaults defaults) {
setLazyInit(defaults.isLazyInit());
setAutowireMode(defaults.getAutowireMode());
setDependencyCheck(defaults.getDependencyCheck());
setInitMethodName(defaults.getInitMethodName());
setEnforceInitMethod(false);
setDestroyMethodName(defaults.getDestroyMethodName());
setEnforceDestroyMethod(false);
}
就这样,扫描的Bean就全部注册完成了(若你的Config比较多的情况下,用扫描的方式更加简单些~)
BeanDefinition注册中心BeanDefinitionRegistry
BeanDefinitionRegistry是一个接口, 实现了AliasRegistry接口, 定义了一些对 bean的常用操作。
它有大概如下功能:
- 以Map<String, BeanDefinition>的形式注册bean
- 根据beanName 删除和获取 beanDefiniation
- 得到持有的beanDefiniation的数目
- 根据beanName 判断是否包含beanDefiniation
// 它继承自 AliasRegistry
public interface BeanDefinitionRegistry extends AliasRegistry {
// 关键 -> 往注册表中注册一个新的 BeanDefinition 实例
void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException;
// 移除注册表中已注册的 BeanDefinition 实例
void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
// 从注册中心取得指定的 BeanDefinition 实例
BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
// 判断 BeanDefinition 实例是否在注册表中(是否注册)
boolean containsBeanDefinition(String beanName);
// 取得注册表中所有 BeanDefinition 实例的 beanName(标识)
String[] getBeanDefinitionNames();
// 返回注册表中 BeanDefinition 实例的数量
int getBeanDefinitionCount();
// beanName(标识)是否被占用
boolean isBeanNameInUse(String beanName);
}
下面看看它们的继承关系:
可以看出,它的默认实现类,主要有三个:SimpleBeanDefinitionRegistry、DefaultListableBeanFactory、GenericApplicationContext
SimpleBeanDefinitionRegistry
它是默认的一个实现方式,也是一个非常简单的实现。存储用的是ConcurrentHashMap ,可以保证线程安全
// @since 2.5.2可以看到提供得还是比较晚的
// AliasRegistry和SimpleAliasRegistry都是@since 2.5.2之后才有的~~~
public class SimpleBeanDefinitionRegistry extends SimpleAliasRegistry implements BeanDefinitionRegistry {
// 采用的ConcurrentHashMap来存储注册进来的Bean定义信息~~~~
/** Map of bean definition objects, keyed by bean name */
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(64);
... // 各种实现都异常的简单,都是操作map
// 这里只简单说说这两个方法
// 需要注意的是:如果没有Bean定义,是抛出的异常,而不是返回null这点需要注意
@Override
public BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {
BeanDefinition bd = this.beanDefinitionMap.get(beanName);
if (bd == null) {
throw new NoSuchBeanDefinitionException(beanName);
}
return bd;
}
// beanName是个已存在的别名,或者已经包含此Bean定义了,那就证明在使用了嘛
// 它比单纯的containsBeanDefinition()范围更大些~~~
@Override
public boolean isBeanNameInUse(String beanName) {
return isAlias(beanName) || containsBeanDefinition(beanName);
}
}
DefaultListableBeanFactory
该类是 BeanDefinitionRegistry 接口的基本实现类,但同时也实现其他了接口的功能,这里关注注册 BeanDefinition 实例的相关方法。
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
...
/** Map of bean definition objects, keyed by bean name */
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
// 保存所有的Bean名称
/** List of bean definition names, in registration order */
private volatile List<String> beanDefinitionNames = new ArrayList<>(256);
// 注册Bean定义信息~~
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
...
BeanDefinition oldBeanDefinition = this.beanDefinitionMap.get(beanName);
// 如果不为null,说明这个beanName对应的Bean定义信息已经存在了~~~~~
if (oldBeanDefinition != null) {
// 是否允许覆盖(默认是true 表示允许的)
if (!isAllowBeanDefinitionOverriding()) {
// 抛异常
}
// 若允许覆盖 那还得比较下role 如果新进来的这个Bean的role更大
// 比如老的是ROLE_APPLICATION(0) 新的是ROLE_INFRASTRUCTURE(2)
// 最终会执行到put,但是此处输出一个warn日志,告知你的bean被覆盖啦~~~~~~~(我们自己覆盖Spring框架内的bean显然就不需要warn提示了)
else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
// 仅仅输出一个logger.warn
}
// 最终会执行put,但是内容还不相同 那就提醒一个info信息吧
else if (!beanDefinition.equals(oldBeanDefinition)) {
// 输出一个info信息
}
else {
// 输出一个debug信息
}
// 最终添加进去 (哪怕已经存在了~)
// 从这里能看出Spring对日志输出的一个优秀处理,方便我们定位问题~~~
this.beanDefinitionMap.put(beanName, beanDefinition);
// 请注意:这里beanName并没有再add了,因为已经存在了 没必要了嘛
}
else {
// hasBeanCreationStarted:表示已经存在bean开始创建了(开始getBean()了吧~~~)
if (hasBeanCreationStarted()) {
// 注册过程需要synchronized,保证数据的一致性 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
// 表示仍然在启动 注册的状态~~~就很好处理了 put仅需,名字add进去
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
// 手动注册的BeanNames里面移除~~~ 因为有Bean定义信息了,所以现在不是手动直接注册的Bean单例~~~~
this.manualSingletonNames.remove(beanName);
}
// 这里的意思是:但凡你新增了一个新的Bean定义信息,之前已经冻结的就清空呗~~~
this.frozenBeanDefinitionNames = null;
}
// 最后异步很有意思:老的bean定义信息不为null(beanName已经存在了),或者这个beanName直接是一个单例Bean了~
if (oldBeanDefinition != null || containsSingleton(beanName)) {
// 做清理工作:
// clearMergedBeanDefinition(beanName)
// destroySingleton(beanName); 销毁这个单例Bean 因为有了该bean定义信息 最终还是会创建的
// Reset all bean definitions that have the given bean as parent (recursively). 处理该Bean定义的getParentName 有相同的也得做清楚 所以这里是个递归
resetBeanDefinition(beanName);
}
}
@Override
public void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {
// 移除整体上比较简单:beanDefinitionMap.remove
// beanDefinitionNames.remove
// resetBeanDefinition(beanName);
BeanDefinition bd = this.beanDefinitionMap.remove(beanName);
// 这里发现移除,若这个Bean定义本来就不存在,事抛异常,而不是返回null 需要注意~~~~
if (bd == null) {
throw new NoSuchBeanDefinitionException(beanName);
}
if (hasBeanCreationStarted()) {
synchronized (this.beanDefinitionMap) {
List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames);
updatedDefinitions.remove(beanName);
this.beanDefinitionNames = updatedDefinitions;
}
} else {
this.beanDefinitionNames.remove(beanName);
}
this.frozenBeanDefinitionNames = null;
resetBeanDefinition(beanName);
}
// 这个实现非常的简单,直接从map里拿
@Override
public BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {
BeanDefinition bd = this.beanDefinitionMap.get(beanName);
if (bd == null) {
throw new NoSuchBeanDefinitionException(beanName);
}
return bd;
}
@Override
public boolean containsBeanDefinition(String beanName) {
return this.beanDefinitionMap.containsKey(beanName);
}
@Override
public int getBeanDefinitionCount() {
return this.beanDefinitionMap.size();
}
@Override
public String[] getBeanDefinitionNames() {
String[] frozenNames = this.frozenBeanDefinitionNames;
if (frozenNames != null) {
return frozenNames.clone();
}
else {
return StringUtils.toStringArray(this.beanDefinitionNames);
}
}
// ==========这个方法非常有意思:它是间接的实现的===============
// 因为BeanDefinitionRegistry有这个方法,而它的父类AbstractBeanFactory也有这个方法,所以一步小心,就间接的实现了这个接口方法
public boolean isBeanNameInUse(String beanName) {
// 增加了一个hasDependentBean(beanName); 或者这个BeanName是依赖的Bean 也会让位被使用了
return isAlias(beanName) || containsLocalBean(beanName) || hasDependentBean(beanName);
}
}
DefaultListableBeanFactory它对Bean定义注册中心接口的实现逻辑。
XmlBeanFactory
它是DefaultListableBeanFactory的子类。Spring3.1之后建议用DefaultListableBeanFactory代替
@Deprecated
@SuppressWarnings({"serial", "all"})
public class XmlBeanFactory extends DefaultListableBeanFactory {
private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
// 此处resource资源事传一个xml的文件资源~~~~
// parentBeanFactory:父工厂~~~
public XmlBeanFactory(Resource resource) throws BeansException {
this(resource, null);
}
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
super(parentBeanFactory);
this.reader.loadBeanDefinitions(resource);
}
}
GenericApplicationContext
这是一个通用的Spring上下文了,之前也说到了,它基本什么都得靠自己手动来处理:
public static void main(String[] args) {
GenericApplicationContext ctx = new GenericApplicationContext();
//手动使用XmlBeanDefinitionReader
XmlBeanDefinitionReader xmlReader = new XmlBeanDefinitionReader(ctx);
//加载ClassPathResource
xmlReader.loadBeanDefinitions(new ClassPathResource("spring.xml"));
//=========我们可议执行多次loadBeanDefinitions,从不同的地方把Bean定义信息给拿过来,最后再启动容器即可==============
备注:此处的bean都采用properties的方式去配置(基本没人会这么使用了)
//PropertiesBeanDefinitionReader propReader = new PropertiesBeanDefinitionReader(ctx);
//propReader.loadBeanDefinitions(new ClassPathResource("spring.properties"));
//调用Refresh方法 启动容器(这个都需要手动 哈哈)
ctx.refresh();
//和其他ApplicationContext方法一样的使用方式
System.out.println(ctx.getBean("person")); //com.fsx.bean.Person@1068e947
}
spring.xml如下:
<bean id="person" class="com.fsx.bean.Person"/>
因为是手动档,对API的使用有一定的门槛,因此我们一般情况下不会直接使用它。但是它有两个子类我们是比较熟悉的。
GenericXmlApplicationContext
利用XML来配置Bean的定义信息,借助XmlBeanDefinitionReader去读取~~~
public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {
// 这个很重要:它持有一个DefaultListableBeanFactory的引用
private final DefaultListableBeanFactory beanFactory;
// 所以下面所有的 BeanDefinitionRegistry 相关的方法都是委托给beanFactory去做了的,因此省略~~~
}
AbstractApplicationContext最终也是委托给getBeanFactory()去做这些事。而最终的实现都是它:DefaultListableBeanFactory
备注:AnnotationConfigWebApplicationContext、XmlWebApplicationContext都继承自AbstractRefreshableConfigApplicationContext,从而也最终继承了AbstractApplicationContext。
AnnotationConfigApplicationContext
注解驱动去扫描Bean的定义信息。先用ClassPathBeanDefinitionScanner把文件都扫描进来,然后用AnnotatedBeanDefinitionReader去load没有里面的Bean定义信息。
说明:由上面的继承关系可以看出,上文顶层接口ApplicationContext是不提供直接注册Bean定义信息、删除等一些操作的。因为ApplicationContext它并没有实现此接口BeanDefinitionRegistry,但是它继承了接口ListableBeanFactory,所以它有如下三个能力:
boolean containsBeanDefinition(String beanName);
int getBeanDefinitionCount();
String[] getBeanDefinitionNames();
ApplicationContext体系里只有子体系GenericApplicationContext下才能直接操作注册中心。比如常用的:GenericXmlApplicationContext和AnnotationConfigApplicationContext。
手动注册BeanDefinition(编程方式注册Bean定义)
手动注册bean的两种方式:
- 实现ImportBeanDefinitionRegistrar
- 实现BeanDefinitionRegistryPostProcessor
有个重要实现类ConfigurationClassPostProcessor,它是来处理@Configuration配置文件的。它最终就是解析配置文件里的@Import、@Bean等,然后把定义信息都注册进去~~~
参考: |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!