写在前面
Spring-Boot
- 简化spring开发
- 约定优于配置
- 并不是对spring的增强,而是快速开发spring项目的方式
- jar的打包方式
- 业务代码编写方式完全一样
起步依赖
spring-boot-starter-parent控制依赖版本
spring-boot-starter-web继承依赖了了Spring-web和mvc
引导类
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
配置文件
yaml
- 文件名只能为
application
- .yml/.yaml,类似.properties 设置默认值
- 实现配置层级的关系,使用缩进表示层级关系,只允许使用空格,idea中tab可以;#表示注释
//.properties
server:
port: 8082
//.yml/.yaml
server:
port: 8082
- 多种配置文件,加载顺序为.properties/.yml/.yaml
- 使用
person: {name: zhangsan}
adress:
- bejing
- shanghai
age: [18,20]
msg1: 'hello \n world'
msg2: "hello \n world"
sex: man
people:
sex: ${sex}
读取配置文件
Value方式
@Value("${sex}")
private String sex;
@Value("${people.sex}")
private String sex;
@Value("${adresses[0]}")
private String adress;
environment
@Autowired
private Environment environment;
environment.getProperty("people.sex") + environment.getProperty("adresses[0]")
ConfigurationProperties
@Component
@ConfigurationProperties(prefix = "person")
public class Person {
private String name;
private int age;
private String[] adresses;
...
getter/setter
}
person:
name: ${name}
age: 20
adresses:
- bejing
- shanghai
@Autowired
private Person person;
profile
动态配置切换
spring.profiles.active=dev
.yaml多文档
---
server:
port: 8081
spring:
config:
activate:
on-profile: dev
---
server:
port: 8082
spring:
config:
activate:
on-profile: test
---
server:
port: 8083
spring:
config:
activate:
on-profile: pro
---
spring:
profiles:
active: dev
虚拟机参数设置
-Dspring.profiles.active=test
命令行参数
--spring.profiles.active=pro
java -jar demo-0.0.1-SNAPSHOT.jar --spring.profiles.active=pro
内部配置加载顺序
file:../config/ 当前项目
file../
classpath:/config/ resources目录下
classpath:/
server.servlet.context-path=/hello
整合其他框架
整合junit
@SpringBootTest
class DemoApplicationTests {
@Autowired
private UserService userService;
@Test
void serviceTest() {
userService.add();
}
}
- 如果跟要测试的包不在同一个包或者子包下,要写明classes属性
@RunWith(SpringRunner.class)
@SpringBootTest(classes = DemoApplication.class)
整合Redis
spring:
redis:
host: 127.0.0.1
port: 3435
@Autowired
private RedisTemplate redisTemplate;
@Test
public void testSet() {
redisTemplate.boundValueOps("name").set("zhangsan");
}
@Test
public void testGet() {
Object name = redisTemplate.boundValueOps("name").get();
System.out.println(name);
}
整合Mybatis
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql:///dbtest2
username: root
password: 123456789
- 如果使用xml配置mapper,需要配置mybatis
mybatis:
mapper-locations:
config-location:
type-aliases-package:
@Autowired
private AccountMapper accountMapper;
@Test
public void testFindAll() {
List<Account> accountList = accountMapper.findAll();
for (Account account : accountList) {
System.out.println(account);
}
}
condition 自动配置
//获取springboot容器
ConfigurableApplicationContext context = SpringApplication.run(Application.class, args)
//获取Bean
Object redisTemplate = context.getBean("redisTemplate")
System.out.println(redisTemplate)
手动实现
@Configuration
public class UserConfig {
@Bean
@Conditional(ClassCondition.class)
public User user() {
return new User();
}
}
public class ClassCondition implements Condition {
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
boolean b = true;
try {
Class<?> cls = Class.forName("redis.clients.jedis.Jedis");
} catch (ClassNotFoundException e) {
b = false;
}
return b;
}
}
动态实现
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(ClassCondition.class)
public @interface ConditionOnClass {
String[] value();
}
public class ClassCondition implements Condition {
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
Map<String, Object> map = annotatedTypeMetadata.getAnnotationAttributes(ConditionOnClass.class.getName());
String[] value = (String[]) map.get("value");
boolean b = true;
try {
for (String s : value) {
Class<?> cls = Class.forName(s);
}
} catch (ClassNotFoundException e) {
b = false;
}
return b;
}
}
@Configuration
public class UserConfig {
@Bean
@ConditionOnClass({"redis.clients.jedis.Jedis"})
public User user() {
return new User();
}
}
切换内置web服务器
<exclusions>
<exclusion>
<artifactId>spring-boot-starter-tomcat</artifactId>
<groupId>org.springframework.boot</groupId>
</exclusion>
</exclusions>
<dependency>
<artifactId>spring-boot-starter-jetty</artifactId>
<groupId>org.springframework.boot</groupId>
</dependency>
Enable注解
- 用于动态启用某些功能,底层原理使用
@Import注解导入一些配置类,实现动态加载
- @Import加载类,这些类都会被Spring创建并放入IOC容器
@Import(UserConfig.class)
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(UserConfig.class)
public @interface EnableUser {
}
Import注解
@Import(User.class)
@Import(UserConfig.class)
@Import(MyImportSelector.class)
public class MyImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
return new String[]{"com.java.domain.User"};
}
}
- 导入
ImportBeanDefinitionRegistrar实现类
@Import(MyImportBeanDefinitionRegistrar.class)
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(User.class).getBeanDefinition();
registry.registerBeanDefinition("user",beanDefinition);
}
}
@EnableAutoConfiguration
- 内部使用
@Import({AutoConfigurationImportSelector.class})加载配置类
- 加载
META-INF/spring.factories文件中的配置类,在springBoot启动时,根据Conditional条件进行选择性的加载Bean
自定义starter
- 创建
spring-boot-autoConfig模块
- 创建
RedisAutoConfig类,加载Bean
@Configuration
@EnableConfigurationProperties(RedisProperties.class)
public class RedisAutoConfig {
@Bean
public Jedis jedis(RedisProperties redisProperties) {
return new Jedis(redisProperties.getHost(),redisProperties.getPort());
}
}
//在properties文件中设置时的引用 类似 redis.port=6666
@ConfigurationProperties(prefix = "redis")
public class RedisProperties {
//默认值
private String host = "localhost"
private int port = 6379
}
- 创建
META-INF/spring.factories文件,springBoot会自动扫描加载
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.java.redis.config.RedisAutoConfig
- 创建
redis-spring-boot-starter模块,最终导入这个模块使用
监听
CommandLineRunner和ApplicationRunner
- 当项目启动后执行
run方法,如提前加载数据库的数据,数据预热‘
- 效果一样
- 参数通过命令行导入
name=java
- ApplicationRunner
@Component
public class MyApplicationRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println("MyApplicationRunner...run");
System.out.println(args.getSourceArgs()[0]);
}
}
@Component
public class MyCommandLineRunner implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
System.out.println("MyCommandLineRunner...run");
System.out.println(Arrays.asList(args));
}
}
ApplicationContextInitializer和SpringApplicationRunListener
- 配置
META-INF/spring.factories
org.springframework.context.ApplicationContextInitializer=com.java.listen.MyApplitaionCentextInitializer
org.springframework.boot.SpringApplicationRunListener=com.java.listen.MySpringApplicationRunListener
- ApplicationContextInitializer环境准备好后,执行
@Component
public class MyApplitaionCentextInitializer implements ApplicationContextInitializer {
@Override
public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
System.out.println("MyApplitaionCentextInitializer...");
}
}
- SpringApplicationRunListener 要自己配置构造方法,不能注入
public class MySpringApplicationRunListener implements SpringApplicationRunListener {
public MySpringApplicationRunListener(SpringApplication application, String[] args) {
}
......
starting...项目启动
environmentPrepared...环境对象开始准备
contextPrepared...上下文开始准备
contextLoaded...上下文对象开始加载
started...上下文对象加载完成
running...项目启动完成,开始运行
failed...项目启动失败
}
启动流程
- 初始化,加载模块
- 启动应用,启动计时器,启动监听器
- 启动监听模块,配置环境模块,应用上下文模块(加载bean)
- 刷新上下文
- 关闭监听,记录启动结束时间
监控
- Acuator
- 访问
http://localhost:8080/actuator
{
"_links":{
"self":{
"href":"http://localhost:8080/actuator",
"templated":false
},
"health":{
"href":"http://localhost:8080/actuator/health",
"templated":false
},
"health-path":{
"href":"http://localhost:8080/actuator/health/{*path}",
"templated":true}}}
# 开启健康检查的完整信息
management.endpoint.health.show-details=always
{"status":"UP",
"components":{
"diskSpace":{
"status":"UP",
"details":{
"total":250685575168,
"free":27977404416,
"threshold":10485760,
"exists":true}},
"ping":{
"status":"UP"}}}
开启其他监控信息
management.endpoints.web.exposure.include=*
Admin
- 图形化处理监控信息
- 服务端加载
admin-server提供UI界面查看
- 客户端加载
admin-client,并配置
spring.boot.admin.client.url=http://localhost:9000
management.endpoint.health.show-details=always
management.endpoints.web.exposure.include=*
部署
- jar包 命令行执行
java -jar spring-boot-admin-client-0.0.1-SNAPSHOT.jar
war包
- 引导类修改,继承
SpringBootServletInitializer
@SpringBootApplication
public class SpringBootAdminClientApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(SpringBootAdminClientApplication.class, args);
}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(SpringBootAdminClientApplication.class);
}
}
- 放在tomcat的webapps文件夹下,访问路径要加包名
http://localhost:8080/spring-war/user/findAll
- build标签指定包名
<finalName>spring-war</finalName>
<packaging>war</packaging>