SpringBoot 启动类 源码解析 (二 . run() 方法之 prepareEnvironment createApplicationContext 解析)

SpringBoot 启动类 源码解析 (一 .new SpringApplication 解析)


 // * 方法为重要的方法 不加 * 的可以不看 意义不大

@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
public class CmasApplication
{
    public static void main(String[] args)
    {
        // 点击run方法进入
        SpringApplication.run(CmasApplication.class, args);
    }
}

public class SpringApplication {

    // run 方法
    public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
        return run(new Class<?>[] { primarySource }, args);
    }

    //  通过 run 方法进入 1. new了 一个 SpringApplication 对象  2.调用 run 方法
    public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
        // 点击 进入  run 的方法 
        return new SpringApplication(primarySources).run(args);
    }

    // run
    public ConfigurableApplicationContext run(String... args) {
        // 翻译为秒表 
        StopWatch stopWatch = new StopWatch();
        // 进入 start 方法  记录了 当前任务 当前启动时间 
        stopWatch.start();
        // 上下文
        ConfigurableApplicationContext context = null;
        // 启动异常报告集合:支持自定义  springboot启动错误会进行回调 (看源码的翻译 简洁明了)
        Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
        // 设置jdk系统属性java.awt.headless,默认情况为true即开启 看翻译是和 jdk相关的 不重要
        configureHeadlessProperty();
        // 获取springboot 启动监听器 进入 getRunListeners  返回 EventPublishingRunListener 监听器 这是是从SpringFactoriesLoader.cache 缓存里获取的
        // 还记得 SpringApplication 实例化时 设置监听器和初始化器 把所有文件放到了缓存里吗
        //  这是spring-boot 下的 META-INF/spring.factories 文件内的内容 我们可以看到 我们传入的 key 是 SpringApplicationRunListener
        //  # Run Listeners
        //  org.springframework.boot.SpringApplicationRunListener=\
        //  org.springframework.boot.context.event.EventPublishingRunListener
       
        SpringApplicationRunListeners listeners = getRunListeners(args);
        //  监听器启动 进行 ApplicationStartingEvent 事件广播
        listeners.starting();
        try {
            // 参数封装,即命令行启动时所传参数,如 --server.port=8080
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            // * 准备系统环境 进入方法 listeners 只有一个值就是 EventPublishingRunListener 
            // 加载外部化配置资源到environment,包括命令行参数、servletConfigInitParams、servletContextInitParams、
            //systemProperties、sytemEnvironment、random、application.yml(.yaml/.xml/.properties)等,初始化日志系统。
            ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
            // 配置spring.beaninfo.ignore,并添加到 systemProperties的PropertySource中,默认为true即开启 (跳过)
            configureIgnoreBeanInfo(environment);
            // 控制台打印图案 (不重要)
            Banner printedBanner = printBanner(environment);
            // * 创建应用上下文 我们先看到这里
            // 对其部分属性:reader、scanner、beanFactory进行了实例化;reader中实例化了属性conditionEvaluator;
            context = createApplicationContext();
           
            exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
                    new Class[] { ConfigurableApplicationContext.class }, context);
            
            prepareContext(context, environment, listeners, applicationArguments, printedBanner);

            refreshContext(context);
            afterRefresh(context, applicationArguments);
            stopWatch.stop();
            if (this.logStartupInfo) {
                new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
            }
            listeners.started(context);
            callRunners(context, applicationArguments);
        }
        catch (Throwable ex) {
            handleRunFailure(context, ex, exceptionReporters, listeners);
            throw new IllegalStateException(ex);
        }

        try {
            listeners.running(context);
        }
        catch (Throwable ex) {
            handleRunFailure(context, ex, exceptionReporters, null);
            throw new IllegalStateException(ex);
        }
        return context;
    }

    public void start(String taskName) throws IllegalStateException {
        if (this.currentTaskName != null) {
            throw new IllegalStateException("Can't start StopWatch: it's already running");
        }
        this.currentTaskName = taskName;
        this.startTimeNanos = System.nanoTime();
    }

    // 获取监听器
    private SpringApplicationRunListeners getRunListeners(String[] args) {
        Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
        return new SpringApplicationRunListeners(logger,
                getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
    }
    // 获取 工厂实例 我们发现 这个方法又被调了,在 new SpringApplication 时 设置初始化器和监听器就调用了这个方法 
    private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
        ClassLoader classLoader = getClassLoader();
        // Use names and ensure unique to protect against duplicates
        Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
        List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
        AnnotationAwareOrderComparator.sort(instances);
        return instances;
    }
    // 准备系统环境
    private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
            ApplicationArguments applicationArguments) {
        // 获取或者创建系统环境  进入方法 
        ConfigurableEnvironment environment = getOrCreateEnvironment();
        // 配置PropertySources和activeProfiles
        configureEnvironment(environment, applicationArguments.getSourceArgs());
        ConfigurationPropertySources.attach(environment);
        // ApplicationEnvironmentPreparedEvent 监听器环境准备 进行事件广播(应用环境准备事件)   
        //和前面的 listeners.starting(); 一样的调用,只是发布的事件不同(ApplicationStartingEvent)
        listeners.environmentPrepared(environment);
        // 将环境绑定到SpringApplication
        bindToSpringApplication(environment);
        if (!this.isCustomEnvironment) {
            environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
                    deduceEnvironmentClass());
        }
        ConfigurationPropertySources.attach(environment);
        return environment;
    }
    // 获取或者创建系统环境
    private ConfigurableEnvironment getOrCreateEnvironment() {

        if (this.environment != null) {
            return this.environment;
        }
        switch (this.webApplicationType) {
        case SERVLET:
            return new StandardServletEnvironment(); // 我们知道 webApplicationType = SERVLET 返回 StandardServletEnvironment
        case REACTIVE:
            return new StandardReactiveWebEnvironment();
        default:
            return new StandardEnvironment();
        }
    }
    // * 配置环境
    protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
        if (this.addConversionService) {
            ConversionService conversionService = ApplicationConversionService.getSharedInstance();
            environment.setConversionService((ConfigurableConversionService) conversionService);
        }
        // 配置属性资源
        configurePropertySources(environment, args);
        // 配置 profile 
        configureProfiles(environment, args);
    }
    // * 创建应用上下文
    protected ConfigurableApplicationContext createApplicationContext() {
        Class<?> contextClass = this.applicationContextClass;
        if (contextClass == null) {
            try {
                // 还记得 this.webApplicationType 参数吗,在上面已经看过 是 web应用  this.webApplicationType = SERVLET
                // DEFAULT_SERVLET_WEB_CONTEXT_CLASS 是个常量 代码如下:
                // public static final String DEFAULT_SERVLET_WEB_CONTEXT_CLASS = "org.springframework.boot." + "web.servlet.context.AnnotationConfigServletWebServerApplicationContext";
                // 是个全路径类名 通过反射获取到 AnnotationConfigServletWebServerApplicationContext class
                switch (this.webApplicationType) {
                case SERVLET:
                    contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
                    break;
                case REACTIVE:
                    contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
                    break;
                default:
                    contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
                }
            }
            catch (ClassNotFoundException ex) {
                throw new IllegalStateException(
                        "Unable create a default ApplicationContext, please specify an ApplicationContextClass", ex);
            }
        }
        // 创建 AnnotationConfigServletWebServerApplicationContext 实例对象 
        return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
    }

    //
    public static <T> T instantiateClass(Class<T> clazz) throws BeanInstantiationException {
        Assert.notNull(clazz, "Class must not be null");
        if (clazz.isInterface()) {
            throw new BeanInstantiationException(clazz, "Specified class is an interface");
        }
        try {
            // 获取默认构造器,然后进行实例化
            return instantiateClass(clazz.getDeclaredConstructor());
        }
        catch (NoSuchMethodException ex) {
            Constructor<T> ctor = findPrimaryConstructor(clazz);
            if (ctor != null) {
                return instantiateClass(ctor);
            }
            throw new BeanInstantiationException(clazz, "No default constructor found", ex);
        }
        catch (LinkageError err) {
            throw new BeanInstantiationException(clazz, "Unresolvable class definition", err);
        }
    }

    public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {
        Assert.notNull(ctor, "Constructor must not be null");
        try {
            // 让构造方法变成可访问的 里面代码较少,代码意思一目了然,我直接复制到这 
            // if ((!Modifier.isPublic(ctor.getModifiers()) || !Modifier.isPublic(ctor.getDeclaringClass().getModifiers())) && !ctor.isAccessible()) {
            //    ctor.setAccessible(true);
            // }
            ReflectionUtils.makeAccessible(ctor);
            if (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(ctor.getDeclaringClass())) {
                return KotlinDelegate.instantiateClass(ctor, args);
            }
            else {
                // 代码走这里
                Class<?>[] parameterTypes = ctor.getParameterTypes();
                // 参数不能比构造器参数多,从调用可知 这里没有参数 所以不进入 for循环
                Assert.isTrue(args.length <= parameterTypes.length, "Can't specify more arguments than constructor parameters");
                Object[] argsWithDefaultValues = new Object[args.length];
                for (int i = 0 ; i < args.length; i++) {
                    if (args[i] == null) {
                        Class<?> parameterType = parameterTypes[i];
                        argsWithDefaultValues[i] = (parameterType.isPrimitive() ? DEFAULT_TYPE_VALUES.get(parameterType) : null);
                    }
                    else {
                        argsWithDefaultValues[i] = args[i];
                    }
                }
                // 通过构造器创建对象
                return ctor.newInstance(argsWithDefaultValues);
            }
        }
        catch (InstantiationException ex) {
            throw new BeanInstantiationException(ctor, "Is it an abstract class?", ex);
        }
        catch (IllegalAccessException ex) {
            throw new BeanInstantiationException(ctor, "Is the constructor accessible?", ex);
        }
        catch (IllegalArgumentException ex) {
            throw new BeanInstantiationException(ctor, "Illegal arguments for constructor", ex);
        }
        catch (InvocationTargetException ex) {
            throw new BeanInstantiationException(ctor, "Constructor threw exception", ex.getTargetException());
        }
    }
}

