您的位置:首页 > 编程语言 > Java开发

spring源码分析(2)——Bean 定义的解析与Bean的注册

2018-03-06 17:29 786 查看
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
this();
register(annotatedClasses);
refresh();
}
        在sprint的源码分析(1)中,我们分析了this()这条语句调用的无参构造方法初始化了AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner这两个类,接着我们分析register(annotatedClasses)这个函数。public void register(Class<?>... annotatedClasses) {
Assert.notEmpty(annotatedClasses, "At least one annotated class must be specified");
this.reader.register(annotatedClasses);
}
        入参Class<?>... annotatedClasses是我们进行初始化的时候传入的类;this.reader就是已经初始化完毕的AnnotatedBeanDefinitionReader。public void register(Class<?>... annotatedClasses) {
for (Class<?> annotatedClass : annotatedClasses) {
registerBean(annotatedClass);
}
}
        通过for循环轮流对传入的类进行解析,注册为bean。public void registerBean(Class<?> annotatedClass) {
doRegisterBean(annotatedClass, null, null, null);
}
        最终调用doRegisterBean方法。下面分别讲解每一句的含义。<T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,
@Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {

AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
return;
}

abd.setInstanceSupplier(instanceSupplier);
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
abd.setScope(scopeMetadata.getScopeName());
String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));

AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
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);
}

BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}        首先分析doRegisterBean方法的第4行代码:
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);        doRegisterBean方法第一句就是将类转化为AnnotatedGenericBeanDefinition。public AnnotatedGenericBeanDefinition(Class<?> beanClass) {
setBeanClass(beanClass);
this.metadata = new StandardAnnotationMetadata(beanClass, true);
}
        Spring中使用BeanDefinition描述了一个bean的实例,AnnotatedGenericBeanDefinition实现了接口AnnotatedBeanDefinition,而AnnotatedBeanDefinition继承了BeanDefinition。AnnotatedBeanDefinition比BeanDefinition多出getMetadata()方法,用于获得类上的注解信息。spring4.1.1之后还多出了getFactoryMethodMetadata()方法,也是用于获得类上的注解信息。public StandardAnnotationMetadata(Class<?> introspectedClass, boolean nestedAnnotationsAsMap) {
super(introspectedClass);
this.annotations = introspectedClass.getAnnotations();
this.nestedAnnotationsAsMap = nestedAnnotationsAsMap;
}
        AnnotationMetadata的标准实现类StandardAnnotationMetadata,它使用标准的反射来获取制定类的内部注解信息。

        分析doRegisterBean方法的第5-7行代码:if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
return;
}
        conditionEvaluator是在AnotatedBeanDefinitionReader类初始化的时候初始化的,ConditionEvaluator这个类主要用于完成条件注解@Conditional的解析和判断。@Conditional 是Spring 4框架的新特性。此注解使得只有在特定条件满足时才启用一些配置。ConditionEvaluator的shouldSkip就是用于判断@Conditional下的而配置是否被启用。public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) {
if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {
return false;
}
......
}
        从代码的前两句很容易判断, 如果这个类没有被@Conditional注解所修饰,不会skip。
        分析doRegisterBean方法的第10行代码:
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);        scopeMetadataResolver是AnotatedBeanDefinitionReader的一个成员变量,是类AnnotationScopeMetadataResolver的一个实例。AnnotationScopeMetadataResolver实现了ScopeMetadataResolver接口的resolveScopeMetadata()方法。@Override
public ScopeMetadata resolveScopeMetadata(BeanDefinition definition) {
ScopeMetadata metadata = new ScopeMetadata();
if (definition instanceof AnnotatedBeanDefinition) {
AnnotatedBeanDefinition annDef = (AnnotatedBeanDefinition) definition;
AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(
annDef.getMetadata(), this.scopeAnnotationType);
if (attributes != null) {
metadata.setScopeName(attributes.getString("value"));
ScopedProxyMode proxyMode = attributes.getEnum("proxyMode");
if (proxyMode == ScopedProxyMode.DEFAULT) {
proxyMode = this.defaultProxyMode;
}
metadata.setScopedProxyMode(proxyMode);
}
}
return metadata;
}
        第一句新建了一个ScopeMetadata,ScopeMetadata中默认的scope是singleton。重点关注AnnotationConfigUtils.attributesFor(annDef.getMetadata(), this.scopeAnnotationType)。this.scopeAnnotationType是AnnotationScopeMetadataResolver成员变量,值为Scope.class。该方法就是从元数据中获得注解scope的值,并将其返回。如果没有配置@scope,那么它的默认值就是singleton,即单例模式。        分析doRegisterBean方法的第12行代码:
