springboot核心源码 -启动类的run方法

1. 启动类的run方法

@SpringBootApplication
public class ZscApplication {

    public static void main(String[] args) {
        SpringApplication.run(ZscApplication.class, args);
    }
}
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
    return run(new Class[]{primarySource}, args);
}
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
    return (new SpringApplication(primarySources)).run(args);
}

到这里可以看出,这里有两个维度,第一个是初始化SpringApplication实例化,第二个是执行run方法。

1.1. SpringApplication实例化

public SpringApplication(Class<?>... primarySources) {
    this((ResourceLoader)null, primarySources);
}
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    //传入的sources为null
    this.sources = new LinkedHashSet();
    this.bannerMode = Mode.CONSOLE;
    this.logStartupInfo = true;
    this.addCommandLineProperties = true;
    this.addConversionService = true;
    this.headless = true;
    this.registerShutdownHook = true;
    this.additionalProfiles = Collections.emptySet();
    this.isCustomEnvironment = false;
    this.lazyInitialization = false;
    this.applicationContextFactory = ApplicationContextFactory.DEFAULT;
    this.applicationStartup = ApplicationStartup.DEFAULT;
    this.resourceLoader = resourceLoader;
    //这是一个断言,就是判断当前传入进来的配置类有没有,如果没有的话,就会进行一个提示
    //为什么要拿到这个启动配置类呢,因为要用到这个类的注解,实现自动装配
    Assert.notNull(primarySources, "PrimarySources must not be null");
    //保存配置类
    this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
    this.webApplicationType = WebApplicationType.deduceFromClasspath();
    this.bootstrapRegistryInitializers = new ArrayList(this.getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
    //getSpringFactoriesInstances ,以spi的形式获取到接口的实例
    //ApplicationContextInitializer是由context包提供的,这个包也是一个初始化器,
    //在spi的规范条件下,有没有准备接口,在这里,已经准备了ApplicationContextInitializer接口
    //有了接口后,就可以根据spi获取对应的接口实现类,可以在spring #refresh刷新之前做一些事情,那么就可以对初始化器进行实现,也就相当于对spring进行了扩展。
    this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
    //这个是事件监听器,
    this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
    this.mainApplicationClass = this.deduceMainApplicationClass();
}

spi:根据接口获取实现类实例类

java spi : ServiceLoader

dubbo spi : ExtensionLoader

spring spi :springFactotrieLoader

package org.springframework.context;

@FunctionalInterface
public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext> {
    void initialize(C applicationContext);
}
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
    return this.getSpringFactoriesInstances(type, new Class[0]);
}
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
    ClassLoader classLoader = this.getClassLoader();
    Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
    List<T> instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
    AnnotationAwareOrderComparator.sort(instances);
    return instances;
}
//从spring.factories文件中尽显查找,以ApplicationContextInitializer的全路径为key,找value
private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args, Set<String> names) {
    List<T> instances = new ArrayList(names.size());
    Iterator var7 = names.iterator();

    while(var7.hasNext()) {
        String name = (String)var7.next();

        try {
            Class<?> instanceClass = ClassUtils.forName(name, classLoader);
            Assert.isAssignable(type, instanceClass);
            Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
            T instance = BeanUtils.instantiateClass(constructor, args);
            instances.add(instance);
        } catch (Throwable var12) {
            Throwable ex = var12;
            throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, ex);
        }
    }

    return instances;
}
public void setInitializers(Collection<? extends ApplicationContextInitializer<?>> initializers) {
    this.initializers = new ArrayList(initializers);
}
1.1.1. 自定义初始化器

//将spi的实例方法进行回调

那这个spi的实例方法回调的应用场景是什么呢:
如果我们想要在spring #refresh刷新之前做一些事情,那么就可以对初始化器进行实现,也就相当于对spring进行了扩展。

通过这个我们可以自定义自己的初始化器

1.1.2. 监听器

这是一种典型的观察者设计模式。

如果想查看监听器的更多事件详情,可以到ApplicationEvent类中查看。