public final class SpringFactoriesLoader {

    public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";


    // 根据类型获取工厂名 也就是全路径的类名 factoryType = ApplicationContextInitializer.class
    public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
        String factoryTypeName = factoryType.getName();
        // 进入方法  META-INF/spring.factories 路径下的所有文件 并通过 getOrDefault 方法进行过滤 (containsKey(key) 文件中的key是否包含 factoryTypeName)
        return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
    }

    private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
        MultiValueMap<String, String> result = cache.get(classLoader);
        if (result != null) {
            return result;
        }

        try {
            // classLoader 里面可以获取到已经加载的所有class 类文件 从类文件根据文件名获取 所有 META-INF/spring.factories 路径下的所有文件
            Enumeration<URL> urls = (classLoader != null ?
                    classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
                    ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
            result = new LinkedMultiValueMap<>();
            while (urls.hasMoreElements()) {
                URL url = urls.nextElement();
                UrlResource resource = new UrlResource(url);
                Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                for (Map.Entry<?, ?> entry : properties.entrySet()) {
                    String factoryTypeName = ((String) entry.getKey()).trim();
                    for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
                        result.add(factoryTypeName, factoryImplementationName.trim());
                    }
                }
            }
            cache.put(classLoader, result);
            return result;
        }
        catch (IOException ex) {
            throw new IllegalArgumentException("Unable to load factories from location [" +
                    FACTORIES_RESOURCE_LOCATION + "]", ex);
        }
    }


}
// 实例化 AnnotationConfigServletWebServerApplicationContext
public class AnnotationConfigServletWebServerApplicationContext extends ServletWebServerApplicationContext
        implements AnnotationConfigRegistry {

    public AnnotationConfigServletWebServerApplicationContext() {
        //实例化  注解bean定义读取器 读取 对象注解的 我们知道对象注解一般有 @Bean @Component 等
        this.reader = new AnnotatedBeanDefinitionReader(this);
        // 实例化类路径bean定义扫描器     
        this.scanner = new ClassPathBeanDefinitionScanner(this);     
    }
} 
// 实例化 注解bean定义读取器 AnnotatedBeanDefinitionReader
public class AnnotatedBeanDefinitionReader {
    // 实例化
    public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
        this(registry, getOrCreateEnvironment(registry));
    }
    // this 调用
    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);
    }
}
// 看翻译 :用于评估Conditional注释的内部类 说明是用于 @Conditional 条件注解的
class ConditionEvaluator {