String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));        这句代码生成bean的名称,beanNameGenerator是AnnotatedBeanDefinitionReader的一个成员变量,是类AnnotationBeanNameGenerator的一个实例。AnnotationBeanNameGenerator实现了BeanNameGenerator接口的generateBeanName()方法。
@Override
public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
if (definition instanceof AnnotatedBeanDefinition) {
String beanName = determineBeanNameFromAnnotation((AnnotatedBeanDefinition) definition);
if (StringUtils.hasText(beanName)) {
// Explicit bean name found.
return beanName;
}
}
// Fallback: generate a unique default bean name.
return buildDefaultBeanName(definition, registry);
}
        如果不是AnnotationBeanDefinition,buildDefaultBeanName()方法直接将类名(不含包名)作为bean name。如果是的话,执行determineBeanNameFromAnnotation(),从注解上获得bean name。protected String determineBeanNameFromAnnotation(AnnotatedBeanDefinition annotatedDef) {
AnnotationMetadata amd = annotatedDef.getMetadata();
Set<String> types = amd.getAnnotationTypes();
String beanName = null;
for (String type : types) {
AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(amd, type);
if (attributes != null && isStereotypeWithNameValue(type, amd.getMetaAnnotationTypes(type), attributes)) {
Object value = attributes.get("value");
if (value instanceof String) {
String strVal = (String) value;
if (StringUtils.hasLength(strVal)) {
if (beanName != null && !strVal.equals(beanName)) {
throw new IllegalStateException("Stereotype annotations suggest inconsistent " +
"component names: '" + beanName + "' versus '" + strVal + "'");
}
beanName = strVal;
}
}
}
}
return beanName;
}
        首先通过getAnnotationTypes()方法获得所有的注解,遍历这些注解,AnnotationConfigUtils.attributesFor()方法读取注解对应的所有属性。isStereotypeWithNameValue()方法用于判断 这些注解是否是@component注解,是否继承了@component注解,是否是@ManageBean注解,是否是@Named注解,如果满足以上条件中的任何一个并且包含value属性,则返回true。接下来判断vale的值不多于1个且value属性非空(也
c009
就是不能同时出现@service和@component且都配置value值),不然会报错。都满足的话,将value属性对应的值作为bean name。

        分析doRegisterBean方法的第14行代码:AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);        这句代码使用AnnotationConfigUtils的processCommonDefinitionAnnotations方法处理注解Bean定义类中通用的注解。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"));
}

if (abd instanceof AbstractBeanDefinition) {
AbstractBeanDefinition absBd = (AbstractBeanDefinition) abd;
AnnotationAttributes role = attributesFor(metadata, Role.class);
if (role != null) {
absBd.setRole(role.getNumber("value").intValue());
}
AnnotationAttributes description = attributesFor(metadata, Description.class);
if (description != null) {
absBd.setDescription(description.getString("value"));
}
}
}
        从代码中可以看出,processCommonDefinitionAnnotations方法处理了5个注解,分别是:
        @lazy注解:用于指定该Bean是否懒加载,如果该注解的value为true的话,则这个bean在spring容器初始化之后,第一次使用时才初始化。AbstractBeanDefinition中定义该值的默认值是false。
        @primary注解:自动装配时当出现多个Bean候选者时,被注解为@Primary的Bean将作为首选者,否则将抛出异常。
        @DependsOn注解:定义Bean初始化顺序。
        如果这个bean是AbstractBeanDefinition的子类的话,还会处理以下两个注解:
        @Role注解:用于用户自定义的bean,value值是int类型,表明该bean在应用中的角色,默认值是0,极少用到。
        @Description注解:用于描述bean,提高代码可读性,极少用到。
        分析doRegisterBean方法的第15-27行代码:
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));
}
}
}
        这一段代码是针对 @Qualifier注解的,一般情况下,@Autowired是根据类型进行自动装配的。如果当Spring上下文中存在不止一个该类型的bean时,就会抛出BeanCreationException异常。@Qualifier可以配置自动依赖注入装配的限定条件,@Qualifier 可以直接指定注入 Bean 的名称,简单来说, @Autowired 和 @Qualifier 结合使用时,自动注入的策略就从 byType 转变成 byName 了。本段代码在当前的例子中是不执行的。
        分析doRegisterBean方法的第28-30行代码:for (BeanDefinitionCustomizer customizer : definitionCustomizers) {
customizer.customize(abd);
}
        这段代码是spring5.0以后新加入的,Spring 5允许使用lambda 表达式来自定义注册一个 bean,用到的时候再分析。
        分析doRegisterBean方法的第32行:
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);        BeanDefinitionHolder就是一个BeanDefinition的持有者,它有三个成员变量。private final BeanDefinition beanDefinition;

private final String beanName;