事件有非常多的类型,这些事件都是ApplicationEvent的子类,可以自定义一个监听器,监听你感兴趣的事件,那如何缩小这个范围呢,就是这个范围是ApplicationEvent的子类型,继承这个子类就可以。

/**
 * 这个监听器对ApplicationStartedEvent感兴趣,
 * 也就是如果Spring源码启动的时候,有广播器发布了ApplicationStartedEvent事件,那么就会回调下面的方法
 */

public class Listener implements ApplicationListener<ApplicationStartedEvent> {
    @Override
    public void onApplicationEvent(ApplicationStartedEvent event) {
        System.out.println("项目启动-------------");
    }
}
org.springframework.context.ApplicationListener=\
  com.zsc.zsc.demo.v3.Listener

1.2. Spring中的扩展机制

(1)自定义自己的初始化器:固定

(2)事件监听机制:可以在任意只要发布事件的地方进行监听,扩展更加灵活,贯穿整个spring启动的生命周期。

我们也可以自定义广播器、事件和监听器

(3)Run

(4)自定义BeanFactoryPostcessor用于修改beanfactory的属性值

1.3. SpringAoolication的run方法

public ConfigurableApplicationContext run(String... args) {
    long startTime = System.nanoTime();
    DefaultBootstrapContext bootstrapContext = this.createBootstrapContext();
    ConfigurableApplicationContext context = null;
    this.configureHeadlessProperty();
    //获取到一些监听器
    SpringApplicationRunListeners listeners = this.getRunListeners(args);
    //进行监听器的一个回调
    listeners.starting(bootstrapContext, this.mainApplicationClass);

    Throwable ex;
    try {
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
        ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);
        this.configureIgnoreBeanInfo(environment);
        //打印banner操作,可以创建一个banner.txt文件,写启动时打印的东西
        Banner printedBanner = this.printBanner(environment);
        //创建context,根据你引入的jar包创建对应的context
        context = this.createApplicationContext();
        context.setApplicationStartup(this.applicationStartup);
        //回调初始化器
        this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
        //刷新
        this.refreshContext(context);
        this.afterRefresh(context, applicationArguments);
        Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
        if (this.logStartupInfo) {
            (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), timeTakenToStartup);
        }

        listeners.started(context, timeTakenToStartup);
        //在最后的最后,可以在这里实现,可以实现资源的释放或清理
        this.callRunners(context, applicationArguments);
    } catch (Throwable var12) {
        ex = var12;
        this.handleRunFailure(context, ex, listeners);
        throw new IllegalStateException(ex);
    }

    try {
        Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
        listeners.ready(context, timeTakenToReady);
        return context;
    } catch (Throwable var11) {
        ex = var11;
        this.handleRunFailure(context, ex, (SpringApplicationRunListeners)null);
        throw new IllegalStateException(ex);
    }
}
@Component
public class ZscApplicationRunner implements ApplicationRunner {
    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println("我是最后执行的...  ZscApplicationRunner");
    }
}

public void refresh() throws BeansException, IllegalStateException {
        synchronized(this.startupShutdownMonitor) {
            StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
            //下面这三个是准备系统bean对象
            this.prepareRefresh();
            ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
            this.prepareBeanFactory(beanFactory);

            try {
                this.postProcessBeanFactory(beanFactory);
                StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
                this.invokeBeanFactoryPostProcessors(beanFactory);
                this.registerBeanPostProcessors(beanFactory);
                beanPostProcess.end();
                this.initMessageSource();
                this.initApplicationEventMulticaster();
                this.onRefresh();
                this.registerListeners();
                this.finishBeanFactoryInitialization(beanFactory);
                this.finishRefresh();
            } catch (BeansException var10) {
                BeansException ex = var10;
                if (this.logger.isWarnEnabled()) {
                    this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + ex);
                }

                this.destroyBeans();
                this.cancelRefresh(ex);
                throw ex;
            } finally {
                this.resetCommonCaches();
                contextRefresh.end();
            }

        }
    }

在上下文刷新过程中,可以修改bean的原属性:
 

org.springframework.context.ApplicationListener=\
  com.zsc.zsc.demo.v3.Listener

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值