Spring Boot
- 内嵌式容器简化Web项目
- 没有冗余代码生成和XML配置的要求
与和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
@Value("${name}")private String name;
- @ConfigurationProperties
@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(); }}
异步调用
- 添加`@EnableAsync`
- 在需要异步调用的方法上面添加`@Async`
多环境配置
spring.profiles.active=dev
添加开发环境配置文件application-dev.properties
事务管理
- 依赖
<dependency> <groupId>javax.transaction</groupId> <artifactId>javax.transaction-api</artifactId> <version>1.3</version></dependency>
- 添加`@Transactional`
多数据源
配置多个DataSource,一个DataSource配置一个事务管理器,声明事务时指定事务管理器, 不同的ORM框架有不同的指定数据源的方式
jta-atomikos
通过把多个DataSource交给jta事务管理器管理,使用jta事务管理器来解决分布式事务问题
打包
jar
- 添加插件
<plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId></plugin>
- 执行`mvn package`
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/
- 创建Controller
@Controllerpublic class HelloController { @RequestMapping("hello") public String index(ModelMap map){ map.put("hello","java"); return "index"; }}
- 在template目录下创建index.ftl
<body> ${hello}</body>
集成Mybatis
- 引入依赖
<dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.0</version></dependency>
- 配置数据库信息和mybatis配置
# 数据库连接信息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
- 配置mybatis包扫描路径
@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> { }
- @MapperScan注解需要使用tk.mybatis包
集成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
切换内置服务器
- 排除tomcat依赖
- 引入其他内置服务器依赖
@EnableXX原理
此类注解使用了@Import修饰,通过@Import注解来导入一些配置类
@Import使用:
- 导入Bean
- 导入配置类
- ImportSelector的实现类
- 自定义需要导入的类逻辑(返回全限定类名)
- ImportBeanDefinitionRegistrar 实现类
- 自定义(编程式向IOC容器注册)
@EnableAutoConfiguration原理
- @Import AutoConfigurationImportSelector 加载配置类
- AutoConfigurationImportSelector读取META-INF/spring.factories 加载配置类
自定义starter
- 定义autoconfigure模块
- 定义starter模块依赖autoconfigure模块
- 在autoconfigure模块定义META-INF/spring.factories
事件监听
- SpringApplicationRunListener
- CommandLineRunner 项目启动后执行(放入ioc容器即可被识别)
- ApplicationRunner 项目启动后执行(放入ioc容器即可被识别)
为了在应用启动成功之后执行某些操作,某些情况下使用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 }}