private final String[] aliases;
        所以这行代码就是把BeanDefination简单的封装为BeanDefinitionHolder。
        分析doRegisterBean方法的第33行:definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);        进入applyScopedProxyMode()方法。static BeanDefinitionHolder applyScopedProxyMode(
ScopeMetadata metadata, BeanDefinitionHolder definition, BeanDefinitionRegistry registry) {

ScopedProxyMode scopedProxyMode = metadata.getScopedProxyMode();
if (scopedProxyMode.equals(ScopedProxyMode.NO)) {
return definition;
}
boolean proxyTargetClass = scopedProxyMode.equals(ScopedProxyMode.TARGET_CLASS);
return ScopedProxyCreator.createScopedProxy(definition, registry, proxyTargetClass);
}
        这段代码首先需要获得ScopedProxyMode值,这个值实在@scope注解中使用proxyMode属性设置的,默认为NO,就是没有代理。它还可被设置为ScopedProxyMode. INTERFACES或者是ScopedProxyMode. TARGET_CLASS。这个值具体有什么用呢,我们只带。@scope注解的value可以设置为以下几种:
        单例(singleton):在整个应用中,只创建bean的一个实例。
        原型(prototype):每次注入或者通过Spring应用上下文获取的时候,都会创建一个新的实例。
        会话(session):在Web应用中,为每个会话创建一个bean实例。
        请求(request):在Web应用中,为每个请求创建一个bean实例。
        当一个singleton作用域的bean中需要注入一个session作用域的bean的时候,会报错,应为此时应用没有人访问,session作用域bean没有创建,所以出现了问题。spring提供给我们的解决方案就是通过设置proxyMode属性的值来解决,当他设置为ScopedProxyMode. INTERFACES或者是ScopedProxyMode. TARGET_CLASS时,spring会为session作用域bean创建代理对象,而真正调用的bean则在运行时懒加载,两者的区别是一个使用JDK提供的动态代理实现,一个使用CGLIB实现。
这段代码就是通过判断proxyMode的值为注册的Bean创建相应模式的代理对象。默认不创建。

        分析doRegisterBean方法的最后一行代码。BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);        this.registry在spring源码分析(1)中分析过,其实就是AnnotationConfigApplicationContext实例对象,spring的上下文。public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {

// Register bean definition under primary name.
String beanName = definitionHolder.getBeanName();
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);
}
}
}
        第7行的registerBeanDefinition方法是BeanDefinitionRegistry接口方法,他有多个实现类,由于AnnotationConfigApplicationContext继承了GenericApplicationContext,所以这里调用的是GenericApplicationContext的registerBeanDefinition方法。@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {

this.beanFactory.registerBeanDefinition(beanName, beanDefinition);
}
        this.beanFactory是在初始化GenericApplicationContext类时初始化的,是一个DefaultListableBeanFactory。DefaultListableBeanFactory也实现了BeanDefinitionRegistry接口的registerBeanDefinition方法,所以最终调用的是DefaultListableBeanFactory的registerBeanDefinition方法。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);
}
}

BeanDefinition oldBeanDefinition;

oldBeanDefinition = this.beanDefinitionMap.get(beanName);
if (oldBeanDefinition != null) {
if (!isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
"': There is already [" + oldBeanDefinition + "] bound.");
}
else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
if (this.logger.isWarnEnabled()) {
this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
"' with a framework-generated bean definition: replacing [" +
oldBeanDefinition + "] with [" + beanDefinition + "]");
}
}
else if (!beanDefinition.equals(oldBeanDefinition)) {
if (this.logger.isInfoEnabled()) {
this.logger.info("Overriding bean definition for bean '" + beanName +
"' with a different definition: replacing [" + oldBeanDefinition +
"] with [" + beanDefinition + "]");
}
}
else {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Overriding bean definition for bean '" + beanName +
"' with an equivalent definition: replacing [" + oldBeanDefinition +
"] with [" + beanDefinition + "]");
}
}
this.beanDefinitionMap.put(beanName, beanDefinition);
}
else {
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 (oldBeanDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}
}
        这一大段代码看起来挺复杂的,但是做的事情很简单。
        7-15行是对BeanDefiniton  的校验,具体来说,是对AbstractBeanDefinition属性中的methodOverrides 效验; 效验methodOverrides 是否与工厂方法并存或者methodOverrides对应的方法根本不存在。
        17-49行是对容器中已经存在了一个同名bean的处理方法。如果对应beanName已经注册 并且beanName不能被覆盖,则抛出异常,否则后注册的覆盖先注册的。
        50-73是正常情况的处理流程,这里会将beanName和beanDefinition放到beanDefinitionMap中,此时的beanDefinitionMap中已经存在了6个beanDefinition,是在Spring源码分析(1)中放进去的6个处理器。
        registerBeanDefinition方法之后,还有registry.registerAlias(beanName, alias)方法,这是给bean注册别名用的。其实就是spring上线文对bean名称和别名之间维护了映射关系,就不具体分析了。
        本文讲解了一个Bean在spring上下文当中的解析与注册流程,通过这个步骤,Bean定义信息被Spring所管理,是容器可以进行依赖注入的基础。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息