博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
SpringBoot入门(三)——入口类解析
阅读量:6989 次
发布时间:2019-06-27

本文共 5035 字,大约阅读时间需要 16 分钟。

本文来自

上一篇介绍了起步依赖,这篇我们先来看下SpringBoot项目是如何启动的。

入口类

再次观察工程的Maven配置文件,可以看到工程的默认打包方式是jar格式的。

jar

SpringBoot默认的打包方式为jar,并且内嵌web容器。因此我们可以用运行jar包的方式启动一个web程序:

java -jar xxx.jar

linux服务器上可以用下面命令让服务常驻:

nohup java -jar xxx.jar &

我们知道jar包方式运行需要main方法,SpringBoot已为我们自动生成,这个类便是项目启动入口。

我的项目名是blog-demo,对应生成的main方法在BlogDemoApplication.java,其代码如下:

@SpringBootApplicationpublic class BlogDemoApplication {    public static void main(String[] args) {        SpringApplication.run(BlogDemoApplication.class, args);    }}

main方法中执行SpringApplication的静态方法run,并将当前类和启动参数传入。

静态方法中实例化一个SpringApplication,并调用实例的run方法:

public static ConfigurableApplicationContext run(Class
[] primarySources,            String[] args) {        return new SpringApplication(primarySources).run(args);    }

先来看下调用的SpringApplication的构造方法:

public SpringApplication(ResourceLoader resourceLoader, Class
... primarySources) {    this.resourceLoader = resourceLoader;    Assert.notNull(primarySources, "PrimarySources must not be null");    // 这里的primarySources就是我们传入的入口类    this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));    // 推断应用类型    this.webApplicationType = deduceWebApplicationType();    // 设置初始化器    setInitializers((Collection) getSpringFactoriesInstances(        ApplicationContextInitializer.class));    // 设置监听器    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));    // 很有意思的方法,通过异常栈获取应用入口类    this.mainApplicationClass = deduceMainApplicationClass();}

注意我们传入的启动类被保存到了primarySources变量中,将作为后续context加载beans时的资源,其他细节不再展开。

接着看实例的run方法:

/** * 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) {    // 计时工具    StopWatch stopWatch = new StopWatch();    stopWatch.start();    // 应用上下文    ConfigurableApplicationContext context = null;    Collection
 exceptionReporters = new ArrayList<>();    configureHeadlessProperty();    // 设置系统参数-无图形化界面    // 获取监听器    SpringApplicationRunListeners listeners = getRunListeners(args);    listeners.starting();    try {        ApplicationArguments applicationArguments = new DefaultApplicationArguments(            args);        ConfigurableEnvironment environment = prepareEnvironment(listeners,                                                                 applicationArguments);        configureIgnoreBeanInfo(environment);        Banner printedBanner = printBanner(environment);        // 创建上下文        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, listeners, exceptionReporters, ex);        throw new IllegalStateException(ex);    }    listeners.running(context);    return context;}

通过方法注释也可以看出来该run方法引发了一系列复杂的内部调用和加载过程,从而创建了一个SpringContext。

在prepareContext方法中会解析我们传入的入口类,解析其上的注解。下面来看下入口类上的注解。

@SpringBootApplication

入口类上的注解@SpringBootApplication是SpringBoot自动配置的关键。其定义如下:

@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 {    ...}

说明它是@ComponentScan、@SpringBootConfiguration和@EnableAutoConfiguration三个注解的组合。

@ComponentScan

@ComponentScan是Spring框架原有的注解,在spring-context组件下,用来开启自动扫描Bean并解析注解注入。

可以用basePackages指定扫描的包,缺省情况下默认扫描被注解类所在的包。SpringBoot项目中一般会将入口类放在顶层目录,这样默认就会扫描整个项目。

@SpringBootConfiguration

@SpringBootConfiguration是SpringBoot新增的注解,在spring-boot组件下,定义如下:

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

相当于注解@Configuration,配备了该注解的类就能够以JavaConfig的方式完成一些配置,可以不再使用XML配置。

所以在入口类内也可以以JavaConfig的方式定义Bean。

@EnableAutoConfiguration

@EnableAutoConfiguration是SpringBoot新增的注解,在spring-boot-autoconfigurate组件下,它是SpringBoot开启自动配置的关键。放到下一节再讲。

小结

这一节简单解析了SpringBoot的入口类,一个由SpringBoot自动生成的java类,虽然只有短短几行代码,却引发了Spring上下文的创建的一系列事件。

首先SpringBoot将入口类传入作为资源的起点,当解析到入口类的时候发现其上的注解又开启了自动配置和包扫描,这样我们自定义的Bean就会被加载进去完成创建和依赖。

相关阅读:

 

网易云新用户大礼包:

 

本文来自网易实践者社区,经作者金港生授权发布。

转载地址:http://oawvl.baihongyu.com/

你可能感兴趣的文章
获取函数所在模块的方法
查看>>
Linux信号处理
查看>>
VS预定义宏
查看>>
QtTableView
查看>>
*****运维人员如何最大限度避免误删除文件?
查看>>
Android应用开发基础--Adapter
查看>>
条件随机场
查看>>
别人要访问我的电脑上部署的tomcat,必须关闭防火墙吗?
查看>>
位运算的基本操作【转载】
查看>>
关系型数据库设计——E-R图
查看>>
作业六
查看>>
c++ 二叉树打印节点路径
查看>>
BOS中常用方法和类
查看>>
append的问题
查看>>
git &github 快速入门
查看>>
JS中的几种函数
查看>>
ios--编码规范
查看>>
JsCV Core v0.2发布 & Javascript图像处理系列目录
查看>>
bzoj 2784 [JLOI2012]时间流逝——树上高斯消元
查看>>
SQL优化三板斧:精简之道、驱动为王、集合为本
查看>>