spring boot 源码分析(一)

扫码关注公众号:Java 技术驿站

发送:vip
将链接复制到本浏览器,永久解锁本站全部文章

【公众号:Java 技术驿站】 【加作者微信交流技术,拉技术群】

1、spring boot 入口类

    package com.vesus.springboothelloworld;

    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;

    @SpringBootApplication
    public class SpringbootHelloworldApplication {

        public static void main(String[] args) {

            SpringApplication.run(SpringbootHelloworldApplication.class, args);
        }
    }

2、查看注解@SpringBootApplication配置

    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    @SpringBootConfiguration
    @EnableAutoConfiguration
    @ComponentScan(
        excludeFilters = {@Filter(
        type = FilterType.CUSTOM,
        classes = {TypeExcludeFilter.class}
    ), @Filter(
        type = FilterType.CUSTOM,
        classes = {AutoConfigurationExcludeFilter.class}
    )}
    )
    public @interface SpringBootApplication {
        ...
    }

去掉元注解,剩下三个注解@SpringBootConfiguration,@EnableAutoConfiguration,@ComponentScan下面我们进入到SpringBootConfiguration类。

2.1、查看@SpringBootConfiguration注解

    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Configuration
    public @interface SpringBootConfiguration {
    }

可以看到这个注解实际上和@Configuration有相同的作用.

2.2、@ComponentScan

顾名思义,这个注解完成的是自动扫描的功能,相当于Spring XML配置文件中的,默认扫描@ComponentScan注解所在类的同级类和同级目录下的所有类.

    <context:component-scan>

2.3、@EnableAutoConfiguration

    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    @AutoConfigurationPackage
    @Import({EnableAutoConfigurationImportSelector.class})
    public @interface EnableAutoConfiguration {
        String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

        Class<?>[] exclude() default {};

        String[] excludeName() default {};
    }
  1. 入口方法

3.1 SpringApplication的实例化

    SpringApplication.run(SpringbootHelloworldApplication.class, args);

相应实现:

    //实现方法
    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);
    }

它实际上会构造一个SpringApplication的实例(new SpringApplication),然后运行它的run方法:

    public SpringApplication(Object... sources) {
        //调用初始化方法
        initialize(sources);
    }

SpringApplication的构造函数会调用initialize方法进行初始化

    private void initialize(Object[] sources) {
        //判断参数是否存在,存在添加至sources中,该属性是一个LinkedHashSet类型
        if (sources != null && sources.length > 0) {
            this.sources.addAll(Arrays.asList(sources));
        }
        //判断是否为web程序,主要判断类中是否包含(“javax.servlet.Servlet",
                "org.springframework.web.context.ConfigurableWebApplicationContext)这两个类
        this.webEnvironment = deduceWebEnvironment();
        setInitializers((Collection) getSpringFactoriesInstances(
        ApplicationContextInitializer.class));
        setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
        this.mainApplicationClass = deduceMainApplicationClass();
    }

1、首先,会把sources参数添加到SpringApplication对象的sources属性,该属性是一个LinkedHashSet类型

    private final Set<Object> sources = new LinkedHashSet<Object>();

接下来的调用了deduceWebEnvironment方法,判断是否为web程序,主要判断类中是否包含(“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;
        }

    private static final String[] WEB_ENVIRONMENT_CLASSES = { "javax.servlet.Servlet",
                "org.springframework.web.context.ConfigurableWebApplicationContext" };

2、接下来初始化ApplicationContextInitializer

    在classpath下的JAR文件中包含的/META/spring.factories文件里找到对应的属性,然后实例化并排序,设置到SpringApplication对象的initializers属性,该属性是一个ArrayList类型

    private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type,
                Class<?>[] parameterTypes, Object... args) {
            ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
            // 在classpath下的JAR文件中包含的/META/spring.factories文件里找到对应的属性
            Set<String> names = new LinkedHashSet<String>(
                    SpringFactoriesLoader.loadFactoryNames(type, classLoader));
            List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
                    classLoader, args, names);
            //实例化并排序,设置到SpringApplication对象的initializers属性
            AnnotationAwareOrderComparator.sort(instances);
            return instances;
        }

取出的属性值为:

    0 = "org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer"
    1 = "org.springframework.boot.context.ContextIdApplicationContextInitializer"
    2 = "org.springframework.boot.context.config.DelegatingApplicationContextInitializer"
    3 = "org.springframework.boot.context.embedded.ServerPortInfoApplicationContextInitializer"
    4 = "org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer"
    5 = "org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer"

3、初始化监听器ApplicationListener

    在classpath下的JAR文件中包含的/META/spring.factories文件里找到org.springframework.context.ApplicationListener对应的属性,然后实例化并排序,设置到SpringApplication对象的listeners属性,该属性是一个ArrayList类型

    private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type,
                Class<?>[] parameterTypes, Object... args) {
            ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
            // Use names and ensure unique to protect against duplicates
            Set<String> names = new LinkedHashSet<String>(
                    SpringFactoriesLoader.loadFactoryNames(type, classLoader));
            List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
                    classLoader, args, names);
            AnnotationAwareOrderComparator.sort(instances);
            return instances;
        }

取出的属性值为:

    0 = "org.springframework.boot.ClearCachesApplicationListener"
    1 = "org.springframework.boot.builder.ParentContextCloserApplicationListener"
    2 = "org.springframework.boot.context.FileEncodingApplicationListener"
    3 = "org.springframework.boot.context.config.AnsiOutputApplicationListener"
    4 = "org.springframework.boot.context.config.ConfigFileApplicationListener"
    5 = "org.springframework.boot.context.config.DelegatingApplicationListener"
    6 = "org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener"
    7 = "org.springframework.boot.logging.ClasspathLoggingApplicationListener"
    8 = "org.springframework.boot.logging.LoggingApplicationListener"
    9 = "org.springframework.boot.autoconfigure.BackgroundPreinitializer"

4、最后调用deduceMainApplicationClass方法找到main函数所在的类,实现的方式是获取当前方法调用栈,找到main函数的类,并设置到SpringApplication对象的mainApplicationClass属性,该属性是一个Class类型

    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;
        }

来源:http://ddrv.cn

赞(0) 打赏
版权归原创作者所有,任何形式的转载请联系博主:daming_90:Java 技术驿站 » spring boot 源码分析(一)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