美文网首页
spring boot源码解析

spring boot源码解析

作者: java_飞 | 来源:发表于2020-04-20 15:17 被阅读0次

1.看源码的入口

  public static void main(String[] args) {
        SpringApplication.run(MerchantSignApplication.class, args);
    }//任何一个application启动类,都可以找到这个地方

2.第一个比较重要的地方

/**
     * Run the Spring application, creating and refreshing a new
     * {@link ApplicationContext}.
     * @param args the application arguments (usually passed from a Java main method)
     * @return a running {@link ApplicationContext}
     */
public ConfigurableApplicationContext run(String... args){

.......
}

看方法上面注释可以知道,这个类的作用是运行spring应用程序,创建和刷新上下文内容,传入的参数类似main方法,启动的时候配置,返回一个正在运行的上下文;
主要做的工作:
(1).创建定时器并且启动
(2).配置java.awt.headless模式(在该模式下,系统缺少了显示设备、键盘或鼠标)
(3).获取运行的spring监听器,主要是配置在spring.factories然后key为SpringApplicationRunListener的类
(4).启动这些监听器
(5).准备环境
(6).banner打印
(7).创建web上下文或者默认上下文
(8).利用上下文创建分析类
(9).预备上下文环境
(10).刷新上下文
(11).后置上下文刷新
(12).关闭监听器
(13).停止定时器
(14).判断启动信息是否开,开的话就打印启动信息

3.解析各个步骤的实现细节

(1).仅仅是进行开始计时的操作,供最后打印启动信息时,打印出整个系统的启动时间使用
(2).配置成java.awt.headless模式,因为我们的程序会在服务器上跑,然后服务器是没有显示器也没有鼠标,这个模式就是为了让我们可以像有鼠标和显示器一样的操作
(3).

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


public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
        String factoryClassName = factoryClass.getName();
        try {
                  //获取所有jar下面的META-INF/spring.factories
            Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
                    ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
            List<String> result = new ArrayList<String>();
//获取所有在spring.factories里面配置的类名为SpringApplicationRunListener对应的类
            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);
        }
    }

//通过反射创建出所有SpringApplicationRunListener类型的类
private <T> List<T> createSpringFactoriesInstances(Class<T> type,
            Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args,
            Set<String> names) {
        List<T> instances = new ArrayList<T>(names.size());
        for (String name : names) {
            try {
                Class<?> instanceClass = ClassUtils.forName(name, classLoader);
                Assert.isAssignable(type, instanceClass);
                Constructor<?> constructor = instanceClass
                        .getDeclaredConstructor(parameterTypes);
                T instance = (T) BeanUtils.instantiateClass(constructor, args);
                instances.add(instance);
            }
            catch (Throwable ex) {
                throw new IllegalArgumentException(
                        "Cannot instantiate " + type + " : " + name, ex);
            }
        }
        return instances;
    }

(4).启动监听器

@Override
    @SuppressWarnings("deprecation")
    public void starting() {
//创建应用启动事件,然后设置它们
        this.initialMulticaster
                .multicastEvent(new ApplicationStartedEvent(this.application, this.args));
    }


    @Override
    public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {
        ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
        for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {//通过事件和类型获取所有的应用监听器,为所有的监听器注册事件
            Executor executor = getTaskExecutor();
            if (executor != null) {
                executor.execute(new Runnable() {
                    @Override
                    public void run() {
                        invokeListener(listener, event);
                    }
                });
            }
            else {
                invokeListener(listener, event);
            }
        }
    }

(5).获取配置环境

private ConfigurableEnvironment prepareEnvironment(
            SpringApplicationRunListeners listeners,
            ApplicationArguments applicationArguments) {
        // Create and configure the environment
        ConfigurableEnvironment environment = getOrCreateEnvironment();//获取或者创建环境对象
        configureEnvironment(environment, applicationArguments.getSourceArgs());//这里是对启动时传入的参数做处理,以及激活的配置文件和多个配置属性源数据加入
        listeners.environmentPrepared(environment);//为所有的监听器准备环境变量,同时也包装成事件进行注册
        if (!this.webEnvironment) {
            environment = new EnvironmentConverter(getClassLoader())
                    .convertToStandardEnvironmentIfNecessary(environment);//将环境变为web环境
        }
        return environment;
    }

