美文网首页
AnnotationConfigApplicationConte

AnnotationConfigApplicationConte

作者: zekers | 来源:发表于2020-02-02 02:11 被阅读0次

    AnnotationConfigApplicationContext 源码分析(二):注册配置类

    本文是作者的个人学习笔记,仅做参考,Spring代码版本5.2.2

    AnnotationConfigApplicationContext 源码分析(一)

    注册配置类

    注册配置类将要解析由AnnotationConfigRegistry接口所提供的#register(Class<?>... componentClasses)方法,该方法用于注册一个或多个组件类(标注了@component的类),注意的是注册完了之后容器必须调用#refresh()方法,不然将会导致未知的问题。

    public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry {
      /**
         * Register one or more component classes to be processed.
         * <p>Note that {@link #refresh()} must be called in order for the context
         * to fully process the new classes.
         * @param componentClasses one or more component classes &mdash; for example,
         * {@link Configuration @Configuration} classes
         *
         * 注册一个或多个要处理的组件类。
         * <p>请注意,必须调用{@link #refresh()},以便容器完全处理新类。
         * @param componentClasses 一个或多个组件类,例如,{@link Configuration@Configuration}类
         */
        @Override
        public void register(Class<?>... componentClasses) {
            Assert.notEmpty(componentClasses, "At least one component class must be specified");
            this.reader.register(componentClasses);
        }
    }
    

    根据代码可以知道,实际上调用的是AnnotatedBeanDefinitionReader#register(Class<?>... componentClasses)方法

    public class AnnotatedBeanDefinitionReader {
      /**
         * Register one or more component classes to be processed.
         * <p>Calls to {@code register} are idempotent; adding the same
         * component class more than once has no additional effect.
         * @param componentClasses one or more component classes,
         * e.g. {@link Configuration @Configuration} classes
         *
         * 注册一个或多个要处理的组件类。
         * <p>对{@code register}的调用是等幂的;多次添加同一个组件类没有额外的效果。
         * @param componentClasses 一个或多个组件类,例如{@link Configuration @Configuration}类
         */
        public void register(Class<?>... componentClasses) {
            for (Class<?> componentClass : componentClasses) {
                registerBean(componentClass);
            }
        }
        public void registerBean(Class<?> beanClass) {
            doRegisterBean(beanClass, null, null, null, null);
        }
    }
    

    for循环依次调用注册组件类,这里就不过多解析

    public class AnnotatedBeanDefinitionReader {
      /**  **/
      private ScopeMetadataResolver scopeMetadataResolver = new AnnotationScopeMetadataResolver();
      
      /**
         * Register a bean from the given bean class, deriving its metadata from
         * class-declared annotations.
         * @param beanClass the class of the bean
         * @param name an explicit name for the bean
         * @param qualifiers specific qualifier annotations to consider, if any,
         * in addition to qualifiers at the bean class level
         * @param supplier a callback for creating an instance of the bean
         * (may be {@code null})
         * @param customizers one or more callbacks for customizing the factory's
         * {@link BeanDefinition}, e.g. setting a lazy-init or primary flag
         *
         * 从给定的bean类中注册一个bean,从类声明的注释中派生其元数据。
         * @param beanClass 注册的Bean的Class对象
         * @param name  bean的显式名称
         * @param qualifiers 除了bean类级别的限定符之外,要考虑的特定限定符注释(如果有的话)
         * @param supplier 用于创建bean实例的回调(可以是{@code null})
         * @param customizers 一个或多个回调,用于自定义工厂的{@link BeanDefinition},例如设置lazy init或primary标志
         * @since 5.0
         */
        private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name,
                @Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier,
                @Nullable BeanDefinitionCustomizer[] customizers) {
    
        //1、根据beanClass生成AnnotatedGenericBeanDefinition
            AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
            //2、
            if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
                return;
            }
        //3、supplier==null,略
            abd.setInstanceSupplier(supplier);
        //4、解析BeanDefinition上的@Scope标签,设置BeanDefinition的scope
            ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
            abd.setScope(scopeMetadata.getScopeName());
        //5、解析BeanDefinition获得beanName(Bean的名称)
            String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
            //6、分析类上的多个注解,在BeanDefinition上设置注解上设置的配置元数据
            AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
        //7、qualifiers==null,略
            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));
                    }
                }
            }
        //8、customizers==null,略
            if (customizers != null) {
                for (BeanDefinitionCustomizer customizer : customizers) {
                    customizer.customize(abd);
                }
            }
        
            //9、生成BeanDefinitionHolder对象
            BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
        //10、作用域代理策略,针对@Scope标签的proxyMode属性
            definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
        //11、注册definitionHolder到容器中
            BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
        }
    }
    

    往容器中注册一个bean

    参数解析:

    1. beanClass:解析的目标类
    2. name:这里为空,注册的名字
    3. qualifiers:这里为空,暂不分析
    4. supplier:这里为空,暂不分析
    5. customizers:这里为空,暂不分析

    步骤:

    1. 生成AnnotatedGenericBeanDefinition对象(存储Bean的描述信息的对象),持有beanClass,同时解析beanClass获取部分配置元数据(配置元数据即描述这个Bean的配置信息),存储到该BeanDefinition对象中;
    2. 暂时跳过;
    3. 这里无作用,略;
    4. 使用scopeMetadataResolver解析BeanDefinition上的@Scope标签,确定作用域元数据。然后设置到BeanDefinition上
    5. 解析BeanDefinition获得beanName(Bean的名称)
    6. 通过AnnotatedBeanDefinition上的配置元数据,解析存储在该配置元数据上的以下的注解信息,获取注解上的值,存储到该AnnotatedBeanDefinition对象上
      1. @Lazy
      2. @Primary
      3. @DependsOn
      4. @Role
      5. @Description
    7. 这里无作用,略;
    8. 这里无作用,略;
    9. 生成BeanDefinitionHolder对象,持有BeanDefinition和Bean的名称
    10. 作用域代理策略,将根据参数判断是否需要代理,使用jdk代理还是CGLIB代理
    11. 往容器中注册BeanDefinitionHolder

    生成AnnotatedGenericBeanDefinition对象

    public class AnnotatedGenericBeanDefinition extends GenericBeanDefinition implements AnnotatedBeanDefinition {
      /**
         * Create a new AnnotatedGenericBeanDefinition for the given bean class.
         * @param beanClass the loaded bean class
         * 为给定的bean类创建一个新的AnnotatedGenericBeanDefinition。
         * @param beanClass 加载的bean类
         */
        public AnnotatedGenericBeanDefinition(Class<?> beanClass) {
            setBeanClass(beanClass);
            this.metadata = AnnotationMetadata.introspect(beanClass);
        }
    }
    

    这个类是GenericBeanDefinition(GenericBeanDefinition是通用的BeanDefinition)的基础上实现AnnotatedBeanDefinition接口,该接口提供了用于暴露注解相关的配置元数据,即AnnotationMetadata的接口。

    AnnotatedGenericBeanDefinition类型的BeanDefinition通常只在注册组件类的时候被定义。

    步骤:

    1. BeanDefinition持有类对象
    2. 通过内省(java机制)类对象生成StandardAnnotationMetadata对象(配置元数据对象)并被当前BeanDefinition持有。相关类将另起文章分析
    

    解析BeanDefinition获取ScopeMetadata

    /**
     * A {@link ScopeMetadataResolver} implementation that by default checks for
     * the presence of Spring's {@link Scope @Scope} annotation on the bean class.
     *
     * <p>The exact type of annotation that is checked for is configurable via
     * {@link #setScopeAnnotationType(Class)}.
     * 默认情况下检查bean类上是否存在Spring的{@link Scope@Scope}注释的{@link ScopeMetadataResolver}实现。
     * <p>检查的注释的确切类型可以通过{@link #setScopeAnnotationType(Class)}配置
     */
    public class AnnotationScopeMetadataResolver implements ScopeMetadataResolver {
    
      
      @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;
        }
    }
    

    步骤:

    1. 新建ScopeMetadata对象
    2. 使用AnnotationConfigUtils工具类获取标记了@Scope的注解对象(AnnotationAttributes)
    3. 如果注解对象不为空,则解析注解对象的属性,并设置给配置ScopeMetadata(保存Scope注解信息的配置元数据)
      1. value—>setScopeName
      2. proxyMode—>设置setScopedProxyMode:作用域代理模式,用于决定是否要代理这个类,代理的模式是jdk代理还是CGLIB代理
    4. 返回ScopeMetadata对象后,通过BeanDefinition#setScope(String scopeName)设置到BeanDefinition中持有

    生成BeanName策略

    public class AnnotationBeanNameGenerator implements BeanNameGenerator {
        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);
        }
    }
    

    BeanNameGenerator是Spring中为bean definitions生成名字策略接口。

    AnnotationBeanNameGenerator生成BeanName的策略:

    1. 如果definition是AnnotatedBeanDefinition,则会通过解析类上的注解,获取以下注解(包括继承的注解类)上value的值作为BeanName
      1. @Component
      2. @ManagedBean
      3. @Named
    2. 如果以上注解中value的值为null,将会获取类名,转化为beanName,转换方式如下
      1. 常规类:package.MyConfiguration—>myConfiguration
      2. 静态内部类:package.MyConfiguration$Config—>myConfiguration.Config

    作用域代理策略

    public abstract class AnnotationConfigUtils {
        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.NO,则不做任何处理,否则进行ScopedProxyCreator#createScopedProxy方法返回一个新的BeanDefinitionHolder对象

    获取ScopedProxyFactoryBean类的BeanDefinitionHolder

    final class ScopedProxyCreator {
      
        public static BeanDefinitionHolder createScopedProxy(
                BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry, boolean proxyTargetClass) {
        
            return ScopedProxyUtils.createScopedProxy(definitionHolder, registry, proxyTargetClass);
        }
    }
    
    
    public abstract class ScopedProxyUtils {
        /**
         * Generate a scoped proxy for the supplied target bean, registering the target
         * bean with an internal name and setting 'targetBeanName' on the scoped proxy.
         * @param definition the original bean definition
         * @param registry the bean definition registry
         * @param proxyTargetClass whether to create a target class proxy
         * @return the scoped proxy definition
         *
         * 为提供的目标bean生成作用域代理,用内部名称注册目标bean,并在作用域代理上设置“target bean name”。
         */
        public static BeanDefinitionHolder createScopedProxy(BeanDefinitionHolder definition,
                BeanDefinitionRegistry registry, boolean proxyTargetClass) {
        
            String originalBeanName = definition.getBeanName();
            BeanDefinition targetDefinition = definition.getBeanDefinition();
        //targetBeanName = "scopedTarget."+ originalBeanName
            String targetBeanName = getTargetBeanName(originalBeanName);
    
            // Create a scoped proxy definition for the original bean name,
            // "hiding" the target bean in an internal target definition.
            // 为原始bean名称创建一个作用域代理定义,
            // 在内部目标定义中“隐藏”目标bean。
            RootBeanDefinition proxyDefinition = new RootBeanDefinition(ScopedProxyFactoryBean.class);
            proxyDefinition.setDecoratedDefinition(new BeanDefinitionHolder(targetDefinition, targetBeanName));
            proxyDefinition.setOriginatingBeanDefinition(targetDefinition);
            proxyDefinition.setSource(definition.getSource());
            proxyDefinition.setRole(targetDefinition.getRole());
    
            proxyDefinition.getPropertyValues().add("targetBeanName", targetBeanName);
            if (proxyTargetClass) {
                targetDefinition.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
                // ScopedProxyFactoryBean's "proxyTargetClass" default is TRUE, so we don't need to set it explicitly here.
                // ScopedProxyFactoryBean的“proxyTargetClass”默认值为TRUE,因此不需要在这里显式设置它。
            }
            else {
                proxyDefinition.getPropertyValues().add("proxyTargetClass", Boolean.FALSE);
            }
    
            // Copy autowire settings from original bean definition.
            // 从原始bean定义复制autowire设置。
            proxyDefinition.setAutowireCandidate(targetDefinition.isAutowireCandidate());
            proxyDefinition.setPrimary(targetDefinition.isPrimary());
            if (targetDefinition instanceof AbstractBeanDefinition) {
                proxyDefinition.copyQualifiersFrom((AbstractBeanDefinition) targetDefinition);
            }
    
            // The target bean should be ignored in favor of the scoped proxy.
            // 为了支持作用域代理,应该忽略目标bean。
            targetDefinition.setAutowireCandidate(false);
            targetDefinition.setPrimary(false);
    
            // Register the target bean as separate bean in the factory.
            // 在工厂中将目标bean注册为单独的bean。
            registry.registerBeanDefinition(targetBeanName, targetDefinition);
    
            // Return the scoped proxy definition as primary bean definition
            // (potentially an inner bean).
            return new BeanDefinitionHolder(proxyDefinition, originalBeanName, definition.getAliases());
        }
    }
    

    在上述过程中,主要做了三件事

    1. 新建一个ScopedProxyFactoryBean类的BeanDefinition,用于生成代理原来的Bean的代理Bean,设置所需的参数,确定代理类使用jdk代理还是CGLIB代理。
    2. 处理原来的BeanDefinition
      1. 原来的BeanDefinition中autowireCandidate属性和primary属性设置为false
      2. 将原来的BeanDefinition的以("scopedTarget."+原BeanName)作为新名称注册到容器中
    3. 返回包含原BeanName和ScopedProxyFactoryBean类的BeanDefinition信息的BeanDefinitionHolder。
      1. 以后再调用原来的beanName去获取bean的时候,获取的将是在ScopedProxyFactoryBean对象中获取的BeanDefinition的代理对象。

    总结

    在注册组件类的时候主要做了以下事情:

    1. 分析组件类生成BeanDefinition对象,将以下注解的配置元信息设置到BeanDefinition对象
      1. @Scope
      2. @Lazy
      3. @Primary
      4. @DependsOn
      5. @Role
      6. @Description
    2. 确定BeanName
    3. 根据@Scope的proxyMode属性,进行不同的作用域代理策略
    4. 将组件类的BeanDefinition或ScopedProxyFactoryBean类的BeanDefinition注册到容器中

    相关文章

      网友评论

          本文标题:AnnotationConfigApplicationConte

          本文链接:https://www.haomeiwen.com/subject/klufxhtx.html