SpringBoot学习
1.常见注解
1.1 @ComponentScan
@ComponentScan对应XML配置形式中的<context:component-scan>元素,用于配合一些元信息Java Annotation,比如@Component和@Repository等,将标注了这些元信息Annotation的bean定义类批量采集到Spring的IoC容器中。
我们可以通过basePackages等属性来细粒度地定制@ComponentScan自动扫描的范围,如果不指定,则默认Spring框架实现会从声明@ComponentScan所在类的package进行扫描。
1.2 @PropertySource
@PropertySource用于从某些地方加载*.properties文件内容,并将其中的属性加载到IOC容器中,便于填充一些bean定义属性的占位符(placeholder)。使用方式如下:
@Configuration @PropertySource("classpath:1.properties") @PropertySource("classpath:2.properties") public class XConfiguration { }
1.3 @Import和@ImportResource
用于将多个分开的容器配置合到一个配置中,如下:
@Configuration @Import(PageHelperConfig.class) public class XConfiguration { }
@Import只负责引入JavaConfig形式定义的Ioc容器配置,如果有一些遗留的配置或者遗留系统需要以XML形式来配置(比如Dubbo框架),我们依然可以通过ImportResource将它们一起合并到当前JavaConfig配置的容器中,如下
@Configuration @Import(PageHelperConfig.class) @ImportResource("...") public class XConfiguration { }
2.SpringBoot工作机制
2.1 @SpringBootApplication
@SpringBootApplications是一个复合注解
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @Configuration @EnableAutoConfiguration @ComponentScan public @interface SpringBootApplication { }
虽然它的定义使用了多个注解进行元信息标注,但实际上对于SpringBoot应用来说,重要的三个注解是:
- @Configuration
- @EnableAutoConfiguration
- @ComponentScan
2.1.1 @Configuration
@Configuration就是JavaConfig形式的Spring Ioc容器的配置类所使用的注解。启动类标注了@Configuration之后,本身其实也是一个IOC容器的配置类。
2.1.2 @EnableAutoConfiguration
@EnableAutoConfiguration借助@Import的帮助,将所有复合自动配置条件的bean定义加载到Ioc容器
2.1.3 @ComponentScan
@ComponentScan的功能其实就是自动扫描并加载符合条件的组件或bean定义,最终将这些bean定义加载到容器中
2.2 SpringApplication类
2.2.1 SpringApplication执行流程
当调用SpringApplication类的静态run方法时,这个方法里面首先创建一个SpringApplication对象实例,然后调用这个创建好的SpringApplication的实例run方法。当SpringApplication类实例化的时候,它会提前做如下几件事情:
- 根据classpath里面是否存在某个特征类(org.springframework.web.context.ConfigurableWebApplicationContext)来决定是否应该创建一个为web应用使用的ApplicationContext类型,还是应该创建一个标准Standalone应用使用的ApplicationContext类型
- 使用SpringFactoriesLoader在应用的classpath中查找并加载所有可用的ApplicationContextInitializer
- 使用SpringFactoriesLoader在应用的classpath中查找并加载所有可用的ApplicationListener
- 推断并设置main方法的定义类
(2)springApplication实例初始化完成并完成设置后,就开始执行run方法的逻辑,首先便利执行所有通过SpringFactoriesLoader可以查找到并加载的SpringApplicationListener,调用它们的start()方法,告诉这些SpringApplicationListener说SpringBoot应用即将启动
(3)创建并配置当前SpringBoot应用将要使用的Environment(包括配置要使用的PropertySource和Profile)
(4)遍历调用所有SpringApplicationListener的environmentPrepared()的方法,告诉它们SpringBoot应用使用的Environment已经准备好
(5)若SpringApplication的showBanner属性被设置为true,则打印banner
(6)根据用户是否明确了applicationContextClass类型及初始化阶段的推断结果,决定为当前SpringBoot应用创建什么类型的ApplicationContext并创建完成,然后根据条件决定是否添加ShutdownHook,决定是否使用自定义的BeanNameGenerator,决定是否使用自定义的ResourceLoader,最重要的,将之前准备好的Environment设置给创建好的ApplicationContext使用
(7)ApplicationContext创建好之后,SpringApplication会再次借助SpringFactoriesLoader,查找并加载classpath中所有可用的ApplicationContextInitializer,然后遍历调用这些ApplicationContextInitializer的initalize方法来对已经创建好的ApplicationContext进行进一步的处理。
(8)遍历调用所有SpringApplicationRunListener的contextPrepared()方法,通知它们SpringBoot应用使用的ApplicationContext准备好了
(9)最核心的一步,将之前通过@EnableAutoConfiguration获取的所有配置以及其他形式的Ioc容器配置加载到已经准备完毕的ApplicationContext
遍历调用所有SpringApplicationRunListener的contextLoaded()方法,告知所有SpringApplicationRunListener,ApplicationContext装填完毕
(11)调用ApplicationContext的refresh()方法,完成IOC容器可用的最后一道工序
(12)查找当前ApplicationContext中是否注册有CommandLineRunner,如果有,则遍历执行它们。
(13)正常情况下,遍历执行SpringApplicationRunListener的finished()方法,启动完毕(备注:若整个过程出现异常,则依然调用所有SpringApplicationRunListener的finished()方法,不过这种情况下会将异常信息一并传入)
至此,一个完整的SpringBoot应用启动完毕。简单示意图如下
2.2.2 SpringApplicationRunListener
SpringApplicationRunListener是一个只有SpringBoot应用的main方法执行过程中接收不同执行时点事件通知的监听者。
public interface SpringApplicationRunListener { void starting(); void environmentPrepared(ConfigurableEnvironment var1); void contextPrepared(ConfigurableApplicationContext var1); void contextLoaded(ConfigurableApplicationContext var1); void finished(ConfigurableApplicationContext var1, Throwable var2); }
SpringBoot默认实现了一个org.springframework.boot.context.event.EventPublishingRunListener,用于在SpringBoot启动的不同点发布不同的应用事件类型(ApplicationEvent),如果有哪些ApplicationListener对这些应用事件感兴趣,则可以接收并处理。
2.2.3 ApplicationListener
ApplicationListener属于Spring框架对Java中实现的监听者模式的一种框架实现
2.2.4 ApplicationContextInitializer
ApplicationContextInitializer类的主要目的就是在ConfigurableApplicationContext类型或子类型的ApplicationContext做refresh之前,允许我们对ConfigurableApplicationContext的实例做进一步的设置或处理。
2.2.5 CommandLineRunner
CommandLineRunner属于SpringBoot应用特定的回调扩展接口。
public interface CommandLineRunner { void run(String... var1) throws Exception; }
CommandLineRunner的关注点:
- 所有的CommandLineRunner的执行时点在SpringBoot应用的ApplicationContext完全初始化工作之后(可以认为是main方法执行完成之前最后一步)
- 只要存在于当前SpringBoot应用的ApplicationContext中的任何CommandLineRunner,都会被加载执行
2.3.自动装配
前面说到,@EnableAutoConfiguration可以借助SpringFactoriesLoader这个特性将标注了@Configuration的JavaConfig类汇总并加载到最终的ApplicationContext。
实际上,基于@EnableAutoConfiguration的自动配置功能拥有更加强大的调控能力,通过配合比如基于条件的配置能力或者调整加载顺序,我们可以对自动配置进行更加细粒度的调整和控制
2.3.1 基于条件的自动配置
基于条件的自动装配来源于Spring框架的“基于条件的配置”这一特性。在Spring框架中,我们可以使用@Conditional这个注解配合@Configuration或者@Bean等注解来干预一个配置或者bean定义是否能生效。
2.3.2 调整自动配置的顺序
在实现自动装配的过程中,除了可以提供基于条件的配置,我们可以对当前要提供的配置或组件的加载顺序进行相应调整,从而让这些配置或组件之间的依赖分析和组装可以顺利完成。
3.spring-boot-strater
SpringBoot提供了很多针对日常企业应用研发各种场景的spring-boot-starter自动配置依赖模块,这些模块开箱即用,使得开发各种场景的Spring应用更加快速和高效。
所有的spring-boot-strater都有约定俗成的默认配置。但允许我们调整这些配置以改变默认的配置行为,即"约定优先于配置"。
SpringBoot应用的配置约定,简单来讲,将对SpringBoot的行为可以进行干预的配置方式划分为几类:
- 命令行参数
- 系统环境变量
- 位于文件系统中的配置文件
- 位于classpath中的配置文件
- 固化到代码中的配置项
以上几种方式按照优先级从高到低排列,高优先级方式提供的配置项可以覆盖或者优先生效。
SpringBoot应用默认的配置文件名叫application.properties,可以直接放在当前项目的根目录下或名为config的子目录下。
3.1 应用日志和spring-boot-stater-logging
假如maven依赖中添加了spring-boot-stater-logging:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId> </dependency>
那么SpringBoot应用将自动使用logback作为应用日志框架。SpringBoot为我们提供了很多默认的日志框架,所以,只要将spring-boot-stater-logging作为依赖加入到当前应用的classpath,则开箱即用,不需要做任何多余配置。
假设我们要对默认SpringBoot提供的应用日志设定做调整,则可以通过以下几种方式进行配置调整:
- 遵循logback约定,在classpath中使用自己定制的logback.xml配置文件
- 在文件系统总任何一个位置提供logback.xml配置文件,然后通过logging.config配置项指向这个配置文件来启用它
如果更习惯使用log4j和log4j2,那么也可以采用类似的方式将它们对应的spring-boot-starter依赖模块加到Maven依赖中即可。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-log4j</artifactId> </dependency>
或者
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-log4j2</artifactId> </dependency>
(注意:一定不要将完成同一目的spring-boot-stater都加到依赖中,只引入一个即可)
3.2 快速web应用开发与spring-boot-starter-web
为了帮我们简化快速搭建并开发一个web项目,SpringBoot为我们提供了spring-boot-starter-web自动配置模块。
只要将spring-boot-starter-web加入项目的maven依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
我们就得到了一个直接可执行的web应用,当前项目下运行mvn spring-boot:run 就可以直接启动一个使用了嵌入式tomcat服务请求的web应用。
spring-boot-starter-web默认使用嵌入式tomcat(spring-boot-starter-tomcat自动配置模块)作为web容器对外提供http服务,默认将使用8080端口对外监听和提供服务。
3.3 数据访问与spring-boot-starter-jdbc
SpringBoot为我们自动配置相应的数据访问设施。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency>
默认情况下,当我们没有配置任何DataSource,SpringBoot会为我们自动配置一个DataSource,这种自动配置的方式一般适用于测试,开发还是自己配置一个DataSource的实例比较好。
如果我们的工程只依赖一个数据库,那么,使用DataSource自动配置模块提供的参数是最方便的:
spring.datasource.url=jdbc:mysql://{datasource host}:3306/{databaseName} spring.datasource.username={database username} spring.datasource.passwd={database passwd}
还会自动配置的有:JdbcTemplate DateSourceTransactionManager等,我们只要在使用的时候注入(@Autowired)就好了
此外,SpringBoot还支持的数据库有spring-boot-data-jpa spring-boot-data-mongodb。
当在一个应用中需要依赖和访问多个数据库(多个数据源)的时候,需要排除掉SpringBoot默认提供的DataSource相关的自动配置,否则会报错
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class }) public class CrmDemoApplication { }
3.4 spring-boot-starter-aop
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
spring-boot-starter-aop自动配置行为由两部分组成:
位于spring-boot-autoconfigure的org.sringframework.boot.autoconfigure.aop.AopAutoConfiguration提供的@Configuration配置类和相应的配置项,即下面的2个配置项:
spring.aop.auto=true spring.aop.proxy-target-class=false
spring-boot-starter-aop模块提供了针对spring-aop aspectjrt 和aspectjweaver的依赖
3.5 应用安全与spring-boot-starter-security
spring-boot-starter-security 主要面向的是Web应用开发,配合spring-boot-starter-web,所以,对应的maven依赖如下:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>
spring-boot-starter-security 默认会提供一个基于HTTP Basic认证的安全防护策略,默认用户为user,访问密码则在当前web应用启动的时候,打印到控制台,要想定制,则在配置文件如下进行配置:
security.user.name={username} security.user.password={passwd}
除此之外,spring-boot-starter-security还会默认启动一些必要的Web安全防护,比如针对XSS CSRF等场针对Web应用的攻击,同时,也会将一些常见的静态资源路径排除在安全防护之外。
AuthenticationManager AccessDecisionManager AbstractSecurityInterceptor被称为Spring Security的基础铁三角,前2者负责制定规则, AbstractSecurityInterceptor负责执行。我们常见的Filter类就可以定制和扩展SpringSecurity的防护机制。
进一步定制spring-boot-starter-security:
上诉使用SecurityProperties暴露的配置项,即以security.*对spring-boot-starter-security进行简单的配置,还可以通过给出一个继承了WebSecurityConfigurerAdapter的JavaConfig配置类对spring-boot-starter-security的行为进行更深级别的定制,例如:
- 使用其他的AuthenticationManager实例
- 对默认的HttpSecurity定义的资源访问的规则重新定义
- 对默认提供的WebSecurity行为进行调整
一般配合@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)进行标注。
3.6 应用监控与spring-boot-starter-actuator
在生产环境中,需要实时或定期监控服务的可用性。Spring Boot的actuator(健康监控)功能提供了很多监控所需的接口,可以对应用系统进行配置查看、相关功能统计等。
SpringBoot框架提供了spring-boot-starter-actuator自动配置模块用于支持SpringBoot应用的监控。
maven依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
如果使用HTTP调用的方式,还需要这个依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
配置:
application.yml中指定监控的HTTP端口(如果不指定,则使用和Server相同的端口);指定去掉某项的检查(比如不监控health.mail):
server: port: 8082 management: port: 54001 health: mail: enabled: false
使用:
HTTP方法 路径 描述 鉴权
GET /autoconfig 查看自动配置的使用情况 true
GET /configprops 查看配置属性,包括默认配置 true
GET /beans 查看bean及其关系列表 true
GET /dump 打印线程栈 true
GET /env 查看所有环境变量 true
GET /env/{name} 查看具体变量值 true
GET /health 查看应用健康指标 false
GET /info 查看应用信息(需要自己在application.properties里头添加信息,比如info.contact.email=easonjim@163.com) false
GET /mappings 查看所有url映射 true
GET /metrics 查看应用基本指标 true
GET /metrics/{name} 查看具体指标 true
POST /shutdown 关闭应用(要真正生效,得配置文件开启endpoints.shutdown.enabled: true) true
GET /trace 查看基本追踪信息 true