    public ConditionEvaluator(@Nullable BeanDefinitionRegistry registry,
            @Nullable Environment environment, @Nullable ResourceLoader resourceLoader) {

        this.context = new ConditionContextImpl(registry, environment, resourceLoader);
    }

    // 内部类并且实现了ConditionContext
   private static class ConditionContextImpl implements ConditionContext {

        public ConditionContextImpl(@Nullable BeanDefinitionRegistry registry,
                @Nullable Environment environment, @Nullable ResourceLoader resourceLoader) {

            this.registry = registry;
            // 由返回可知 返回类型为:ConfigurableListableBeanFactory 的工厂
            this.beanFactory = deduceBeanFactory(registry);
            this.environment = (environment != null ? environment : deduceEnvironment(registry));
            this.resourceLoader = (resourceLoader != null ? resourceLoader : deduceResourceLoader(registry));
            this.classLoader = deduceClassLoader(resourceLoader, this.beanFactory);
        }

        @Nullable
        private ConfigurableListableBeanFactory deduceBeanFactory(@Nullable BeanDefinitionRegistry source) {
            if (source instanceof ConfigurableListableBeanFactory) {
                return (ConfigurableListableBeanFactory) source;
            }
            if (source instanceof ConfigurableApplicationContext) {
                return (((ConfigurableApplicationContext) source).getBeanFactory());
            }
            return null;
        }
   }

}

