프로세스를 시작 springboot (F) IOC 컨테이너 새로 고침 과정 (파트 I)

전체 기사

https://www.cnblogs.com/lay2017/p/11478237.html

 

본문

이전 기사에서, 우리는 환경 창조, 응용 프로그램 구성 파일을로드 개체의 ApplicationContext의 인스턴스를 생성 볼뿐만 아니라, 메인 클래스가로드하는 BeanDefinition을하게된다. IOC 컨테이너를 상쾌 중앙 부분에 마지막으로 너무 많은 준비를 완료합니다.

여기, 우리는 도움이되지 수 있지만 다시 SpringAplication 실행 방법을 찾기 위해

공공 ConfigurableApplicationContext RUN (문자열 ... 인수) {
     // 문맥 컨테이너 선언 
    ConfigurableApplicationContext 컨텍스트 = 널 (null)를 ;
     // 리스너 얻을 
    리스너] =의에서 SpringApplicationRunListeners을 getRunListeners (인수);
     // 시작 청취자 전화 
    , listeners.starting () 

    은 try를 {
         // 생성 환경을 설정 (프로그램 구성 파일을로드이 프로세스) 
        ConfigurableEnvironment 환경 = (리스너, applicationArguments에서) prepareEnvironment 단계;
         // 애플리케이션의 종류에 따라 용기를 대응 콘텍스트 생성 
        컨텍스트 =를 ; createApplicationContext () 

        // 리프레시 컨텍스트 용기 전의 준비
        prepareContext (문맥, 환경, 리스너에서, applicationArguments, printedBanner);
         // 새로 고침 상황에 맞는 컨테이너 
        , refreshContext (컨텍스트)
         // 새로 고침 컨텍스트 컨테이너 후 공정 
        AfterRefresh (문맥, applicationArguments); 

        // 컨텍스트 컨테이너는 완전한 릴리스 새로 고침 
        listeners.started (컨텍스트) ; 

        // 트리거 컨텍스트 컨테이너가 새로 고침되어 수행 한 후에 
        callRunners (문맥, applicationArguments); 
    } 캐치 (Throwable의 EX) {} 

    은 try {
         // 컨텍스트 부팅이 완료 될 때, 주자가 릴리스 실행을 완료 
        , listeners.running (컨텍스트) 
    } 캐치 (Throwable의 EX를 ) {} 

    반환  컨텍스트;
}

실행에있어서, 입구 및 플러싱 IOC afterRefresh 용기 사이에있어서 refreshContext prepareContext 방법.

 

ApplicationContext는 和의 BeanFactory

그러나 refreshContext 방법을 읽기 전에, 우리는 두 가지의 ApplicationContext와 BeanFactory를 사이에 어떤 관계를 구별해야합니다. 이전 기사에서 우리는 두 가지를 구분하지 않습니다. 예를 들어, 우리는 항상 "빈은 ApplicationContext를 컨테이너에 등록."라고

우리의 이해에서, 컨테이너는 물건을 저장하는 무언가를위한 공간의 개념을해야합니다. 봄, 가게는 콩이다. 콩의 BeanFactory가 아니라 우리가 ApplicationContext의 말을 한 것보다, 위치 때문에 BeanFactory에이 같은 콩의 주요 컨테이너 저장 공간을 제공한다.

ApplicationContext를 이후로는 셰인 즉, 컨테이너 아닌가요? 우리는 "컨텍스트."호출 "컨텍스트"의 개념은 우리가 반드시 그렇게 익숙하지 수 있지만 "장면"의 개념 이러한 "배치"우리가 더 잘 알고에 있어야합니다. 예를 들어, "촬영 장면", "거래 장소"등등. 그들은 일반적인 이벤트입니다 경우. 그래서 스프링 ApplicationContext에 정의 된 응용 프로그램 이벤트 장소, 소위 애플리케이션 컨텍스트입니다.

 

위, 나는 ApplicationContext를하는 동안 컨텍스트로, BeanFactory에 빈 컨테이너를 이해. 그래서 및 빈 컨테이너 컨텍스트 사이의 관계는 무엇인가? 우리는 조각을 볼 수 있습니다

// 일반 애플리케이션 컨텍스트 구현 
공용  클래스 GenericApplicationContext (가) 확장 AbstractApplicationContext에게 구현 BeanDefinitionRegistry에 {
         // 기본 구현되는 BeanFactory 
    개인  최종 의 DefaultListableBeanFactory의 BeanFactory를; 

    //가 생략 
}