(6).banner打印,这里的功能就是每次启动boot应用时前面会打印的那个图案

            "  .   ____          _            __ _ _",
            " /\\\\ / ___'_ __ _ _(_)_ __  __ _ \\ \\ \\ \\",
            "( ( )\\___ | '_ | '_| | '_ \\/ _` | \\ \\ \\ \\",
            " \\\\/  ___)| |_)| | | | | || (_| |  ) ) ) )",
            "  '  |____| .__|_| |_|_| |_\\__, | / / / /",
            " =========|_|==============|___/=/_/_/_/" 
private Banner printBanner(ConfigurableEnvironment environment) {
        if (this.bannerMode == Banner.Mode.OFF) {
            return null;
        }
        ResourceLoader resourceLoader = (this.resourceLoader != null ? this.resourceLoader
                : new DefaultResourceLoader(getClassLoader()));
        SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(
                resourceLoader, this.banner);
        if (this.bannerMode == Mode.LOG) {
            return bannerPrinter.print(environment, this.mainApplicationClass, logger);
        }
        return bannerPrinter.print(environment, this.mainApplicationClass, System.out);
    }

(7).创建web上下文或者默认上下文,这个看下代码就知道了很简单,通过反射的方式创建出上下文

/**
     * Strategy method used to create the {@link ApplicationContext}. By default this
     * method will respect any explicitly set application context or application context
     * class before falling back to a suitable default.
     * @return the application context (not yet refreshed)
     * @see #setApplicationContextClass(Class)
     */
    protected ConfigurableApplicationContext createApplicationContext() {
        Class<?> contextClass = this.applicationContextClass;
        if (contextClass == null) {
            try {
                contextClass = Class.forName(this.webEnvironment
                        ? DEFAULT_WEB_CONTEXT_CLASS : DEFAULT_CONTEXT_CLASS);
            }
            catch (ClassNotFoundException ex) {
                throw new IllegalStateException(
                        "Unable create a default ApplicationContext, "
                                + "please specify an ApplicationContextClass",
                        ex);
            }
        }
        return (ConfigurableApplicationContext) BeanUtils.instantiate(contextClass);
    }

(8).利用上下文创建分析类,将上一步创建出的上下文作为参数直接创建出该类,用于分析故障并提供可以显示给用户的诊断信息

    analyzers = new FailureAnalyzers(context);

(9).预备上下文环境,将上面创建出来的对象都设置到创建出的上下文应用中

private void prepareContext(ConfigurableApplicationContext context,
            ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
            ApplicationArguments applicationArguments, Banner printedBanner) {
        context.setEnvironment(environment);//为上下问设置外部环境
        postProcessApplicationContext(context);//进入这个方法里面的
        applyInitializers(context);//初始化给定的应用程序上下文
        listeners.contextPrepared(context);//在上下文创建和准备之后调用,但是在资源加载之前使用
        if (this.logStartupInfo) {
            logStartupInfo(context.getParent() == null);
            logStartupProfileInfo(context);
        }

        // Add boot specific singleton beans
        context.getBeanFactory().registerSingleton("springApplicationArguments",
                applicationArguments);//看注释就知道是注册boot特别的bean
        if (printedBanner != null) {
            context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);//如果有banner就需要注册springBootBanner bean
        }

        // Load the sources
        Set<Object> sources = getSources();
        Assert.notEmpty(sources, "Sources must not be empty");
        load(context, sources.toArray(new Object[sources.size()]));//将资源文件中的bean加载到上下文中
        listeners.contextLoaded(context);//主要就是注册事件,供之前的listener监听到
    }

protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
        if (this.beanNameGenerator != null) {
            context.getBeanFactory().registerSingleton(
                    AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,
                    this.beanNameGenerator);
      ..........
    }
@Override
    public void registerSingleton(String beanName, Object singletonObject) throws IllegalStateException {
        super.registerSingleton(beanName, singletonObject);
                //这里主要就是对循环依赖做处理,
        if (hasBeanCreationStarted()) {
            // Cannot modify startup-time collection elements anymore (for stable iteration)
            synchronized (this.beanDefinitionMap) {
                if (!this.beanDefinitionMap.containsKey(beanName)) {
                    Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames.size() + 1);
                    updatedSingletons.addAll(this.manualSingletonNames);
                    updatedSingletons.add(beanName);
                    this.manualSingletonNames = updatedSingletons;//这里就是先将集合中的bean拿出来然后放到新集合,再将新的bean设置进去,然后再将集合赋值给原来的
                }
            }
        }
        else {
            // Still in startup registration phase
            if (!this.beanDefinitionMap.containsKey(beanName)) {  
                this.manualSingletonNames.add(beanName);//添加到手动注册单例bean的集合
            }
        }

        clearByTypeCache();//清空以类型为间的集合
    }

