一、快速入门
- pom.xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.0.1</version>
</parent>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<!-- <version>3.0.1</version>-->
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
- com.xie.controller.HelloController.java
@RestController
public class HelloController {
@RequestMapping("/hello")
public String hello(){
return "hello Spring Boot!";
}
}
- com.xie.HlloAplication.java
/**
* 引导类:SpringBoot项目的入口
* */
@SpringBootApplication
public class HelloApplication {
public static void main(String[] args) {
SpringApplication.run(HelloApplication.class,args);
}
}
-
运行
-
浏览器
http://localhost:8080/hello -
小结
- SpringBoot在创建项目时,使用jar的打包方式
- SpringBoot的引导类,是项目入口,运行main方法就可以启动项目.
- 使用SpringBooti和Spring构建的项目,业务代码编写方式完全一样.
使用idea快速构建SpringBoot工程
- 新建com.xie.HelloController.java
@RestController
public class HelloController {
@RequestMapping("/hello")
public String hello(){
return "SpringBoot快速构建";
}
}
- 测试:浏览器
http://localhost:8080/hello
二、SpringBoot起步依赖原理分析
- 在spring-boot-starter-parent中定义了各种技术的版本信息,组合了一套最优搭配的技术版本。
- 在各种starter中,定义了完成该功能需要的坐标合集,其中大部分版本信息来自于父工程。
- 我们的工程继承parent,引l入starter)后,通过依赖传递,就可以简单方便获得需要的jar包,并且不会存在版本冲突等问题。
三、SpringBoot配置
3.1 配置文件分类
Spring Boot是基于约定的,所以很多配置都有默认值,但如果想使用自己的配置替换默认配置的话,就可以使用application.properties或者application.yml(application.yml)进行配置。
- properties:
server.port=8080
- yaml
server:
port: 8080
注意:如果三个都配置了,那么properties生效
小结
- SpringBoot提供了2种配置文件类型:properteisi和yml/yaml
- 默认配置文件名称:application
- 在同一级目录下优先级为:properties>yml>yaml
3.2 yaml
YAML全称是YAML Ain't Markup Language。YAML是一种直观的能够被电脑识别的的数据数据序列化格式,并且容易被人类阅读,容易和脚本语言饺互的,可以被支持YAML库的不同的编程语言程序导入,比如:C/C++,Ruby,Python,Java,Perl,C#,PHP等。YML文件是以数据为核心的,比传统的xml方式更加简洁。
YAML文件的扩展名可以使用.yml或者.yaml。
3.2.1 基本语法
- 大小写敏感
- 数据值前边必须有空格,作为分隔符
- 使用缩进表示层级关系
- 缩进时不允许使用Tab键,只允许使用空格(各个系统Tb对应的空格数目可能不同,导致层次混乱)。
- 缩进的空格数目不重要,只要相同层级的元素左侧吹对齐即可
- #表示注释,从这个字符一直到行尾,都会被解析器忽略。
server:
port: 8080
address: 127.0.0
name:abc
3.2.2 数据格式
- 对象(map):键值对的集合
person:
name: zhangsan
# 行内写法
person: {name: zhangsan}
- 数组:一组按次序排列的值
address:
- beijing
- shanghai
# 行内写法
address: [beijing,shanghai]
- 纯量:单个的、不可再分的值
msg1: 'hello \n world' # 单引忽略转义字符
msg2: "hello \n world" # 双引识别转义字符
- 参数引用
name: list
person:
name: ${name} #引用上边定义的name值
3.3 读取配置文件内容
- @Value
- Environment
- @ConfigurationProperties
3.3.1 @value
@RestController
public class HelloController {
@Value("${name}")
private String name;
@Value("${person.name}")
private String name2;
@Value("${person.age}")
private int age;
@Value("${address[0]}")
private String address;
@Value("${msg1}")
private String msg1;
@Value("${msg2}")
private String smg2;
@RequestMapping("/hello")
public String hello(){
return "SpringBoot快速构建";
}
@RequestMapping("/hello2")
public String hello2(){
System.out.println(name);
System.out.println("person.name的值:"+name2);
System.out.println("person底下age的值:"+age);
System.out.println("获取数组里的值:"+address);
System.out.println("获取msg1的值: "+msg1);
System.out.println("打印msg2: "+smg2);
return "获取数据";
}
}
3.3.2 Environment
@RestController
public class HelloController {
@Autowired
private Environment env;
@RequestMapping("/hello2")
public String hello2(){
System.out.println(env.getProperty("person.name"));
System.out.println(env.getProperty("msg1"));
System.out.println(env.getProperty("address[0]"));
return "获取数据";
}
}
3.3.3 @ConfigurationProperties
- 新建Person.java
@Component
@ConfigurationProperties
public class Person {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "person{" +
"name='" + name + ''' +
", age=" + age +
'}';
}
}
@RestController
public class HelloController {
@Autowired
private Person person;
@RequestMapping("/hello2")
public String hello2(){
System.out.println(person);
String[] address= person.getAddress();
for(String s:address){
System.out.println(s);
}
return "获取数据";
}
}
这里获取的是这个值
要想获取person.name和person.age的值,要添加前缀
@Component
@ConfigurationProperties(prefix = "person")
3.3.4 添加依赖
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-configuration-processor -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
3.4 profile
我们在开发Spring Boot应用时,通常同一套程序会被安装到不同环境,比如:开发、测试、生产等。其中数据库地址、服务器端口等等配置都不同,如果每次打包时,都要修改配置文件,那么非常麻烦。profile功能就是来进行动态配置切换的。
- profile配置方式
- 多profile文件方式
spring.profiles.active=dev
* yml多文档方式
2. profile激活方式
* 配置文件
* 虚拟机参数
* 命令行参数
- profile是用来完成不同环境下,配置动态切换功能的。
- profile配置方式
- 多profile.文件方式:提供多个配置文件,每个代表一种环境
- application-dev.properties/,yml开发环境
- application-test.properties/yml测试环境
- application-pro.properties./yml生产环境
- yml多文档方式:
- 在yml中使用--分隔不同配置
- profile激活方式
- 配置文件:在配置文件中配置:spring.profiles.active:=dev
- 虚拟机参数:在VM options指定:-Dspring.profiles.active:=dev
- 命令行参数:java-jarxxx.jar-spring.profiles..active=dev
3.5 内部配置加载顺序
内部配置加载顺序
Springbooti程序启动时,会从以下位置加载配置文件:
- file:./config/:当前项目下的/config目录下
- file:./ : 当前项目的根目录
- classpath:/config/:classpath的/config目录
- classpath:/:classpath的根目录
加载顺序为上文的排列顺序,高优先级配置的属性会生效
# 修改项目的访问路径 默认为/
server.servlet.context-path=/hello
3.6 外部配置加载顺序
四、SprinBoot整合其他框架
4.1 SpringBoot整合junit
- 搭建SpringBoot工程
- 引入starter-test起步依赖
- 编写测试类
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
- 添加测试相关注解
- @RunWith(SpringRunner.class)
- @SpringBootTest(classes=启动类.class))
- 编写测试方法
@Service
public class UserService {
public void add(){
System.out.println("add....");
}
}
/**
* UserService的测试类
* */
@RunWith(SpringRunner.class)
@SpringBootTest()
public class UserServiceTest {
@Autowired
private UserService userService;
@Test
public void testAdd(){
userService.add();
}
}
4.2 整合Redis
- 搭建SpringBoot框架
- 搭建SpringBoot工程
- 引入redis起步依赖
- 配置redis相关属性
- 注入RedisTemplate模板
- 编写测试方法,测试
4.3 整合mybatis
- 搭建SpringBoot工程
- 引入mybatisi起步依赖,添加mysq驱动
- 编写DataSource和MyBatis相关配置
- 定义表和实体类
- 编写dao和mapper文件/纯注解开发
- 测试
- domain.User.java
package com.xie.mybatis.domain;
public class User {
private int id;
private String username;
private String password;
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + ''' +
", password='" + password + ''' +
'}';
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
- application.yml
# datasource
spring:
datasource:
url: jdbc:mysql:///springboot?serverTimezone=UTC
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
- mapper.UserMapper.java
@Mapper
public interface UserMapper {
@Select("select * from t_user")
public List<User> findAll();
}
- 测试
@SpringBootTest
class SpringbootMybatisApplicationTests {
@Autowired
private UserMapper userMapper;
@Test
public void testFindAll() {
List<User> list = userMapper.findAll();
System.out.println(list);
}
}
4.3.1 方法一
@Mapper
public interface UserMapper {
@Select("select * from t_user")
public List<User> findAll();
}
测试
@SpringBootTest
class SpringbootMybatisApplicationTests {
@Autowired
private UserMapper userMapper;
@Test
public void testFindAll() {
List<User> list = userMapper.findAll();
System.out.println(list);
}
}
4.3.2 方法二
- application.yml
# mybatis
mybatis:
mapper-locations: classpath:mapper/*Mapper.xml # mapper映射文件路径
type-aliases-package: com.xie.mybatis.domain
# config-location: # 指定mybatis的核心配置文件
- UserMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xie.mybatis.mapper.UserXmlMapper">
<select id="findAll" resultType="User">
select * from t_user
</select>
</mapper>
- UserXmlMapper.java
@Mapper
public interface UserXmlMapper {
public List<User> findAll();
}
- 测试
@SpringBootTest
class SpringbootMybatisApplicationTests {
@Autowired
private UserXmlMapper userXmlMapper;
@Test
public void testFindAll2() {
List<User> list = userXmlMapper.findAll();
System.out.println(list);
}
}
五、SpringBoot原理分析
5.1 Condition
Condition是在Spring 4.0增加的条件判断功能,通过这个可以功能可以实现选择性的创建Bean操作。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
在Spring的IOC容器中有一个User的Bean,现要求:
- 导入jedis坐标后,加载该Bean,没导入,则不加载
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
public class User {
}
public class ClassCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
// 1.需求:导入jedis坐标后创建bean
// 思路:判断redis.clients.jedis.Jedis。class文件是否存在
boolean flag=true;
try {
Class<?> aClass = Class.forName("redis.clients.jedis.Jedis");
} catch (ClassNotFoundException e) {
flag=false;
}
return flag;
}
}
@Configuration
public class UserConfig {
@Bean
@Conditional(ClassCondition.class)
public User user(){
return new User();
}
}
public static void main(String[] args) {
ConfigurableApplicationContext context=SpringApplication.run(SpringbootConditionApplication.class, args);
// Object redis=context.getBean("redisTemplate");
// System.out.println(redis);
Object user = context.getBean("user");
System.out.println(user);
}
- 将类的判断定义为动态的,判断哪个字节码文件存在可以动态指定。
- pom.xml
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
- domain.User.java
public class User {
}
- condition.ConditionOnClass.java(自定义注解)
@Conditional(ClassCondition.class)
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ConditionOnClass {
String[] value();
}
- config.UserConfig.java
@Configuration
public class UserConfig {
@Bean
@ConditionOnClass("redis.clients.jedis.Jedis")
public User user(){
return new User();
}
}
- condition.ClassCondition.java
public class ClassCondition implements Condition {
/**
* context 上下文对戏,用于获取环境,IOC容器,ClassLoader对象
* metadata 注解的元对象,可以用于获取注解定义的属性值
* */
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
// 2.需求:导入通过注解属性value指定坐标后创建bean
// 获取注解属性值:value
Map<String, Object> map = metadata.getAnnotationAttributes(ConditionOnClass.class.getName());
// System.out.println(map);
String[] value =(String[]) map.get("value");
boolean flag=true;
try {
for(String className:value){
Class<?> aClass = Class.forName(className);
}
} catch (ClassNotFoundException e) {
flag=false;
}
return flag;
}
}
- 测试
@SpringBootApplication
public class SpringbootConditionApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context=SpringApplication.run(SpringbootConditionApplication.class, args);
// Object redis=context.getBean("redisTemplate");
// System.out.println(redis);
Object user = context.getBean("user");
System.out.println(user);
}
}
也可以:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>2.0.23</version>
</dependency>
@Configuration
public class UserConfig {
@Bean
// @ConditionOnClass("redis.clients.jedis.Jedis")
@ConditionOnClass("com.alibaba.fastjson.JSON")
public User user(){
return new User();
}
}
- 方法二
- UserConfig.java
@Configuration
public class UserConfig {
@Bean
@ConditionOnClass("redis.clients.jedis.Jedis")
// @ConditionOnClass("com.alibaba.fastjson.JSON")
public User user(){
return new User();
}
@Bean
@ConditionalOnProperty(name="itcast" ,havingValue = "xie")
public User user2(){
return new User();
}
}
- application.yml
itcast=xie
- 测试
@SpringBootApplication
public class SpringbootConditionApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context=SpringApplication.run(SpringbootConditionApplication.class, args);
// Object redis=context.getBean("redisTemplate");
// System.out.println(redis);
Object user = context.getBean("user2");
System.out.println(user);
}
}
小结
- 自定义条件:
- 定义条件类:自定义类实现Condition接口,重写matches方法,在matches方法中进行逻辑判断,返回boolean值。matches方法两个参数:
-
context:上下文对象,可以获取属性值,获取类加载器,获取BeanFactory等。
-
metadata:元数据对象,用于获取注解属性。
-
- 判断条件:在初始化Bean时,使用@Conditional(条件类.class)注解
- SpringBoot提供的常用条件注解:
- ConditionalonProperty:判断配置文件中是否有对应属性和值才初始化Bean
- Conditionalonclass:判断环境中是否有对应字节码文件才初始化Bean
- ConditionalonMissingBean:判断环境中设有对应Bean才初始化Bean
5.2 切换内置服务器
SpringBoot的web环境中默认使用tomcatf作为内置服务器,其实SpringBoot提供了4中内置服务器供我们选择,我们可以很方便的进行切换。
5.2.1 Tomcat
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
5.2.2 jetty
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<!-- 排除Tomcat依赖-->
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 引入jetty的依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
5.3 @Enable*注解
SpringBoot中提供了很多Enable开头的注解,这些注解都是用于动态启用某些功能的。而其底层原理是使用@Import注解导入一些配置类,实现Bean的动态加载。
5.3.1 不同模块获取bean
<dependency>
<groupId>com.xie</groupId>
<artifactId>enable-other</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
- User.java
public class User {
}
- UserConfig.java
@Configuration
public class UserConfig {
@Bean
public User user(){
return new User();
}
}
- 测试(main)
/**
* @ComponentScan 扫描范围,当前引导类所在包及其子包
* com.xie.config;
* com.xie.domain;
* 解决方法:
* 1. 使用@ComponentScan扫描com.xie.config包
* 2.可以使用@import注解,加载类。这些类都会被Spring创建,并放入IOC容器
* 3.可以对Import注解进行封装
*
* */
@SpringBootApplication
//@ComponentScan("com.xie.config")
//@Import(UserConfig.class)
public class SpringbootEnableApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(SpringbootEnableApplication.class, args);
Object user = context.getBean("user");
System.out.println(user);
}
}
- 方法三:对Import注解进行封装
- 新建EnableUser.java
@Import(UserConfig.class) @Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface EnableUser { }- 测试(main)
@SpringBootApplication //@ComponentScan("com.xie.config") //@Import(UserConfig.class) @EnableUser public class SpringbootEnableApplication { public static void main(String[] args) { ConfigurableApplicationContext context = SpringApplication.run(SpringbootEnableApplication.class, args); Object user = context.getBean("user"); System.out.println(user); } } - 新建EnableUser.java
5.4 @Import注解
@Enable*底层依赖于@Importi注解导入一些类,使用@Import导入的类会被Spring加载到1OC容器中。而@Import提供4种用法:
- 导入Bean
- 导入配置类
- 导入ImportSelector实现类,一般用于加载配置文件中的类
- 导入ImportBeanDefinitionRegistrar实现类
5.4.1 用法一:导入bean
@SpringBootApplication
//@ComponentScan("com.xie.config")
//@Import(UserConfig.class)
//@EnableUser
@Import(User.class)
public class SpringbootEnableApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(SpringbootEnableApplication.class, args);
User bean = context.getBean(User.class);
Map<String, User> map = context.getBeansOfType(User.class);
System.out.println(map);//所有User对应的类以及键的名称,也就是bean的名称以及bean的值
System.out.println(bean);//bean的值
}
}
5.4.2 用法二:导入配置类
- UserConfig.java
@Configuration
public class UserConfig {
@Bean
public User user(){
return new User();
}
@Bean
public Role role(){
return new Role();
}
}
- main
@SpringBootApplication
@Import(UserConfig.class)//如果用了这个注解,则UserConfig里的@Configuration注解可以不加
public class SpringbootEnableApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(SpringbootEnableApplication.class, args);
User bean = context.getBean(User.class);
Role role = context.getBean(Role.class);
System.out.println(role);
System.out.println(bean);//bean的值
}
}
5.4.3 用法三:导入ImportSelect的实现类
- com.xie.config.MyImportSelect.java
public class MyImportSelect implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{"com.xie.domain.User","com.xie.domain.Role"};
}
}
- main
@SpringBootApplication
@Import(MyImportSelect.class)
public class SpringbootEnableApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(SpringbootEnableApplication.class, args);
User bean = context.getBean(User.class);
Role role = context.getBean(Role.class);
System.out.println(role);
System.out.println(bean);//bean的值
}
}
5.4.4 用法四:导入实现类
- com.xie.config.MyImportBeanDefinitionRegistrar.java
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry){
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(User.class).getBeanDefinition();
registry.registerBeanDefinition("user",beanDefinition);
}
}
- main
@SpringBootApplication
@Import(MyImportBeanDefinitionRegistrar.class)
public class SpringbootEnableApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(SpringbootEnableApplication.class, args);
User bean = context.getBean(User.class);
Object user=context.getBean("user");
System.out.println(user);
System.out.println(bean);//bean的值
}
}
5.5 @EnableAutoConfiguration注解
- @EnableAutoConfiguration注解内部使用@Import(AutoConfigurationImportSelector.class)来加载配置类。
- 配置文件位置:META-lNF/spring.factories,该配置文件中定义了大量的配置类,当SpringBoot应用启动时,会自动加载 这些配置类,初始化Bean
- 并不是所有的Bean都会被初始化,在配置类中使用Condition来加载满足条件的Bean
5.5.1 案例
自定义redis-starter。要求当导入redis坐标时,SpringBoot自动创建Jedis的Bean。
<!-- mybatis起步依赖-->
<!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>
实现步骤
- 创建redis-spring-boot-autoconfigure模块
- 创建redis-spring-boot-starter模块,依赖redis-spring- boot-autoconfigurel的模块
- 在redis-spring-boot-autoconfigure模块中初始化Jedis的 Bean。并定义META-lNF/spring.factories文件
- 在测试模块中引入自定义的redis--starter依赖,测试获取 Jedis的Bean,操作redis。.
- redis-spring-boot-starter模块的pom.xml把测试依赖和插件给删了
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- 引入configure-->
<dependency>
<groupId>com.xie</groupId>
<artifactId>autoconfigure</artifactId>
</dependency>
</dependencies>
- redis-spring-boot-autoconfigure模块
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- 引入jedis依赖-->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
</dependencies>
- redis-spring-boot-autoconfigure模块新建config.RedisAutoConfiguration.java
@Configuration//表示是配置文件
@EnableConfigurationProperties(RedisProperties.class)//把RedisProperties这个类加载进来
public class RedisAutoConfiguration {
// 提供Jedis的bean
@Bean
public Jedis jedis(RedisProperties redisProperties){
return new Jedis(redisProperties.getHost(),redisProperties.getPort());
}
}
- redis-spring-boot-autoconfigure模块新建RedisProperties.java
@Component
@ConfigurationProperties(prefix = "redis")
public class RedisProperties {
private String host="localhost";
private int port=6379;
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
}
5.6 SpringBoot监听机制
SpringBoot的监听机制,其实是对Java提供的事件监听机制的封装。
- Java监听机制
Java中的事件监听机制定义了以下几个角色:
- 事件:Event,.继承java.util.EventObject类的对象
- 事件源:Source,任意对象Object
- 监听器:Listener,实现java.util.EventListener接口的对象
- SpringBoot监听机制
SpringBoot在项目启动时,会对几个监听器进行回调,我们可以实现这些监听器接口,在项目启动时完成一些操作。
ApplicationContextlnitializer SpringApplicationRunListener CommandLineRunner,ApplicationRunner
- MyApplicationContextInitializer.java
/**
* 当做是监听器
* */
@Component//注册到Spring容器里
public class MyApplicationContextInitializer implements ApplicationContextInitializer {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
System.out.println("ApplicationContextInitializer.......initialize");
}
}
- MyApplicationRunner.java
/**
* 当我们的项目启动后执行run方法(自动调用)
*
* */
@Component
public class MyApplicationRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println("ApplicationRunner......run");
System.out.println(Arrays.asList(args.getSourceArgs()));
}
}
- MyCommandLineRunner.java
@Component
public class MyCommandLineRunner implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
System.out.println("CommandLineRunner.....run");
System.out.println(Arrays.asList(args));
}
}
- MySpringApplicationRunListener.java
@Component
public class MySpringApplicationRunListener implements SpringApplicationRunListener {
@Override
public void starting(ConfigurableBootstrapContext bootstrapContext) {
System.out.println("starting。。。。。项目启动中");
}
@Override
public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) {
System.out.println("environmentPrepared。。。。。环境对象开始准备");
}
@Override
public void contextPrepared(ConfigurableApplicationContext context) {
System.out.println("contextPrepared。。。。。。上下文对象开始准备");
}
@Override
public void contextLoaded(ConfigurableApplicationContext context) {
System.out.println("contextLoaded。。。。。上下文对象开始加载");
}
@Override
public void started(ConfigurableApplicationContext context, Duration timeTaken) {
System.out.println("started.......上下文对象加载完成");
}
@Override
public void failed(ConfigurableApplicationContext context, Throwable exception) {
System.out.println("failed......项目启动失败");
}
}
注意:当项目启动时,只有run方法执行(即只有两个类),另外两个类需要配置才能执行
org.springframework.context.ApplicationContextInitializer=com.xie.listener.listener.MyApplicationContextInitializer
5.7 SpringBoot启动流程分析
六、SpringBoot监控
6.1 actuator
Spring Bootl自带监控功能Actuator,可以帮助实现对程序内部运行情况监控,比如监控状况、Bean加载情况、配置属性、日志信息等。
使用步骤
-
导入依赖
# 开启健康检查的完整信息
management.endpoint.health.show-details=always
# 将所有的监控endpoint暴露出来
management.endpoints.web.exposure.include=*
6.2 Spring Boot Admin(图形化界面使用)
- Spring Boot Admin是一个开源社区项目,用于管理和监控SpringBoot)应用程序。
- Spring Boot Admin有两个角色,客户端Client)和服务端Server)。
- 应用程序作为Spring Boot Admin Clientl向为Spring Boot Admin Serveri注册
- Spring Boot Admin Server的Ul界面将Spring Boot Admin Client的Actuator Endpoint上的一些监控信息,
使用步骤
- 创建两个模块(admin-server,admin-client)
- admin-server
- 创建admin-server模块
- 导入依赖坐标admin-starter-server
- 在引导类上启用监控功能@EnableAdminServer
- 加入 @EnableAdminServer注解
@EnableAdminServer @SpringBootApplication public class AdminServerApplication { public static void main(String[] args) { SpringApplication.run(AdminServerApplication.class, args); } } - 配置
server.port=9000
- admin-client
- 创建admin-client模块
- 导入依赖坐标admin-starter-client
- 配置相关信息:server地址等
- 启动server和client服务,访问server
- 配置
# 执行admin.server地址 spring.boot.admin.client.url=http://localhost:9000 # 开启所有信息 management.endpoint.health.show-details=always # 开启所有配置 management.endpoints.web.exposure.include=*
- admin-server
先运行admin-server,后运行admin-client,再浏览器http://localhost:9000 ,则可以跳转
七、SpringBoot项目部署
SpringBoot项目开发完毕后,支持两种方式部署到服务器:
- jar包(官方推荐)
- war包
7.1 jar包
- UserController.java
@RequestMapping("/user")
@RestController
public class UserController {
@RequestMapping("/findAll")
public String findAll(){
return "success";
}
}
- 打包
回车运行,然后访问http://localhost:8080/user/findAll
7.2 war包
这是使用内置的Tomcat运行的,也可以用其他的
- 启动类
@SpringBootApplication
public class SpringbootDeployApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(SpringbootDeployApplication.class, args);
}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(SpringbootDeployApplication.class);
}
}
ctrl+o:重写方法
然后再打包,然后找到位置
然后浏览器访问