우리는 그들의 관계가 한 관계의 조합, ApplicationContext를 BeanFactory에의 조합 중 하나입니다 참조하십시오. 즉, 애플리케이션 컨텍스트는 빈 공장이 포함되어 있습니다.

 

다음으로, 우리는 ApplicationContext를 클래스 다이어그램의 각보고

보기의 외부 포인트는 모두 하나이기 때문에 우리는 ApplicationContext를 외부 ApplicationContext를 우리가 항상 주된 이유 등의 ApplicationContext 컨테이너 보는 이유는 BeanFactory에,로 사용할 수 있다는 것을 의미한다 BeanFactory를 상속 있다는 것을 참조하십시오.

특정 작업의 내부 ApplicationContext는 BeanFactory에 관련된 구현은 내부의 BeanFactory 구현 클래스의 조합에 의해 수행 될 경우 위의 조합과의 관계, 우리는 알 수 있습니다.

상속의 조합 : 여기, 우리는 기본적으로의 ApplicationContext와 BeanFactory에 두 가지 방법 사이의 관계를 이해한다.

나중에 우리는 ApplicationContext의 컨텍스트를 요구하지만, 콩의 BeanFactory는 컨테이너, 그 차이를 확인하십시오.

 

상황에 맞는 조합 콩 공장

그래서 시간이 BeanFactory를 수행하도록 ApplicationContext를 결합? 우리는 구현 클래스의 클래스 다이어그램을 살펴의 ApplicationContext

주의! ApplicationContext의 구현 클래스 springboot 기본 서블릿 프로젝트는 AnnotationCofnigServletWebServerApplicationContext, 그래서 우리는 구현 클래스로 볼 것이다

우리의 상향식 (bottom-up)은, 우리가 볼 수 GenericApplicationContext하기 전에 미리보기가 나타 찾기 위해 상속 체인을 따라

공공  클래스 GenericApplicationContext는 확장 AbstractApplicationContext이 구현 BeanDefinitionRegistry에 { 

    민간  최종 의 DefaultListableBeanFactory의 BeanFactory를; 

    공개 GenericApplicationContext () {
          .beanFactory = 의 DefaultListableBeanFactory (); 
    } 

    // 省略 
}

这里,在GenericApplicationContext的构造方法当中构建了一个DefaultListableBeanFactory的实例对象。DefaultListableBeanFactory也就是BeanFactory的默认实现,那么也就是说在构造ApplicationContext实例对象的时候创建并组合了一个BeanFactory的实例。

 

我们顺便也看看DefaultListableBeanFactory的继承关系吧

这个类图只保留了BeanFactory的东西,设计路线自BeanFactory到DefaultListableBeanFactory也很清晰。

 

refreshContext刷新过程

下面,我们将正式进行refreshContext方法的阅读。打开refreshContext方法

private void refreshContext(ConfigurableApplicationContext context) {
    refresh(context);
    if (this.registerShutdownHook) {
        try {
            context.registerShutdownHook();
        } catch (AccessControlException ex) {
            // Not allowed in some environments.
        }
    }
}

跟进refresh方法

protected void refresh(ApplicationContext applicationContext) {
    Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
    ((AbstractApplicationContext) applicationContext).refresh();
}

我们看到,这里调用的是AbstractApplicationContext的refresh方法,顺序AnnotationConfigServletWebServerApplicationContext的继承链向上可以找到AbstractApplicationContext。

 

我们继续跟进AbstractApplicationContext的refresh方法,refresh方法有点长

public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        // 刷新前准备,设置flag、时间,初始化properties等
        prepareRefresh();

        // 获取ApplicationContext中组合的BeanFactory
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

        // 设置类加载器,添加后置处理器等准备
        prepareBeanFactory(beanFactory);

        try {
            // 供子类实现的后置处理
            postProcessBeanFactory(beanFactory);

            // 调用Bean工厂的后置处理器
            invokeBeanFactoryPostProcessors(beanFactory);

            // 注册Bean的后置处理器
            registerBeanPostProcessors(beanFactory);

            // 初始化消息源
            initMessageSource();

            // 初始化事件广播
            initApplicationEventMulticaster();

            // 供之类实现的,初始化特殊的Bean
            onRefresh();

            // 注册监听器
            registerListeners();

            // 实例化所有的(non-lazy-init)单例Bean
            finishBeanFactoryInitialization(beanFactory);

            // 发布刷新完毕事件
            finishRefresh();
        }

        catch (BeansException ex) {
            // 
        } finally {        
            // 
        }
    }
}

