美文网首页程序员Java学习笔记Java 杂谈
spring容器加载分析 一容器构造

spring容器加载分析 一容器构造

作者: wangjie2016 | 来源:发表于2018-01-19 10:02 被阅读240次

    目前的spring应用很少有使用XML进行配置的,springboot就是使用AnnotationConfigApplicationContext和AnnotationConfigEmbeddedWebApplicationContext作为非web应用和web应用的容器。所以就以AnnotationConfigApplicationContext为列来分析容器的加载过程。
    构造方法:

    public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
            // 构造函数
            this();
            // 向容器注册新的注解Bean
            register(annotatedClasses);
            // 刷新容器, 整个容器的加载都在这个方法中了
            refresh();
    }
    

    step 1、this()无参构造方法:

    public AnnotationConfigApplicationContext() {
        // 初始化:基于注解的BeanDefinition读取器
        // this就是AnnotatedBeanDefinitionReader中的BeanDefinitionRegistry
        this.reader = new AnnotatedBeanDefinitionReader(this);
        // 初始化:基于路径的BeanDefinition扫描器
        this.scanner = new ClassPathBeanDefinitionScanner(this);
    }
    

    同时也调用了父类的无参构造方法:

    public GenericApplicationContext() {
        // 实例化了默认的beanFactory
        this.beanFactory = new DefaultListableBeanFactory();
    }
    

    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;
        this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
        AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
    }
    

    AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry)是一个关键的方法,在这个方法中向向容器中注册6个默认的BeanDefinition:
    ConfigurationClassPostProcessor(实现自接口BeanFactoryPostProcessor)
    AutowiredAnnotationBeanPostProcessor(实现自接口BeanPostProcessor)
    RequiredAnnotationBeanPostProcessor(实现自接口BeanPostProcessor)
    CommonAnnotationBeanPostProcessor(实现自接口BeanPostProcessor)
    EventListenerMethodProcessor(实现自接口ApplicationContextAware)
    DefaultEventListenerFactory(实现自接口EventListenerFactory)
    这6个BeanDefinition对Spring至关重要,后面会有更详尽的阐述。

    step 2、register(annotatedClasses)向容器注解新的annotatedClasses:
    调用的是AnnotatedBeanDefinitionReader中的方法。

    public void registerBean(Class<?> annotatedClass, String name, Class<? extends Annotation>... qualifiers) {
        // 创建BeanDefinition
        AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
        // 判断是否需要跳过(Condition注解)
        if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
            return;
        }
        // scopeMetadataResolver = AnnotationScopeMetadataResolver
        // 解析注解Bean定义的作用域,
        // 若@Scope("prototype"),则Bean为原型类型  
        // 若@Scope("singleton"),则Bean为单态类型  
        // 默认为singleton
        ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
        abd.setScope(scopeMetadata.getScopeName());
        // 注解Bean定义生成Bean名称
        String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
        // 处理通用注解 如:Lazy DependsOn 等
        AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
        // 解析限定符注解
        // 主要是配置的关于autowiring自动依赖注入装配的限定条件,即@Qualifier注解  
        // Spring的autowiring默认是按类型装配,如果使用@Qualifier则按名称 和@Resource一样
        if (qualifiers != null) {
            for (Class<? extends Annotation> qualifier : qualifiers) {
                // 如果配置了@Primary注解,设置该Bean为autowiring自动依赖注入装//配时的首选
                if (Primary.class == qualifier) {
                    abd.setPrimary(true);
                }
                //如果配置了@Lazy注解,则设置该Bean为延迟初始化,否则则该Bean为预实例化  
                else if (Lazy.class == qualifier) {
                    abd.setLazyInit(true);
                }
                else {
                    // 如果使用了除@Primary和@Lazy以外的其他注解,则为该Bean添加一 个autowiring自动依赖注入装配限定符
                    // 该Bean在进autowiring自动依赖注入装配时,根据名称装配限定符指定的Bean 
                    abd.addQualifier(new AutowireCandidateQualifier(qualifier));
                }
            }
        }
        // 创建bean持有类
        BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
        // 根据注解Bean定义类中配置的作用域,创建BeanDefinition相应的代理对象  
        definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
        // 注册BeanDefinition,这个方法中会注册所有的alias
        BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
    }
    

    annotatedClass已经注册到容器,但是还没有实例化。
    this.conditionEvaluator.shouldSkip(abd.getMetadata())) 来判断是否满足Bean创建的条件,如果不满足则跳过。
    一个Condition的示例:

    /**
     * 条件:Linux操作系统
     */
    public class LinuxCondition implements Condition {
        @Override
        public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
             return context.getEnvironment().getProperty("os.name").contains("Linux");  
        }
    }
    

    使用方式:

    @Configuration
    @Conditional(LinuxCondition.class)
    public class LinuxStartupConfig{
        ... ...
    }
    

    如果当前的操作系统不是Linux,那么LinuxStartupConfig这个Bean将不会创建。springboot提供的6个@ConditionalOnxxx就基于@Conditional注解和Condition接口实现的。

    step 3、refresh() 容器刷新
    所有Bean的加载和各种依赖的注入都在这个方法中实现的,之前先了解下两个接口BeanFactoryPostProcessor和BeanPostProcessor,它们都是Spring容器初始化时对外暴露的扩展点。

    BeanFactoryPostProcesso接口:

    public interface BeanFactoryPostProcessor {
        void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
    }
    

    只有一个方法postProcessBeanFactory(),它是在容器注册了Bean定义(BeanDefinition)之后,实例化之前执行的。通过这个接口可以获取Bean定义的元数据并且修改它们,如Bean的scope属性、property值等,也可以操作beanFactory。

    BeanPostProcessor接口:

    public interface BeanPostProcessor {
        // 实例化、依赖注入完毕,在调用显示的初始化之前完成一些定制的初始化任务 
        Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
        // 实例化、依赖注入、初始化完毕时执行。 
        Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
    
    }
    

    BeanPostProcessor会在Bean实例化完毕后执行,所以任何BeanPostProcessor都是在BeanFactoryPostProcessor之后执行的。
    BeanPostProcessor的作用可大了,比如自动注入、各种代理(AOP)等等,凡是对需要Bean进行增强操作的大都可以通过它来实现。

    码字不易,转载请保留原文连接https://www.jianshu.com/p/86b53e3f0264

    相关文章

      网友评论

        本文标题:spring容器加载分析 一容器构造

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