一、bean的定义BeanDefinition
-
BeanDefinition的含义 BeanDefinition就是用来描述一个Bean或者BeanDefinition就是Bean的定义。
**Spirng官网描述** SpringIoc容器管理一个Bean或多个Bean,这些Bean通过我们提供给容器的配置元数据被创建出来(例如,在xml中的定义) 在容器中,这些Bean的定义用BeanDefinition对象来表示, 包含以下元数据: 全限定类名, 通常是Bean的实际实现类; Bean行为配置元素,它们说明Bean在容器中的行为(作用域、生命周期回调等等); Bean执行工作所需要的的其他Bean的引用,这些Bean也称为协作者或依赖项; 其他配置信息,例如,管理连接池的bean中,限制池的大小或者使用的连接的数量。
在Spring容器中,定义bean的方式:
-
<bean/>标签 @Bean注解 @Component(@Service、@Controller)
从xml配置文件或者类路径中收集Spring需要的管理对象
在Spring的启动过程第一步就是找到需要被管理的类,比如标注的@Configuration类
找到之后将这些类封装到BeanDefinition对象,也就是bean,包含了这些类的全部信息BeanDefinition是一个接口,有三个实现RootBeanDefinition、ChildBeanDefinition、GenericBeanDefinition。所以也可以通过BeanDefinition这个对象定义一个bean。我们通过,@Bean,@Component等方式所定义的Bean,最终都会被解析为BeanDefinition对象,所有的。
-
使用BeanDefinition定义bean的流程:
导入依赖: <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.6.RELEASE</version> </dependency> 测试实体类: public class User { private Long id; private String name; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public void init(){ System.out.println("初始化"); } } 启动类: public static void main(String[] args) { // 定义了一个BeanDefinition AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition() .getBeanDefinition(); // 当前Bean对象的类型 beanDefinition.setBeanClass(User.class); // 将BeanDefinition注册到BeanFactory中 DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); beanFactory.registerBeanDefinition("user", beanDefinition); // 获取Bean System.out.println(beanFactory.getBean("user")); } 结果:com.gongj.entity.User@70177ecd **BeanDefinition可以设置其他属性** // 设置作用域 beanDefinition.setScope("prototype"); // 设置初始化方法 beanDefinition.setInitMethodName("init"); // 设置自动装配模型 beanDefinition.setAutowireMode(AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE); 结果: 初始化 com.gongj.entity.User@1e88b3c
BeanDefinition继承关系
-
AttributeAccessor:定义用于附加和访问元数据的通用协定的接口,可以是任意对象。
-
public interface AttributeAccessor { //设置属性的值(名称唯一) void setAttribute(String name, Object value); //获得指定属性名称的值,如果不存在返回null Object getAttribute(String name); //删除指定的name的属性,如果不存在则返回null Object removeAttribute(String name); //判断指定的属性名称是否存在 boolean hasAttribute(String name); //返回所有属性的名称 String[] attributeNames(); }
BeanDefinition的源码:
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; //用户自己定义的 Bean
int ROLE_SUPPORT = 1; //来源于配置文件的 Bean
int ROLE_INFRASTRUCTURE = 2;//Spring 内部的 Bean
//配置 /获取父BeanDefinition的名称 XML中的 <bean parent="">
void setParentName(@Nullable String parentName);
@Nullable
String getParentName();
//配置/获取 Bean 的 Class 全路径 XML 中的 <bean class="">
void setBeanClassName(@Nullable String beanClassName);
@Nullable
String getBeanClassName();
//配置/获取 Bean 的作用域 XML中的 <bean scope=""> 配置。
void setScope(@Nullable String scope);
@Nullable
String getScope();
//配置 / 获取 Bean 是否懒加载(默认false,立马加载)
// XML 中的 <bean lazy-init="">
void setLazyInit(boolean lazyInit);
boolean isLazyInit();
//配置/获取 Bean 的依赖对象 XML中的 <bean depends-on="">
void setDependsOn(@Nullable String... dependsOn);
@Nullable
String[] getDependsOn();
//配置/获取 Bean 是否是自动装配的候选者 默认为 true XML中的 <bean autowire-candidate="">
void setAutowireCandidate(boolean autowireCandidate);
boolean isAutowireCandidate();
//如果找到了多个可注入bean,那么则选择被Primary标记的bean/获取当
//前 Bean 是否为首选的 Bean XML中的 <bean primary="">
void setPrimary(boolean primary);
boolean isPrimary();
// 配置/获取 FactoryBean 的名字 XML中的<bean factory-bean="">
void setFactoryBeanName(@Nullable String factoryBeanName);
@Nullable
String getFactoryBeanName();
//配置/获取 FactoryMethod 的名字,可以是某个实例的方法(和factoryBean配合使用)
//也可以是静态方法。 XML 中的<bean factory-method="">
void setFactoryMethodName(@Nullable String factoryMethodName);
@Nullable
String getFactoryMethodName();
//返回该 Bean 构造方法的参数值
ConstructorArgumentValues getConstructorArgumentValues();
//判断 getConstructorArgumentValues 是否是空对象。
default boolean hasConstructorArgumentValues() {
return !getConstructorArgumentValues().isEmpty();
}
//获取普通属性的集合
MutablePropertyValues getPropertyValues();
//判断 getPropertyValues 是否为空对象
default boolean hasPropertyValues() {
return !getPropertyValues().isEmpty();
}
// 配置/获取 Bean 的初始化方法 XML中的<bean init-method="">
void setInitMethodName(@Nullable String initMethodName);
@Nullable
String getInitMethodName();
// 配置/获取 Bean 的销毁方法 XML中的<bean destroy-method="">
void setDestroyMethodName(@Nullable String destroyMethodName);
@Nullable
String getDestroyMethodName();
//配置/获取 Bean的角色
void setRole(int role);
int getRole();
//配置/获取 Bean 的描述
void setDescription(@Nullable String description);
@Nullable
String getDescription();
//用来解析一个Bean对应的类型上的各种信息,比如泛型
ResolvableType getResolvableType();
//是否为单例
boolean isSingleton();
// 是否为原型
boolean isPrototype();
//是否抽象 XML 中的<bean abstract="true">
boolean isAbstract();
//返回定义 Bean 的资源描述
@Nullable
String getResourceDescription();
// 如果当前 BeanDefinition 是一个代理对象,那么该方法可以用来返回原始的 BeanDefinition
@Nullable
BeanDefinition getOriginatingBeanDefinition();
}
具体关系图:
一、先说AbstractBeanDefinition AbstractBeanDefinition是一个抽象类,在BeanDefinition接口中只定义了get和set方法, 没有提供属性,具体的属性在AbstractBeanDefinition中定义
-
1、源码:
```Java
public abstract class AbstractBeanDefinition extends
BeanMetadataAttributeAccessor
implements BeanDefinition, Cloneable {
//默认作用域名称的常量:等效于单例
public static final String SCOPE_DEFAULT = "";
//自动装配的一些常量
// autowireMode = 0,默认值,未激活Autowiring。
// bean 标签的 autowire 属性值为 no
// 1、在xml中需要手动指定依赖注入对象 配置 property标签或者 constructor-arg标签
// 2、使用 @Autowired 注解,autowireMode 的值也是 0
public static final int AUTOWIRE_NO = AutowireCapableBeanFactory.AUTOWIRE_NO;
//autowireMode = 1,根据set方法的的名称作为Bean名称进行依赖查找
//(去掉set,并尝试将首字母变为小写),并将对象设置到该set方法的参数上
// bean 标签的 autowire 属性值配置为 byName
public static final int AUTOWIRE_BY_NAME =
AutowireCapableBeanFactory.AUTOWIRE_BY_NAME;
//autowireMode = 2,根据set方法参数的类型作为Bean类型进行依赖查找
//并将对象设置到该set方法的参数上
// bean 标签的 autowire 属性值配置为 byType
public static final int AUTOWIRE_BY_TYPE =
AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE;
//autowireMode = 3,构造器注入
// bean 标签的 autowire 属性值配置为 constructor
public static final int AUTOWIRE_CONSTRUCTOR =
AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR;
//表明通过Bean的class的内部来自动装配 Spring3.0被弃用。
// bean 标签的 autowire 属性值配置为 autodetect
@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
public static final String INFER_METHOD = "(inferred)";
//Bean的class对象或是类的全限定名
@Nullable
private volatile Object beanClass;
//默认的scope是单例,对应bean属性scope
//@Scope
@Nullable
private String scope = SCOPE_DEFAULT;
//是否是抽象,对应bean属性abstract
private boolean abstractFlag = false;
//是否懒加载,对应bean属性lazy-init,默认不是懒加载
//@Lazy
@Nullable
private Boolean lazyInit;
//自动注入模式,对应bean属性autowire,默认不进行自动装配
private int autowireMode = AUTOWIRE_NO;
//是否进行依赖检查,默认不进行依赖检查
private int dependencyCheck = DEPENDENCY_CHECK_NONE;
//用来表示一个bean的实例化是否依靠另一个bean的实例化,先加载dependsOn的bean,
//对应bean属性depend-on
//@DependsOn
@Nullable
private String[] dependsOn;
/**
* autowire-candidate属性设置为false,这样容器在查找自动装配对象时,
* 将不考虑该bean,即它不会被考虑作为其他bean自动装配的候选者,
* 但是该bean本身还是可以使用自动装配来注入其他bean的
*/
private boolean autowireCandidate = true;
/**
* 自动装配时出现多个bean候选者时,将作为首选者,对应bean属性primary,默认不是首选的
* @Primary
*/
private boolean primary = false;
/**
* 用于记录Qualifier,对应子元素qualifier <bean><qualifier></qualifier></bean>
* 如果容器中有多个相同类型的 bean,
这时我们就可以使用qualifier属性来设置加载指定Bean名称的bean
* @Qualifier
*/
private final Map < String, AutowireCandidateQualifier > qualifiers =
new LinkedHashMap <>();
//java8的函数式接口,创建bean实例的方式之一
@Nullable
private Supplier <? > instanceSupplier;
//是否允许访问非public方法和属性, 默认是true
private boolean nonPublicAccessAllowed = true;
/**
* 是否以一种宽松的模式解析构造函数,默认为true,
* 如果为false,则在以下情况
* interface ITest{}
* class ITestImpl implements ITest{};
* class Main {
* Main(ITest i) {}
* Main(ITestImpl i) {}
* }
* 抛出异常,因为Spring无法准确定位哪个构造函数程序设置
*/
private boolean lenientConstructorResolution = true;
//工厂类名,对应bean属性factory-bean
@Nullable
private String factoryBeanName;
//工厂方法名,对应bean属性factory-method
@Nullable
private String factoryMethodName;
//记录构造函数注入属性,对应bean属性constructor-arg
@Nullable
private ConstructorArgumentValues constructorArgumentValues;
//Bean属性的名称以及对应的值,这里不会存放构造函数相关的参数值,只会存放通过setter注入的值
@Nullable
private MutablePropertyValues propertyValues;
//方法重写的持有者,记录lookup-method、replaced-method元素 @Lookup
private MethodOverrides methodOverrides = new MethodOverrides();
//初始化方法,对应bean属性init-method
@Nullable
private String initMethodName;
//销毁方法,对应bean属性destroy-method
@Nullable
private String destroyMethodName;
//是否执行init-method,默认为true
private boolean enforceInitMethod = true;
//是否执行destroy-method,默认为true
private boolean enforceDestroyMethod = true;
//是否是用户定义的而不是应用程序本身定义的,创建AOP时候为true
private boolean synthetic = false;
//Bean的角色,为用户自定义Bean
private int role = BeanDefinition.ROLE_APPLICATION;
//Bean的描述信息
@Nullable
private String description;
//这个bean定义的资源
@Nullable
private Resource resource;
//...
}
2、AbstractBeanDefinition的三个子类:
-
GenericBeanDefinition: GenericBeanDefinition 是从 Spring2.5 以后新加入的 bean 文件配置属性定义类,是一站式服务类。GenericBeanDefinition 可以动态设置父 Bean,同时兼具 RootBeanDefinition 和 ChildBeanDefinition 的功能。 GenericBeanDefinition 的实现比较简单,在 AbstractBeanDefinition 的基础上只增加了parentName的功能,其余的实现都在父类 AbstractBeanDefinition 里。 注:若你是xml配置,会解析所有属性并统一封装至 GenericBeanDefinition 类型的实例中,之后再逐渐解析的。
-
RootBeanDefinition:
-
源码:
-
public class RootBeanDefinition extends AbstractBeanDefinition {
// BeanDefinitionHolder 存储 Bean 的名称、别名、BeanDefinition
@Nullable
private BeanDefinitionHolder decoratedDefinition;
// AnnotatedElement 是java反射包的接口,通过它可以查看 Bean 的注解信息
@Nullable
private AnnotatedElement qualifiedElement;
// 决定了什么时候 BeanDefinition 需要重新合并
volatile Boolean stale;
// 允许缓存
Boolean allowCaching = true;
// 工厂方法是否唯一
Boolean isFactoryMethodUnique = false;
//封装了 java.lang.reflect.Type,提供了泛型相关的操作
@Nullable
volatile ResolvableType targetType;
//用于缓存给定bean定义中确定的类
// 表示 RootBeanDefinition 存储哪个类的信息
@Nullable
volatile Class<?> resolvedTargetType;
//如果bean是FactoryBean,则用于缓存
@Nullable
volatile Boolean isFactoryBean;
//用于缓存泛型类型工厂方法的返回类型
@Nullable
volatile ResolvableType factoryMethodReturnType;
//用于缓存唯一的工厂方法
@Nullable
volatile Method factoryMethodToIntrospect;
//下面四个构造函数字段的公共锁
final Object constructorArgumentLock = new Object();
// 用用于缓存已解析的构造函数或工厂方法
@Nullable
Executable resolvedConstructorOrFactoryMethod;
//将构造函数参数标记为已解析
Boolean constructorArgumentsResolved = false;
//用于缓存完全解析的构造函数参数
@Nullable
Object[] resolvedConstructorArguments;
//用于缓存部分准备好的构造函数参数
@Nullable
Object[] preparedConstructorArguments;
//下面两个后处理字段的通用锁
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是没有父BeanDefinition
@Override
public String getParentName() {
return null;
}
// 并且还不能进行set
@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");
}
}
}
Spring创建Bean的时候就是基于RootBeanDefinition来创建的,并且RootBeanDefinition是没 有父BeanDefinition的(可以单独存在,不需要依赖父BeanDefinition)
ChildBeanDefinition: 继承自 AbstractBeanDefinition。其相当于一个子类,不可以单独存在,必须依赖一个父 BeanDetintion,构造 ChildBeanDefinition 时,通过构造方法传入父 BeanDetintion 的名称或通过 setParentName 设置父名称。它可以从父类继承方法参数、属性值,并可以重写父类的方法,同时也可以增加新的属性或者方法。(从 Spring 2.5 开始,以编程方式注册 Bean 定义的首选方法是 GenericBeanDefinition,GenericBeanDefinition 可以有效替代 ChildBeanDefinition 的绝大分部使用场合。)
-
二、再说BeanDefinition
-
BeanDefinition的子接口:
-
AnnotatedBeanDefinition源码:
//关于其bean类-无需加载该类。 public interface AnnotatedBeanDefinition extends BeanDefinition { //获取此bean定义注解的元数据 **AnnotationMetadata** getMetadata(); //获取此bean定义的工厂方法的元数据,如果没有,则为null @Nullable **MethodMetadata** getFactoryMethodMetadata(); }
-
-
AnnotatedBeanDefinition可以返回两个元数据的类: AnnotationMetadata : 主要对 Bean 的注解信息进行操作,如:获取当前 Bean 标注的所有注解、判断是否包含指定注解。
-
源码:
public interface AnnotationMetadata extends ClassMetadata, AnnotatedTypeMetadata { //获取所有注解完全限定类名 default Set<String> getAnnotationTypes() { return getAnnotations().stream() .filter(MergedAnnotation::isDirectlyPresent) .map(annotation -> annotation.getType().getName()) .collect(Collectors.toCollection(LinkedHashSet::new)); } //获得annottationName对应的元注解的类全限定名 default Set<String> getMetaAnnotationTypes(String annotationName) { MergedAnnotation<?> annotation = getAnnotations().get(annotationName, MergedAnnotation::isDirectlyPresent); if (!annotation.isPresent()) { return Collections.emptySet(); } return MergedAnnotations.from(annotation.getType(), SearchStrategy.INHERITED_ANNOTATIONS).stream() .map(mergedAnnotation -> mergedAnnotation.getType().getName()) .collect(Collectors.toCollection(LinkedHashSet::new)); } //是否包含指定注解 default boolean hasAnnotation(String annotationName) { return getAnnotations().isDirectlyPresent(annotationName); } //确定是否含有某个元注解 default boolean hasMetaAnnotation(String metaAnnotationName) { return getAnnotations().get(metaAnnotationName, MergedAnnotation::isMetaPresent).isPresent(); } //类里面只要有一个方法标注有指定注解,就返回true default boolean hasAnnotatedMethods(String annotationName) { return !getAnnotatedMethods(annotationName).isEmpty(); } // 返回所有的标注有指定注解的方法元信息 Set<MethodMetadata> getAnnotatedMethods(String annotationName); //工厂方法来使用标准反射为给定的类创建一个新的AnnotationMetadata实例 static AnnotationMetadata introspect(Class<?> type) { return StandardAnnotationMetadata.from(type); } }
MethodMetadata : 方法的元数据类。提供获取方法名称、此方法所属类的全类名、是否是抽象方法、判断是否是静态方法、判断是否是final方法等。
-
源码:
public interface MethodMetadata extends AnnotatedTypeMetadata { //返回方法的名字 String getMethodName(); //返回该方法所属的类的全限定名 String getDeclaringClassName(); //返回该方法返回类型的全限定名 String getReturnTypeName(); //方法是否是有效的抽象方法:即在类上标记为抽象的或声明为规则的, //接口中的非默认方法。 boolean isAbstract(); //方法是否声明为'static'。 boolean isStatic(); //方法是否标记为'final'。 boolean isFinal(); //方法是否可重写:即没有标记为static、final或private。 boolean isOverridable(); }
AnnotatedBeanDefinition下面的三个子类:
-
ScannedGenericBeanDefinition: 实现了 AnnotatedBeanDefinition 也继承了 GenericBeanDefinition。这个 BeanDefinition 用来描述标注@Component、@Service、@Controller等注解标记的类会解析为 ScannedGenericBeanDefinition。
-
源码 多了一个属性:
metadata
用来存储扫描进来的Bean
的一些注解信息。public class ScannedGenericBeanDefinition extends GenericBeanDefinition implements AnnotatedBeanDefinition { private final AnnotationMetadata metadata; /** * 鉴于MetadataReader描述,为类创建一个新的ScannedGenericBeanDefinition */ public ScannedGenericBeanDefinition(MetadataReader metadataReader) { Assert.notNull(metadataReader, "MetadataReader must not be null"); this.metadata = metadataReader.getAnnotationMetadata(); setBeanClassName(this.metadata.getClassName()); } @Override public final AnnotationMetadata getMetadata() { return this.metadata; } @Override @Nullable public MethodMetadata getFactoryMethodMetadata() { return null; } }
-
ConfigurationClassBeanDefinition: 它是ConfigurationClassBeanDefinitionReader的一个私有的静态内部类:这个类负责将@Bean注解的方法转换为对应的ConfigurationClassBeanDefinition 类,源码就不过多解释了,和之前几个BeanDefinition差不多。 其功能特点如下: 1、如果 @Bean 注解没有指定 Bean 的名字,默认会用方法的名字作为Bean的名称。 2、标注 @Configuration、@Component、@Service 注解的类会成为一个工厂类,而标注 @Bean 注解的方法会成为工厂方法,通过工厂方法实例化 Bean。
-
AnnotatedGenericBeanDefinition: 该类继承自 GenericBeanDefinition ,并实现了AnnotatedBeanDefinition 接口。这个 BeanDefinition 用来描述标注使用了 @Configuration 注解标记配置类会解析为 AnnotatedGenericBeanDefinition。
-
源码
public class AnnotatedGenericBeanDefinition extends GenericBeanDefinition implements AnnotatedBeanDefinition { // 注解元数据 private final AnnotationMetadata metadata; @Nullable private MethodMetadata factoryMethodMetadata; /** * 为给定的bean类创建一个新的AnnotatedGenericBeanDefinition * @param beanClass the loaded bean class:加载的bean类 */ public AnnotatedGenericBeanDefinition(Class<?> beanClass) { setBeanClass(beanClass); // 当前类上有哪些注解 this.metadata = AnnotationMetadata.introspect(beanClass); } /** * * 为给定的注释元数据创建一个新AnnotatedGenericBeanDefinition, 传入AnnotationMetadata */ 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; } /** * * 基于一个带注解的类和该类上的工厂方法。,为给定的注释元数据创建一个 新的AnnotatedGenericBeanDefinition, */ 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; } }
-
-
二、扫描过程/收集过程(一)
基本流程
Spring单独使用类扫描器ClassPathBeanDefinitionScanner进行扫描处理
源码上的注释:
A bean definition scanner that detects bean candidates on the classpath,
registering corresponding bean definitions with a
given registry ({@code BeanFactory}
* {@link org.springframework.stereotype.Component @Component},
* {@link org.springframework.stereotype.Repository @Repository},
* {@link org.springframework.stereotype.Service @Service}, or
* {@link org.springframework.stereotype.Controller @Controller} stereotype.
-
bean定义扫描器会在类的路径上检测以上注解,如果存在,就在给定的BeanFactory中注册相应的BeanDefinition,这里就又牵扯出BeanFactory,他是个很重要的接口,DefaultListableBeanFactory就实现了他,这个接口定义了获取bean以及bean的各种属性。
-
主要的方法: Spring中所有do开头的方法,都是做实事的方法,所以必须看doScan() 位于ClassPathBeanDefinitionScanner类扫描器里
public int scan(String... basePackages) {
//开始时候的bean 定义的数量
int beanCountAtScanStart = this.registry.getBeanDefinitionCount();
//要开始做实事了,进行扫描
doScan(basePackages);
//添加一些后置处理器
if (this.includeAnnotationConfig) {
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
//返回新增了多少个
return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);
}
doScan详解 同样位于ClassPathBeanDefinitionScanner类扫描器里: Spring会扫描目标包和他的子包,doScan方法接受多个包名,通常这里只传递项目的根路径,这个方法其中最重要的还是findCandidateComponents,他会找到符合这个包路径的所有类,从中挑选出需要被管理的。
-
1、开始时加载doScan源码:
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
/**
* 保存扫描到的BeanDefinition
*/
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
/**
* 遍历目标包名
*/
for (String basePackage : basePackages) {
/**
* 根据包名找到带有指定注解的类的所有BeanDefinition对象
*/
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
/**
* 遍历BeanDefinition
*/
for (BeanDefinition candidate : candidates) {
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.
resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
String beanName = this.beanNameGenerator.generateBeanName(candidate,
this.registry);
if (candidate instanceof AbstractBeanDefinition) {
postProcessBeanDefinition((AbstractBeanDefinition) candidate,
beanName);
}
/**
* 根据其他注解设置BeanDefinition对应字段值
*/
if (candidate instanceof AnnotatedBeanDefinition) {
AnnotationConfigUtils.processCommonDefinitionAnnotations(
(AnnotatedBeanDefinition) candidate);
}
/**
* 验证这个bean,比如是否存在
*/
if (checkCandidate(beanName, candidate)) {
/**
* 使用BeanDefinitionHolder包装BeanDefinition
*/
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder
(candidate, beanName);
definitionHolder =
AnnotationConfigUtils.applyScopedProxyMode
(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
/**
* 向容器注册这个BeanDefinition
*/
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
2、doScan中的findCandidateComponents详解 findCandidateComponents中的核心是scanCandidateComponents,他首先会根据传递的包名,拼接成完整的通配符路径,比如包名是com.xxx,那么最后完整的通配路径就是classpath*:com/xxx/**/*.class
,这个通配路径中也包含子包。
-
源码:
private Set<BeanDefinition> scanCandidateComponents(String basePackage) { Set<BeanDefinition> candidates = new LinkedHashSet<>(); try { String packageSearchPath = ResourcePatternResolver. CLASSPATH_ALL_URL_PREFIX + resolveBasePackage(basePackage) + '/' + this.resourcePattern; /** * 扫描出所有符合指定通配符的所有class * 会收集所有符合这个通配路径的Resource对象, * Resource中包含这具体这个类的位置 */ Resource[] resources = getResourcePatternResolver(). getResources(packageSearchPath); /** * 过滤不需要的class */ for (Resource resource : resources) { if (traceEnabled) { logger.trace("Scanning " + resource); } try { /** * 真正读取的Class的Metadata信息的是SimpleMetadataReader, 但是默认实现是CachingMetadataReaderFactory,只不过在他的基础 * 上增加了缓存功能 */ MetadataReaderFactory **metadataReaderFactory** = getMetadataReaderFactory(); /** * 取出访问权限、父类名、注解等信息, * 最终返回成MetadataReader对象, * MetadataReader就包含这这个类上有哪些注解。 */ MetadataReader **metadataReader** = metadataReaderFactory.getMetadataReader(resource); /** * 如果这个类标有Component注解或者他的子类, 那么进行BeanDefinition注册 */ if (**isCandidateComponent**(metadataReader)) { ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader); sbd.setSource(resource); if (isCandidateComponent(sbd)) { candidates.add(sbd); } } } catch (FileNotFoundException ex) { } catch (Throwable ex) { throw new BeanDefinitionStoreException( "Failed to read candidate component class: " + resource, ex); } } } catch (IOException ex) { throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex); } return candidates; }
3、findCandidateComponents中的isCandidateComponent 判断有没有指定注解
if (isCandidateComponent(metadataReader)) { ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader); sbd.setSource(resource); if (isCandidateComponent(sbd)) { candidates.add(sbd); } } } catch (FileNotFoundException ex) { } catch (Throwable ex) { throw new BeanDefinitionStoreException( "Failed to read candidate component class: " + resource, ex); }
源码,用来判断有没有指定的注解:
protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException { for (TypeFilter tf : this.excludeFilters) { if (tf.match(metadataReader, getMetadataReaderFactory())) { return false; } } /** includeFilters字段里保存的就是一些注解列表, 在默认的时候里面含有Component、ManagedBean、Named这三个, 所以,类上只要标有这三个注解,就可以让Spring管理, 而@Service这些注解上都又标有Component注解, 简单可以理解成Service继承Component, 所以,标有@Service也可以让Spring管理,同样我们自定义一个注解, 注解上加入@Component,同样可以。 */ for (TypeFilter tf : this.**includeFilters**) { if (tf.match(metadataReader, getMetadataReaderFactory())) { return isConditionMatch(metadataReader); } } return false; }
4、doScan最后的方法返回说有的注解类 最后这个方法返回所有带有这些注解的类,在回到doScan,剩下的就是遍历上一步返回的结果,注册到容器里,除此之外,还有下面这段代码,首先这个条件是成立的,因为在扫描过程中,返回的是ScannedGenericBeanDefinition,而他是继承AnnotatedBeanDefinition
if (candidate instanceof AnnotatedBeanDefinition) { AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate); }
5、doScan的AnnotationConfigUtils调用processCommonDefinitionAnnotations加载其余的注解 其余注解如Primary用来设置当有众多相同的Bean中,优先使用@Primary注解的Bean。 所以下面代码,只是根据其他注解的值填充到BeanDefinition
static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) { AnnotationAttributes lazy = attributesFor(metadata, Lazy.class); if (lazy != null) { abd.setLazyInit(lazy.getBoolean("value")); } else if (abd.getMetadata() != metadata) { lazy = attributesFor(abd.getMetadata(), Lazy.class); if (lazy != null) { abd.setLazyInit(lazy.getBoolean("value")); } } if (metadata.isAnnotated(Primary.class.getName())) { abd.setPrimary(true); } AnnotationAttributes dependsOn = attributesFor(metadata, DependsOn.class); if (dependsOn != null) { abd.setDependsOn(dependsOn.getStringArray("value")); } AnnotationAttributes role = attributesFor(metadata, Role.class); if (role != null) { abd.setRole(role.getNumber("value").intValue()); } AnnotationAttributes description = attributesFor(metadata, Description.class); if (description != null) { abd.setDescription(description.getString("value")); } }
6、doScan的注册 封装成BeanDefinitionHolder,这个对象里面含有BeanDefinition,调用registerBeanDefinition添加到容器中,容器就是DefaultListableBeanFactory。
registerBeanDefinition(definitionHolder, this.registry);
DefaultListableBeanFactory关系图
然后调用registerBeanDefinition方法,位于DefaultListableBeanFactory,把BeanDefinitionHolder对象添加到beanDefinitionMap中,这个过程中处理别名。
三、扫描过程/收集过程(二)二次收集
1、从AnnotationConfigApplicationContext中的scan和refresh开始 ** scan是第一次收集的时候位于ClassPathBeanDefinitionScanner类扫描器** 下面是 AnnotationConfigApplicationContext的构造方法
public AnnotationConfigApplicationContext(String... basePackages) {
this();
scan(basePackages);
refresh();
}
2、点击refresh方法进入AbstractApplicationContext中的refresh方法:
@Override
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) {
StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
/**
* 不需要看
*/
prepareRefresh();
/**
* 获取在本类的构造方法执行阶段实例化的DefaultListableBeanFactory,
所有阶段都围绕这他
*/
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
/**
* 向ConfigurableListableBeanFactory中添加一些其他辅助类,如后处理器
*/
prepareBeanFactory(beanFactory);
try {
/**
* 这个方法用来扩展,这个过程没有子类重写他,不需要看
*/
postProcessBeanFactory(beanFactory);
StartupStep beanPostProcess = this.applicationStartup.
start("spring.context.beans.post-process")
/**
* 这里也实现了Bean的收集,主要会执行ConfigurationClassPostProcessor
* 这里是个循环收集过程
*/
** invokeBeanFactoryPostProcessors(beanFactory);**
/**
* 收集所有BeanPostProcessors
*/
registerBeanPostProcessors(beanFactory);
beanPostProcess.end();
initMessageSource();
initApplicationEventMulticaster();
onRefresh();
registerListeners();
//实例化剩余的Bean
finishBeanFactoryInitialization(beanFactory);
finishRefresh();
} catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context
initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
} finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
contextRefresh.end();
}
}
}
(一)执行所有——invokeBeanFactoryPostProcessors(beanFactory); 他会调用所有实现了BeanDefinitionRegistryPostProcessor接口的类的postProcessBeanDefinitionRegistry()方法,其中最核心的一个实现类是ConfigurationClassPostProcessor,他可能会向容器添加新的bean,因为类中可能有@Import、@Bean这样的注解,负责这些注解的解析 。
-
点击进入方法invokeBeanFactoryPostProcessors(beanFactory);(依旧位于AbstractApplicationContext)
protected void invokeBeanFactoryPostProcessors( ConfigurableListableBeanFactory beanFactory) {
** //重点**
** *****PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(
beanFactory,
this.getBeanFactoryPostProcessors());***
if (beanFactory.getTempClassLoader() == null &&
beanFactory.containsBean("loadTimeWeaver")) {
beanFactory.addBeanPostProcessor(
new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(
beanFactory.getBeanClassLoader()));
}
}
重要的一句话:
**PostProcessorRegistrationDelegate**.
invokeBeanFactoryPostProcessors(
beanFactory,
this.getBeanFactoryPostProcessors());
1、从现阶段收集到的bean列表中找到实现了BeanDefinitionRegistryPostProcessor接口的bean,
并且还实现了PriorityOrdered接口(用来排序),
唯一一个符合这个条件的就是ConfigurationClassPostProcessor,
那么会调用getBean()实例化他,
实例化后调用postProcessBeanDefinitionRegistry进行新的bean收集。
2、收集过后,容器中可能会增加同样实现了BeanDefinitionRegistryPostProcessor接口的类,
那么Spring还要判断,如果这些类中有实现Ordered(用来排序)接口的,
那么做同样的事,实例化他,并调用postProcessBeanDefinitionRegistry。
点击进入PostProcessorRegistrationDelegate类中,为了新的类可以添加进容器,所有Spring设置了一个while来不断收集
boolean reiterate = true;
while (reiterate) {
reiterate = false;
/**
* 再次获取实现了BeanDefinitionRegistryPostProcessor接口的类,并且实例化
* 这里也是个循环调用,直到所有bean中都收集完成了
*/
postProcessorNames = beanFactory.getBeanNamesForType(
BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName)) {
currentRegistryProcessors.add(beanFactory.
getBean(ppName, BeanDefinitionRegistryPostProcessor.
class));
processedBeans.add(ppName);
reiterate = true;
}
}
//排序
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
//调用postProcessBeanDefinitionRegistry进行新的bean收集。
invokeBeanDefinitionRegistryPostProcessors(
currentRegistryProcessors, registry,
beanFactory.getApplicationStartup());
currentRegistryProcessors.clear();
}
收集过后,会获取所有实现了BeanFactoryPostProcessor接口的类,会按照实现了PriorityOrdered、Ordered接口的优先级,依次调用他们的postProcessBeanFactory方法,这个方法位于BeanFactoryPostProcessor接口下,而BeanDefinitionRegistryPostProcessor又继承他。
@FunctionalInterface
public interface BeanFactoryPostProcessor { void postProcess BeanFactory(
//重点
//参数ConfigurableListableBeanFactory唯一的
//实现类是DefaultListableBeanFactory
//DefaultListableBeanFactory是一个核心类,
//同样也可以注册Bean
** ConfigurableListableBeanFactory** var1)
throws BeansException;
}
public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
//重点
void **postProcessBeanDefinitionRegistry**(
BeanDefinitionRegistry var1) throws BeansException;
}
(二)收集可能存在新Bean的类——点进去发现postProcessBeanDefinitionRegistry这个方法来源于ConfigurationClassPostProcessor类
-
ConfigurationClassPostProcessor类的描述 ConfigurationClassPostProcessor是一个BeanFactory的后置处理器,因此它的主要功能是参与BeanFactory的建造,在这个类中,会解析加了@Configuration的配置类,还会解析@ComponentScan、@ComponentScans注解扫描的包,以及解析@Import等注解。 ConfigurationClassPostProcessor 实现了 BeanDefinitionRegistryPostProcessor 接口,而 BeanDefinitionRegistryPostProcessor 接口继承了 BeanFactoryPostProcessor 接口,所以 ConfigurationClassPostProcessor 中需要重写 postProcessBeanDefinitionRegistry() 方法和 postProcessBeanFactory() 方法。而ConfigurationClassPostProcessor类的作用就是通过这两个方法去实现的。
-
ConfigurationClassPostProcessor类的关系图
ConfigurationClassPostProcessor的工作:
-
1、遍历完现阶段的所有bean
遍历现阶段容器中所有bean,检测这个bean类上是否标有Configuration、 Component、ComponentScan、Import、ImportResource注解, 标有的话,把这个bean放入一个集合中, 如果没有的话,还会检测类中方法上是不是标有@Bean注解, 有的话,同样放到这个集合中。 还有个知识点是如果标有Configuration注解, 并且proxyBeanMethods是true,那么未来会进行增强, 也就是需要进行动态代理。
2、然后解析遍历出来的内部类,然后进行处理。ConfigurationClassParser类进行解析
-
1、判断是不是标有Component注解和Component的子注解,如果标有的话,会先处理他的内部类,如果内部类上同样标有@Component或者他的"子注解",那么这个类最终也会被Spring收录到容器,同样内部类中还有内部类,Spring做好了递归处理
@Nullable protected final ConfigurationClassParser.SourceClass doProcessConfigurationClass( ConfigurationClass configClass, ConfigurationClassParser.SourceClass sourceClass, Predicate<String> filter) throws IOException { if (configClass.getMetadata().isAnnotated(Component.class.getName())) { this.processMemberClasses(configClass, sourceClass, filter); }
-
2、收集属性,判断有没有PropertySources注解,有的话封装成PropertySource添加到上下文的environment中,PropertySource就保存着如application.properties文件中的值,最后用于依赖注入。
-
3、扫描新路径,接着会处理ComponentScans、ComponentScan注解,Spring拿到里面的值后,会重新使用上一章的方法,进如doScan进行扫描,扫描后会把扫描到的新Bean在走一遍这些流程。
-
4、处理Import 处理@Import注解,这部分还是比较多的,因为@Import中的class可能分为以下三种情况。
-
1、实现了ImportSelector(先放入集合)
-
2、实现了ImportBeanDefinitionRegistrar(暂时先实例化后放入到一个集合中,并不会调用其中任何方法,将来才会调用)
-
3、独立类(先放入集合)
-
-
新的bean名称就是他的完整路径,比如com.xxx.TestA,同样这个过程也是个递归收集过程
5、获取带有@Bean注解的方法,将带有@Baen注解的方法封装成BeanMethod对象添加到集合中,在调用的时候把返回值放入到容器
while(var18.hasNext()) { MethodMetadata methodMetadata = (MethodMetadata)var18.next(); configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass)); } this.processInterfaces(configClass, sourceClass); if (sourceClass.getMetadata().hasSuperClass()) { String superclass = sourceClass.getMetadata().getSuperClassName(); if (superclass != null && !superclass.startsWith("java") && !this.knownSuperclasses.containsKey(superclass)) { this.knownSuperclasses.put(superclass, configClass); return sourceClass.getSuperClass(); } }
6、收集接口中的default方法,如果这个类实现了某个接口,并且这个接口中有标有@Bean注解的的default方法,那么Spring还是要收集,并且这也是个递归过程,也就是接口继承接口的时候,会一头钻到底
6、收集接口中的default方法,如果这个类实现了某个接口,并且这个接口中有标有@Bean注解的的default方法,那么Spring还是要收集,并且这也是个递归过程,也就是接口继承接口的时候,会一头钻到底
源码
/** * 获取接口上含有@Bean注解的方法 */ private void processInterfaces(ConfigurationClass configClass, SourceClass sourceClass) throws IOException { /** * 获取父级接口,遍历 */ for (SourceClass ifc : sourceClass.getInterfaces()) { /** * 获取接口中含有@Bean注解的方法元信息,然后遍历 */ Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(ifc); for (MethodMetadata methodMetadata : beanMethods) { /** * 只要此方法不是抽象类型的,则可以放入集合中待后续处理 */ if (!methodMetadata.isAbstract()) { // A default method or other concrete method on a Java 8+ interface... configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass)); } } /** * 这里使用了递归,用来处理父级接口的父接口 */ processInterfaces(configClass, ifc); } }
7、处理父类,当本类处理完后,可能他的父类中同样有上面这些需求,Spring也要处理。但这不是递归过程,是个while过程,doProcessConfigurationClass就是上面说的所有过程,返回值是他的父类,没有的话会返回null。
ConfigurationClassParser.SourceClass sourceClass = this.asSourceClass(configClass, filter); do { sourceClass = this.doProcessConfigurationClass(configClass, sourceClass, filter); } while(sourceClass != null); this.configurationClasses.put(configClass, configClass);
3、向容器里面添加新的bean,ConfigurationClassParser类进行解析完成后,类中所有标有@Bean的方法还有其他信息都已经提取好后封装成了ConfigurationClass,下一步就是读取这些信息,把能放进容器的都放进容器。加载BeanDefinitions从ConfigurationClass,这里注意有s,表明一个配置类中可能有很多个BeanDefinition准备要添加到容器。
private void loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass, ConfigurationClassBeanDefinitionReader.TrackedConditionEvaluator trackedConditionEvaluator) {
//判断是否跳过
if (trackedConditionEvaluator.shouldSkip(configClass)) {
String beanName = configClass.getBeanName();
if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
this.registry.removeBeanDefinition(beanName);
}
this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
} else
{//判断这个类是不是被@Import导入的,
// 如果是,那么会把他封装成BeanDefinitionHolder,添加到容器
if (configClass.isImported()) {
this.registerBeanDefinitionForImportedConfigurationClass(configClass);
}
Iterator var3 = configClass.getBeanMethods().iterator();
//遍历这个类所有加了@Bean注解的方法
while(var3.hasNext()) {
BeanMethod beanMethod = (BeanMethod)var3.next();
this.loadBeanDefinitionsForBeanMethod(beanMethod);
}
this.loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
//调用ImportBeanDefinitionRegistrar
this.loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}
}
@Import的class如果实现了ImportBeanDefinitionRegistrar接口,那么暂时会把他实例化后放入集合,未来会调用,那么这里就是。
private void loadBeanDefinitionsFromRegistrars(Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> registrars) {
registrars.forEach((registrar, metadata) -> {
registrar.registerBeanDefinitions(metadata, this.registry, this.importBeanNameGenerator);
});
}
(三)收集所有实现了BeanPostProcessor接口的类,在refresh()下面registerBeanPostProcessors()方法就是收集所有实现了BeanPostProcessor接口的类,也就是收集所有钩子,未来在创建对象前后会调用。
BeanPostProcessor接口源码
public interface BeanPostProcessor {
@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
在所有bean中获取实现了BeanPostProcessor接口的类
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
(四)遍历所有Bean名称,判断这个Bean是否有实例化的资格,初始化—— finishBeanFactoryInitialization 这基本上是最后一步了,这里面会调用下面这段,注释的意思是实例化剩余的非懒加载的bean,为什么说剩余呢?因为在前面已经有一部分逻辑需要已经实例化过了,比如这个Bean实现了一个Spring必须要用的接口,在前面实例化了,懒加载的bean指的是当需要的时候才实例化。
// Instantiate all remaining (non-lazy-init) singletons.
beanFactory.preInstantiateSingletons();