上一篇文章中,我们提到了这么一个初始化过程:

annotation或者xml中Bean的配置 --> 内存中的BeanDefinition --> Bean

也就是实际的配置,转化成内存中的配置对象,再根据配置对象转化成具体的实例对象。说白了就是从元数据到实例的一个转化过程。

为什么会提及这么一个转化过程呢?因为我们的refresh过程主要包含的就是其中的一步,也就是从annotation或者xml的Bean配置 --> 内存中的BeanDefinition的过程。这个过程的实现在调用Bean工厂的后置处理器的时候完成,也就是invokeBeanFactoryPostProcessors方法

 

我们跟进invokeBeanFactoryPostProcessors方法

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
    PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
    // 
}

这里先获取了所有后置处理器,然后调用处理。再跟进PostProcessorRegistrationDelegate的invokeBeanFactoryFactoryPostProcessors方法

该方法很长,我们删减掉大部分内容

public static void invokeBeanFactoryPostProcessors(
        ConfigurableListableBeanFactory beanFactory, 
        List<BeanFactoryPostProcessor> beanFactoryPostProcessors
        ) {
    // 
    if (beanFactory instanceof BeanDefinitionRegistry) {
        //
        while (reiterate) {
            // 调用BeanDefinition注册的后置处理器
            invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
            // 
        }
        //
    } else {
        // 
    }
    //
}

可以看到,调用后置处理器的时候会调用到注册BeanDefinition的后置处理器。也就是从这里开始作为BeanDefinition的注册入口

 

跟进invokeBeanDefinitionRegistryPostProcessors

private static void invokeBeanDefinitionRegistryPostProcessors(
            Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, 
            BeanDefinitionRegistry registry
            ) {
    for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
        postProcessor.postProcessBeanDefinitionRegistry(registry);
    }
}

这里我们需要断点一下,看看有哪些后置处理器处理BeanDefinition注册

我们看到了ConfigurationClassPostProcessor也就是它完成BeanDefinition注册这项工作的

 

我们跟进ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry方法

public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
    // 省略
    processConfigBeanDefinitions(registry);
}

继续跟进,我们看到processConfigBeanDefinitions方法挺长的,进行了大量的缩减

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
    List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
    String[] candidateNames = registry.getBeanDefinitionNames();

    for (String beanName : candidateNames) {
        BeanDefinition beanDef = registry.getBeanDefinition(beanName);
        if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
                ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
            // 
        } else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
            // 默认仅有主类被添加
            configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
        }
    }

    //

    // 解析被 @Configuration 注解的类
    ConfigurationClassParser parser = new ConfigurationClassParser(
            this.metadataReaderFactory, 
            this.problemReporter, 
            this.environment,
            this.resourceLoader, 
            this.componentScanBeanNameGenerator, 
            registry);

    Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
    // 
    do {
        // 解析的核心方法
        parser.parse(candidates);
        parser.validate();

        // 

        candidates.clear();
        // 
    } while (!candidates.isEmpty());
    // 
}

上一篇文章中,也就是在prepareContext方法的核心逻辑里,main方法所在的主类将会被作为BeanDefinition加载到BeanFactory当中。而在这里,该主类将被作为一个配置类被解析,解析器即ConfigurationClassParser。

 

我们跟进parse方法看看

public void parse(Set<BeanDefinitionHolder> configCandidates) {
    for (BeanDefinitionHolder holder : configCandidates) {
        BeanDefinition bd = holder.getBeanDefinition();
        try {
            if (bd instanceof AnnotatedBeanDefinition) {
                // 主类的解析将从这里进入
                parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
            } else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
                parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
            } else {
                parse(bd.getBeanClassName(), holder.getBeanName());
            }
        } catch (BeanDefinitionStoreException ex) {}
          catch (Throwable ex) {}
    }

    this.deferredImportSelectorHandler.process();
}

继续跟进parse方法

protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
    processConfigurationClass(new ConfigurationClass(metadata, beanName));
}

可以看到主类作为配置类的解析过程将从processConfigurationClass这里开始

 

总结

到这里,ioc容器的refresh过程先做一个小结。我们知道了上下文和Bean容器是继承关系又是组合关系。refreshContext的核心就是为了加载BeanDefinition,而加载BeanDefinition将从main方法所在的主类开始,主类作为一个配置类将由ConfigurationClassParser解析器来完成解析的职责。下一篇文章,我们将会看到从主类中解析出BeanDefinition的主要逻辑。

 

추천

출처www.cnblogs.com/lay2017/p/11494581.html