public abstract class AnnotationConfigUtils {
    // 注册注解配置处理器
    public static void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {
        registerAnnotationConfigProcessors(registry, null);
    }


    // 注册注解配置处理器 最终返回了5个实例
    // internalConfigurationAnnotationProcessor internalAutowiredAnnotationProcessor
    // internalCommonAnnotationProcessor internalEventListenerProcessor internalEventListenerFactory
    public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
            BeanDefinitionRegistry registry, @Nullable Object source) {

        DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
        if (beanFactory != null) {
            if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
                beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
            }
            if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
                beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
            }
        }

        Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);

        if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
            RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
        }

        if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
            RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
        }

        // Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
        if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
            RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
        }

        // Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
        if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
            RootBeanDefinition def = new RootBeanDefinition();
            try {
                def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
                        AnnotationConfigUtils.class.getClassLoader()));
            }
            catch (ClassNotFoundException ex) {
                throw new IllegalStateException(
                        "Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
            }
            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
        }

        if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
            RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
        }

        if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
            RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
        }

        return beanDefs;
    }
}

总结一下:
1.记录当前任务 当前时间
2.启动监听器 进行 ApplicationStartingEvent 事件广播
3.启动时命令行参数封装,
4.准备系统环境 加载外部化配置资源到environment,包括命令行参数、servletConfigInitParams、servletContextInitParams、systemProperties、sytemEnvironment、random、application.yml(.yaml/.xml/.properties)等,初始化日志系统
5.配置spring.beaninfo.ignore,并添加到 systemProperties的PropertySource中
6.控制台打印图案
7.创建应用上下文,对其部分属性:reader、scanner、beanFactory进行了实例化;reader中实例化了属性conditionEvaluator;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
当在Spring Boot的启动中使用`context.getBean()`方法时,通常会出现`NullPointerException`或者`NoSuchBeanDefinitionException`等异常。这是因为Spring Boot的启动中的上下文`ApplicationContext`还没有初始化完成,所以在调用`getBean()`方法时会报错。 为了解决这个问题,可以使用`@Autowired`注解或者构造函数注入的方式来获取需要的bean,这样可以确保在启动中获取bean时,上下文已经初始化完成。例如: ```java @SpringBootApplication public class MyApp { @Autowired private MyBean myBean; public static void main(String[] args) { SpringApplication.run(MyApp.class, args); } // ... } ``` 或者: ```java @SpringBootApplication public class MyApp { private final MyBean myBean; public MyApp(MyBean myBean) { this.myBean = myBean; } public static void main(String[] args) { SpringApplication.run(MyApp.class, args); } // ... } ``` 另外,如果你非要在启动中使用`context.getBean()`方法,也可以通过`ApplicationRunner`或者`CommandLineRunner`接口来延迟执行获取bean的操作,如下所示: ```java @SpringBootApplication public class MyApp implements ApplicationRunner { private ApplicationContext context; public static void main(String[] args) { SpringApplication.run(MyApp.class, args); } @Override public void run(ApplicationArguments args) throws Exception { MyBean myBean = context.getBean(MyBean.class); // use myBean } @Autowired public void setContext(ApplicationContext context) { this.context = context; } } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值