Spring Boot

与和SpringCloud

SpringCloud依赖于SpringBoot组件,使用SpringMVC编写HTTP接口,同时SpringCloud是一套完整的微服务解决框架

环境搭建

<parent> <!--继承父工程 -->    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-parent</artifactId>    <version>2.1.8.RELEASE</version></parent><dependencies>    <!--引入依赖-->    <dependency>        <groupId>org.springframework.boot</groupId>        <artifactId>spring-boot-starter-web</artifactId>    </dependency></dependencies>
@SpringBootApplicationpublic class Application{    public static void main(String[] args) {        SpringApplication.run(Application.class);    }}

热部署

<dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-devtools</artifactId>    <optional>true</optional></dependency>

IDEA需要开启自动编译

配置

YML语法

# 普通数据配置name: hello# 对象配置person:  name: kb  age: 3# 配置数组、集合(字符串)city:  - beijing  - tianjing  - chongqing# 配置数组、集合(对象)student:  - name: tom    age: 3  - name: ll    age: 2

属性注入

@Value("${name}")private String name;
@RestController@ConfigurationProperties(prefix = "person")public class Controller {    private String name;    private Integer age;    @RequestMapping("/hi")    public String hello(){        return name+age;    }    // 省略setter}

全局异常捕获

@ControllerAdvicepublic class ErrorHandler {    @ResponseBody    @ExceptionHandler(Throwable.class)    public String error(Exception e){        return e.getMessage();    }}

异步调用

多环境配置

spring.profiles.active=dev

添加开发环境配置文件application-dev.properties

事务管理

<dependency>    <groupId>javax.transaction</groupId>    <artifactId>javax.transaction-api</artifactId>    <version>1.3</version></dependency>

多数据源

配置多个DataSource,一个DataSource配置一个事务管理器,声明事务时指定事务管理器, 不同的ORM框架有不同的指定数据源的方式

jta-atomikos

通过把多个DataSource交给jta事务管理器管理,使用jta事务管理器来解决分布式事务问题

打包

jar

<plugin>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-maven-plugin</artifactId></plugin>

war

添加打包插件

<packaging>war</packaging>

性能

组件自动扫描带来的问题

使用 @SpringBootApplication 注解后,会触发自动配置( auto-configuration )和 组件扫描 ( component scanning )

JVM参数调整

将tomcat改为undertow

<dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-web</artifactId>    <exclusions>        <exclusion>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-tomcat</artifactId>        </exclusion>    </exclusions></dependency><dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-undertow</artifactId></dependency>

监控中心

Actuator是spring boot的一个附加功能,可在应用程序生产环境时监视和管理应用程序

<dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-actuator</artifactId></dependency>
# 暴露出所有监控接口management:  endpoints:    web:      exposure:        include: "*"
路径作用
/actuator/beans显示应用程序中所有Spring bean的完整列表。
/actuator/configprops显示所有配置信息。
/actuator/env陈列所有的环境变量。
/actuator/mappings显示所有@RequestMapping的url整理列表。
/actuator/health显示应用程序运行状况信息 up表示成功 down失败
/actuator/info返回配置中前缀为info的配置项

集成其他框架

集成freemarker

<dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-freemarker</artifactId></dependency>
spring.freemarker.allow-request-override=falsespring.freemarker.cache=truespring.freemarker.check-template-location=truespring.freemarker.charset=UTF-8spring.freemarker.content-type=text/htmlspring.freemarker.expose-request-attributes=falsespring.freemarker.expose-session-attributes=falsespring.freemarker.expose-spring-macro-helpers=falsespring.freemarker.suffix=.ftlspring.freemarker.template-loader-path=classpath:/templates/
@Controllerpublic class HelloController {    @RequestMapping("hello")    public String index(ModelMap map){        map.put("hello","java");        return "index";    }}
<body>    ${hello}</body>

集成Mybatis

<dependency>    <groupId>org.mybatis.spring.boot</groupId>    <artifactId>mybatis-spring-boot-starter</artifactId>    <version>2.1.0</version></dependency>
# 数据库连接信息spring.datasource.username=rootspring.datasource.password=123spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driverspring.datasource.url=jdbc:mysql:///ssm# mybatis相关配置mybatis.mapper-locations=mappers/*.xmlmybatis.configuration.map-underscore-to-camel-case=true
@MapperScan(basePackages = "wang.ismy.springmybatis.mapper")public class SpringMybatisApplication {    public static void main(String[] args) {        SpringApplication.run(SpringMybatisApplication.class, args);    }}

整合PageHelper

<dependency>    <groupId>com.github.pagehelper</groupId>    <artifactId>pagehelper-spring-boot-starter</artifactId>    <version>1.2.13</version></dependency>
pagehelper.helperDialect=mysqlpagehelper.reasonable=truepagehelper.supportMethodsArguments=truepagehelper.params=count=countSqlpagehelper.page-size-zero=true

集成Junit

<dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-test</artifactId>    <scope>test</scope></dependency>
@SpringBootTest@RunWith(SpringRunner.class)public class ControllerTest{    @Autowired    UserMapper mapper;    @Test    public void test(){        assertNotNull(mapper);    }}

集成Spring data jpa

<dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-data-jpa</artifactId></dependency>
# 数据库连接信息spring.datasource.username=rootspring.datasource.password=123spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driverspring.datasource.url=jdbc:mysql:///ssm# spring data jpa相关配置spring.jpa.database=mysqlspring.jpa.show-sql=truespring.jpa.generate-ddl=truespring.jpa.hibernate.ddl-auto=update

使用通用Mapper

<dependency>    <groupId>tk.mybatis</groupId>    <artifactId>mapper-spring-boot-starter</artifactId>    <version>2.1.5</version></dependency>
public interface UserMapper extends BaseMapper<User> { }

集成Redis

<dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-data-redis</artifactId></dependency>
# redis相关配置spring.redis.host=127.0.0.1spring.redis.port=6379
@RunWith(SpringRunner.class)@SpringBootTestpublic class RedisTest {    @Autowired    RedisTemplate<String,String> redisTemplate;    @Test    public void test(){        String name = redisTemplate.boundValueOps("name").get();        Assert.assertEquals("my",name);    }}

集成swagger

<dependency>    <groupId>com.spring4all</groupId>    <artifactId>swagger-spring-boot-starter</artifactId>    <version>1.9.1.RELEASE</version></dependency>
swagger.base-package=wang.ismy.consume
@EnableSwagger2Doc

zuul整合各个微服务文档

<dependency>    <groupId>com.spring4all</groupId>    <artifactId>swagger-spring-boot-starter</artifactId>    <version>1.9.1.RELEASE</version></dependency>
@Component@Primary@EnableSwagger2Docclass DocumentationConfig implements SwaggerResourcesProvider {    @Override    public List<SwaggerResource> get() {        List resources = new ArrayList<>();        resources.add(swaggerResource("consumer", "/api-consumer/v2/api-docs", "2.0"));        return resources;    }    private SwaggerResource swaggerResource(String name, String location, String version) {        SwaggerResource swaggerResource = new SwaggerResource();        swaggerResource.setName(name);        swaggerResource.setLocation(location);        swaggerResource.setSwaggerVersion(version);        return swaggerResource;    }}

高级

@ConditionOnXX

条件化注入bean

切换内置服务器

@EnableXX原理

此类注解使用了@Import修饰,通过@Import注解来导入一些配置类

@Import使用:

  1. 导入Bean
  2. 导入配置类
  3. ImportSelector的实现类
    • 自定义需要导入的类逻辑(返回全限定类名)
  4. ImportBeanDefinitionRegistrar 实现类
    • 自定义(编程式向IOC容器注册)

@EnableAutoConfiguration原理

  1. @Import AutoConfigurationImportSelector 加载配置类
  2. AutoConfigurationImportSelector读取META-INF/spring.factories 加载配置类

自定义starter

  1. 定义autoconfigure模块
  2. 定义starter模块依赖autoconfigure模块
  3. 在autoconfigure模块定义META-INF/spring.factories

事件监听

为了在应用启动成功之后执行某些操作,某些情况下使用InitializingBean接口并不能满足请求,其回调方法afterPropertiesSet在Bean属性被设置后被调用,此时系统的部分组件可能仍处于未初始化状态。

为解决这个问题,可使用Spring的事件监听机制,监听SpringBoot的AvailabilityChangeEvent<ReadinessState> 当状态为ReadinessState.ACCEPTING_TRAFFIC,表示应用可以开始准备接收请求了,此时再启动所需要的操作

@EventListenerpublic void onSystemReady(AvailabilityChangeEvent<ReadinessState> event) {    if (event.getState().equals(ReadinessState.ACCEPTING_TRAFFIC)) {        // do something    }}