/**
     * Load beans into the application context.
     * @param context the context to load beans into
     * @param sources the sources to load
     */
    protected void load(ApplicationContext context, Object[] sources) {
        if (logger.isDebugEnabled()) {
            logger.debug(
                    "Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
        }
        BeanDefinitionLoader loader = createBeanDefinitionLoader(
                getBeanDefinitionRegistry(context), sources);
        if (this.beanNameGenerator != null) {
            loader.setBeanNameGenerator(this.beanNameGenerator);
        }
        if (this.resourceLoader != null) {
            loader.setResourceLoader(this.resourceLoader);
        }
        if (this.environment != null) {
            loader.setEnvironment(this.environment);
        }
        loader.load();//加载source
    }

(10).刷新上下文

private void refreshContext(ConfigurableApplicationContext context) {
        refresh(context);
        if (this.registerShutdownHook) {
            try {
                context.registerShutdownHook();//注册关闭虚拟机的钩子方法,可以多次调用此方法。每个上下文实例仅注册一个关闭钩子
            }
    .....
}

//这个是核心方法
@Override
    public void refresh() throws BeansException, IllegalStateException {
              //刷新和关闭时候的监控对象
        synchronized (this.startupShutdownMonitor) {
            // Prepare this context for refreshing. 准备此上下文以进行刷新
            prepareRefresh();

            // Tell the subclass to refresh the internal bean factory.
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // Prepare the bean factory for use in this context.
//配置一些beanFactory的信息,例如ClassLoader和后处理器,还有一些必要的bean添加到工厂,一些需要忽视依赖注入的bean配置
            prepareBeanFactory(beanFactory);

            try {
                // Allows post-processing of the bean factory in context subclasses.
                postProcessBeanFactory(beanFactory);

                // Invoke factory processors registered as beans in the context.
                invokeBeanFactoryPostProcessors(beanFactory);

                // Register bean processors that intercept bean creation.
                registerBeanPostProcessors(beanFactory);

                // Initialize message source for this context.
                initMessageSource();

                // Initialize event multicaster for this context.
                initApplicationEventMulticaster();

                // Initialize other special beans in specific context subclasses.
                onRefresh();

                // Check for listener beans and register them.
                registerListeners();

                // Instantiate all remaining (non-lazy-init) singletons.
                finishBeanFactoryInitialization(beanFactory);

                // Last step: publish corresponding event.
                finishRefresh();
            }

            catch (BeansException ex) {
                if (logger.isWarnEnabled()) {
                    logger.warn("Exception encountered during context initialization - " +
                            "cancelling refresh attempt: " + ex);
                }

                // Destroy already created singletons to avoid dangling resources.
                destroyBeans();

                // Reset 'active' flag.
                cancelRefresh(ex);

                // Propagate exception to caller.
                throw ex;
            }

            finally {
                // Reset common introspection caches in Spring's core, since we
                // might not ever need metadata for singleton beans anymore...
                resetCommonCaches();
            }
        }
    }


/**
     * Prepare this context for refreshing, setting its startup date and
     * active flag as well as performing any initialization of property sources.
     */
    protected void prepareRefresh() {
            //设置启动时间以及一些标志位
        this.startupDate = System.currentTimeMillis();
        this.closed.set(false);
        this.active.set(true);

        if (logger.isInfoEnabled()) {
            logger.info("Refreshing " + this);
        }

        // Initialize any placeholder property sources in the context environment,初始化配置文件中的占位符,替换实际的值
        initPropertySources();

        // Validate that all properties marked as required are resolvable
        // see 验证一些必须的属性在ConfigurablePropertyResolver#setRequiredProperties 设置的
        getEnvironment().validateRequiredProperties();

        // Allow for the collection of early ApplicationEvents,
        // to be published once the multicaster is available...
              //用于收集应用的相关事件
        this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();
    }

/**
     * Tell the subclass to refresh the internal bean factory.
     * @return the fresh BeanFactory instance
     * @see #refreshBeanFactory()
     * @see #getBeanFactory()
     */
    protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
        refreshBeanFactory();//前置操作对beanFactory做初始化,设置beanNameGenerate等
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();//获取到上一步初始化后的beanFactory
        if (logger.isDebugEnabled()) {
            logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
        }
        return beanFactory;
    }

相关文章

网友评论

      本文标题:spring boot源码解析

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