[SpringBoot] SpringApplication 인 스 턴 스 생 성

제목: [SpringBoot] SpringApplication 인 스 턴 스 생 성 날짜: 2017 - 07 - 05 21: 22: 54 태그:
  • Java
  • Spring categories: Spring

  • 책 은 지난 번 에 Spring Boot 가 작 동 하 는 입 구 는 JarLaunchermain 방법 이 라 고 말 했다.그 중의 주요 논 리 는 각종 자원 을 불 러 온 후에 새로운 스 레 드 호출 프로그램의 입 구 를 여 는 것 이다.전체 응용 프로그램의 시작 은 여기 서 천천히 전개 되 고 본 고 는 SpringApplication 의 정적 방법 run 에서 호출 된 후에 SpringApplication 인 스 턴 스 를 생 성 하 는 과정 만 설명 한다.그 후의 다른 시작 절 차 는 본 논문 에 기록 되 어 있 지 않다.
    앞에서 말 한 main 방법의 호출:
    @SpringBootApplication
    public class Application {
        public static void main(String[] args) {
            SpringApplication.run(Application.class, args);
        }
    }
    

    정적 run 방법 은 전체 프로그램의 입구 이지 만 최종 적 으로 예화 되 었 다 SpringApplication 대상:
        private final Set sources = new LinkedHashSet();
    
        public static ConfigurableApplicationContext run(Object source, String... args) {
            return run(new Object[] { source }, args);
        }
    
        public static ConfigurableApplicationContext run(Object[] sources, String[] args) {
            return new SpringApplication(sources).run(args);
        }
    
        public SpringApplication(Object... sources) {
            initialize(sources);
        }
    

    오늘 의 목 표 는 initialize 방법의 실현 이다.
        private void initialize(Object[] sources) {
            if (sources != null && sources.length > 0) {
                this.sources.addAll(Arrays.asList(sources));
            }
            //    web    
            this.webEnvironment = deduceWebEnvironment();
            //       
            setInitializers((Collection) getSpringFactoriesInstances(
                    ApplicationContextInitializer.class));
            //      
            setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
            // main     
            this.mainApplicationClass = deduceMainApplicationClass();
        }
    

    웹 환경 추정
    먼저 웹 환경의 판단 을 살 펴 보 자.
        // org/springframework/boot/SpringApplication.java
        private static final String[] WEB_ENVIRONMENT_CLASSES = { "javax.servlet.Servlet",
                "org.springframework.web.context.ConfigurableWebApplicationContext" };
        
        private boolean deduceWebEnvironment() {
            for (String className : WEB_ENVIRONMENT_CLASSES) {
                if (!ClassUtils.isPresent(className, null)) {
                    return false;
                }
            }
            return true;
        }
    

    주어진 클래스 로 더 (null) 가 주어진 클래스 WEB_ENVIRONMENT_CLASSES 를 불 러 올 수 있 는 지 판단 합 니 다.로 더 는 비어 있 습 니 다. 따라 들 어가 면 비어 있 을 때 기본 클래스 로 더 가 있 습 니 다.
        // org/springframework/util/ClassUtils.java
        public static ClassLoader getDefaultClassLoader() {
            ClassLoader cl = null;
            try {
                cl = Thread.currentThread().getContextClassLoader();
            }
            catch (Throwable ex) {
            }
            if (cl == null) {
                cl = ClassUtils.class.getClassLoader();
                if (cl == null) {
                    try {
                        cl = ClassLoader.getSystemClassLoader();
                    }
                    catch (Throwable ex) {
                    }
                }
            }
            return cl;
        }
    

    메 인 방법 찾기
    다른 방법 을 건 너 뛰 고 먼저 보기 main 방법 이 있 는 클래스 찾기
        private Class> deduceMainApplicationClass() {
            try {
                StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
                for (StackTraceElement stackTraceElement : stackTrace) {
                    if ("main".equals(stackTraceElement.getMethodName())) {
                        return Class.forName(stackTraceElement.getClassName());
                    }
                }
            }
            catch (ClassNotFoundException ex) {
                // Swallow and continue
            }
            return null;
        }
    

    main 방법 이 있 는 종 류 를 찾 는 것 은 6 을 비교 하 는 것 입 니 다. 직접 이상 을 만들어 서 창고 에서 찾 는 것 도 기이 한 기교가 라 고 할 수 있 습 니 다.
    초기 화 장치, 모니터 의 로드, 예화
    다음은 SpringApplication 실례 화의 가장 중요 한 부분 인 초기 화기 와 감청 기의 설정 을 중점적으로 살 펴 보 자.
    이들 의 핵심 논 리 는 모두 같 지만 매개 변수 가 다 를 뿐이다.
        private  Collection extends T> getSpringFactoriesInstances(Class type) {
            return getSpringFactoriesInstances(type, new Class>[] {});
        }
    
        private  Collection extends T> getSpringFactoriesInstances(Class type,
                Class>[] parameterTypes, Object... args) {
            ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
            //          ,            
            Set names = new LinkedHashSet(
                    SpringFactoriesLoader.loadFactoryNames(type, classLoader));
            //     ,      
            List instances = createSpringFactoriesInstances(type, parameterTypes,
                    classLoader, args, names);
            AnnotationAwareOrderComparator.sort(instances);
            return instances;
        }
    
        //        
        public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
        //        key factoryClass.getName()  
        public static List loadFactoryNames(Class> factoryClass, 
                                                    ClassLoader classLoader) {
            String factoryClassName = factoryClass.getName();
            try {
                Enumeration urls = (classLoader != null ?
                                         classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
                                       ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
                List result = new ArrayList();
                while (urls.hasMoreElements()) {
                    URL url = urls.nextElement();
                    Properties properties = 
                      PropertiesLoaderUtils.loadProperties(new UrlResource(url));
                    String factoryClassNames = 
                      properties.getProperty(factoryClassName);
                    result.addAll(Arrays.asList(
                      StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
                }
                return result;
            }
            catch (IOException ex) {
                throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() +
                        "] factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex);
            }
        }
    

    모든 초기 화 장치 와 모니터 는 CLASSPATH 의 META-INF/spring.factories 파일 에서 가 져 옵 니 다. 구체 적 인 설정:
    # Application Context Initializers
    org.springframework.context.ApplicationContextInitializer=\
    org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
    org.springframework.boot.context.ContextIdApplicationContextInitializer,\
    org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
    org.springframework.boot.context.embedded.ServerPortInfoApplicationContextInitializer
    
    # Application Listeners
    org.springframework.context.ApplicationListener=\
    org.springframework.boot.ClearCachesApplicationListener,\
    org.springframework.boot.builder.ParentContextCloserApplicationListener,\
    org.springframework.boot.context.FileEncodingApplicationListener,\
    org.springframework.boot.context.config.AnsiOutputApplicationListener,\
    org.springframework.boot.context.config.ConfigFileApplicationListener,\
    org.springframework.boot.context.config.DelegatingApplicationListener,\
    org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener,\
    org.springframework.boot.logging.ClasspathLoggingApplicationListener,\
    org.springframework.boot.logging.LoggingApplicationListener
    

    SpringApplication 의 인 스 턴 스 과정 을 요약 합 니 다.
  • 웹 환경 여 부 를 판단 합 니 다
  • 초기 화 장치 와 모니터 를 불 러 오고 예화
  • main 방법 이 있 는 종 류 를 찾 습 니 다
  • 각 과정의 특징:
  • 웹 환경 은 Spring 의 기본 로 더 가 주어진 종 류 를 불 러 올 수 있 는 지 여부
  • 에 따라 판단 합 니 다.
  • 초기 화 기와 모니터 의 로드 는 모두 근거 META-INF/spring.factories
  • main 방법 이 있 는 종 류 를 찾 는 것 은 이상 을 던 져 서 스 택 에서 찾 는 것 입 니 다
  • 좋은 웹페이지 즐겨찾기