spring boot复习 SpringBoot提供了一种快速使用Spring的方式,基于约定优于配置的思想,可以让开发人员不必在配置与逻辑业务之间进行思维的切换,全身心的投入到逻辑业务的代码编写中,从而大大提高了开发的效率
https://spring.io/ 最标准的文档
spring boot 功能 spring Boot 并不是对 Spring 功能上的增强,而是提供了一种快速使用 Spring 的方式
自动配置 应用程序启动时的一个过程
起步依赖 将具备某种功能的坐标打包到一起,并提供一些默认的功能,解决依赖太多 版本冲突
辅助功能 提供了一些大型项目中常见的非功能性特性,如嵌入式服务器(tomcat)、安全、指标,健康检测、外部配置等
Hello Spring Boot 1 2 3 4 5 6 7 8 9 10 11 12 13 14 <!--springboot工程需要继承的父工程--> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.8.RELEASE</version> </parent> <dependencies> <!--web开发的起步依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies>
配置文件 三种配置文件后缀名properties
yml
yaml
yml AML是一种直观的能够被电脑识别的的数据数据序列化格式,并且容易被人类阅读,容易和脚本语言交互的,可以被支持YAML库的不同的编程语言程序导入
特点
数据格式 对象(map) 1 employee2: {name:xiaobo }
数组 1 2 3 4 address: - changtu - tieling - jinjia
纯量 1 2 3 msg1: 'hello \n spring boot' msg2: "hello \n spring boot"
参数引用 1 2 3 4 5 6 7 msg1: 'hello \n spring boot' msg2: "hello \n spring boot" employee: msg1: ${msg1} msg2: ${msg2}
获取数据 数据获取有三种方式
@Value
在属性上使用@Value取yml文件里定义的属性值
Evironment 1 2 3 4 @Autowired private Environment environment;environment.getProperty("name1" );
@ConfigurationProperties 1 @ConfigurationProperties(prefix = "employee")
profile-运维 配置方式
1 spring.profiles.active=dev
application-dev.properties/yml
开发环境
application-test.properties/yml
测试环境
application-pro.properties/yml
生产环境
激活方式 配置文件 再配置文件中配置:spring.profiles.active=dev
虚拟机参数 在VM options 指定:-Dspring.profiles.active=pro
命令行参数 –spring.profiles.active=dev
相当于上线时,运行jar包:java -jar xxx.jar –spring.profiles.active=dev
配置文件加载顺序 file:./config/:当前项目下的/config目录下
file:./ :当前项目的根目录
classpath:/config/:classpath的/config目录
classpath:/ :classpath的根目录
Spring Boot 整合 spring boot整合Junit
1 2 3 4 5 6 7 8 9 10 11 12 <dependencies > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter</artifactId > </dependency > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-test</artifactId > <scope > test</scope > </dependency > </dependencies >
1 2 3 4 5 6 7 8 9 10 11 12 13 @SpringBootTest(classes = Application.class) @RunWith(SpringRunner.class) public class MybatisTest { @Autowired private UserMapper userMapper; @Test public void testMapper () { List<User> all = userMapper.findAll(); System.out.println(all); } }
spring boot整合Mybatis
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <dependencies > <dependency > <groupId > org.mybatis.spring.boot</groupId > <artifactId > mybatis-spring-boot-starter</artifactId > <version > 2.1.0</version > </dependency > <dependency > <groupId > mysql</groupId > <artifactId > mysql-connector-java</artifactId > </dependency > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-test</artifactId > <scope > test</scope > </dependency > </dependencies >
1 2 3 4 5 6 7 8 9 10 11 12 @Data @NoArgsConstructor @AllArgsConstructor @ToString public class User { private Integer id; private String username; private String password; }
1 2 3 4 5 6 spring: datasource: name: root password: xiaobo driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/db_springboot?characterEncoding=utf8&useUnicode=true&useSSL=false&serverTimezone=GMT%2B8
1 2 3 4 5 6 7 @Mapper public interface UserMapper { @Select("SELECT * FROM t_user") public List<User> findAll () ; }
xml方式
1 2 3 4 5 6 @Mapper public interface UserMapper2 { public List<User> findAll () ; }
1 2 3 4 5 <mapper namespace ="com.dream.xiaobo.mapper.UserMapper2" > <select id ="findAll" resultType ="com.dream.xiaobo.entity.User" > SELECT * FROM `t_user` </select > </mapper >
1 2 3 4 mybatis: mapper-locations: classpath:mapper/* configuration: map-underscore-to-camel-case: true
SpringBoot整合redis
1 2 3 4 5 6 7 8 9 10 11 12 <dependencies > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-data-redis</artifactId > </dependency > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-test</artifactId > <scope > test</scope > </dependency > </dependencies >
1 2 3 4 spring: redis: host: 0.0 .0 .0 port: 6379
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 @Test public void testRedisSet () { redisTemplate.opsForValue().set("name" ,"xiaobo" ); redisTemplate.boundValueOps("age" ).set(22 ); System.out.println("插入成功" ); } @Test public void testRedisGet () { redisTemplate.opsForValue().get("name" ); redisTemplate.boundValueOps("age" ); }
springboot的自动配置 Condition
@Coditional
Conditional要配和Condition的实现类(ClassCondition)进行使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 @Configuration public class UserConfig { @Bean @Conditional(ClassCondition.class) @ConditionOnClass({"redis.clients.jedis.Jedis","com.mysql.cj.jdbc.Driver"}) public User user () { return new User(); } @Bean @ConditionalOnProperty(value = "name",havingValue = "xiaobo") public User user2 () { return new User(); } }
@ConditionOnClass为自定义注解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 public class ClassCondition implements Condition { @Override public boolean matches (ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) { try { Map<String, Object> maps = annotatedTypeMetadata.getAnnotationAttributes("com.dream.xiaobo.annotation.ConditionOnClass" ); System.out.println(maps); String[] values = (String[]) maps.get("value" ); for (String value : values) { Class.forName(value); } return true ; } catch (ClassNotFoundException e) { return false ; } } }
1 2 3 4 5 6 7 @Target({ElementType.METHOD,ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Conditional(ClassCondition.class) public @interface ConditionOnClass { String[] value(); }
这里spring都默认提供了,上面只是介绍一下简单的原理
ConditionalOnProperty
:判断配置文件中是否有对应属性和值才初始化Bean
ConditionalOnClass
:判断环境中是否有对应字节码文件才初始化Bean
ConditionalOnMissingBean
:判断环境中没有对应Bean才初始化Bean
这里我们来思考一个问题,就是为什么我们依赖就直接可以拿到对应的对象呢?
springboot中的autoconfig包下把常用的对象的配置类都封装好了,只要工程中,引入了相关起步依赖,这些对象在我们本项目的容器中就有了
Enable注解原理 SpringBoot不能直接获取在其他工程中定义的Bean,所以我们想获取到就要进行处理,
Enable注解底层原理是使用@Import注解实现Bean的动态加载
1 2 3 4 5 6 7 8 9 @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) }) public @interface SpringBootApplication {
@SpringBootConfiguration
: 自动配置相关
@EnableAutoConfiguration
: 特殊的@import
@ComponentScan
: 扫描本包及子包
三种处理方案
@ComponentScan 扫描范围:当前引导类所在包及其子包
这里我们可以对其指定
自定义一个注解,使用@Import加载类,所以我们只需要声明这个注解即可使用
加载类。这些类都会被Spring创建,并放入IOC容器
四种@Import形式
模块一
在pom中引入模块二
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 @SpringBootApplication @Import(MyImportBeanDefinitionRegistrar.class) public class EnableApplication { public static void main (String[] args) { ConfigurableApplicationContext context = SpringApplication.run(EnableApplication.class, args); Map<String, User> userMap = context.getBeansOfType(User.class); Map<String, Role> roleMap = context.getBeansOfType(Role.class); System.out.println(userMap); System.out.println(roleMap); } }
@EnableAutoConfiguration
中使用的是第三种方式:@Import(AutoConfigurationImportSelector.class)
1 2 3 4 5 6 7 8 9 public class MyImportSelector implements ImportSelector { @Override public String[] selectImports(AnnotationMetadata annotationMetadata) { return new String[]{"com.aliww.entity.User" , "com.aliww.entity.Role" }; } }
MyImportBeanDefinitionRegistrar
1 2 3 4 5 6 7 8 9 10 11 12 13 public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions (AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) { AbstractBeanDefinition user = BeanDefinitionBuilder.rootBeanDefinition(User.class).getBeanDefinition(); AbstractBeanDefinition role = BeanDefinitionBuilder.rootBeanDefinition(Role.class).getBeanDefinition(); beanDefinitionRegistry.registerBeanDefinition("user" ,user); beanDefinitionRegistry.registerBeanDefinition("role" ,role); } }
模块二
1 2 3 4 5 6 7 8 9 10 11 @Configuration public class UserConfiguration { @Bean public User user () { return new User(); } }
1 2 3 4 5 6 @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Import(UserConfiguration.class) public @interface EnableUser {}
自定义starter 就是我们怎么使用的第三方写好依赖,这里我们来模拟一下
模块一
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <dependencies > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter</artifactId > </dependency > <dependency > <groupId > com.dream.xiaobo</groupId > <artifactId > redis-spring-boot-autoconfiguration</artifactId > <version > 1.0-SNAPSHOT</version > </dependency > </dependencies >
模块二
1 2 3 4 5 6 7 8 9 10 11 12 13 <dependencies > <dependency > <groupId > redis.clients</groupId > <artifactId > jedis</artifactId > </dependency > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-configuration-processor</artifactId > <optional > true</optional > </dependency > </dependencies >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 @ConfigurationProperties(prefix = "redis") public class RedisSpringBoot { private String host = "152.136.22.223" ; private Integer port = 6379 ; public String getHost () { return host; } public void setHost (String host) { this .host = host; } public Integer getPort () { return port; } public void setPort (Integer port) { this .port = port; } }
RedisSpringBootConfiguration
1 2 3 4 5 6 7 8 @Configuration @EnableConfigurationProperties(RedisSpringBoot.class) public class RedisSpringBootConfiguration { @Bean public Jedis jedis (RedisSpringBoot redisSpringBoot) { return new Jedis(redisSpringBoot.getHost(),redisSpringBoot.getPort()); } }
META-INF/spring.factories
1 2 3 org.springframework.boot.autoconfigure.EnableAutoConfiguration =\ com.dream.xiaobo.config.RedisSpringBootConfiguration
模块三
1 2 3 4 5 <dependency > <groupId > com.dream.xiaobo</groupId > <artifactId > redis-spring-boot-starter</artifactId > <version > 1.0-SNAPSHOT</version > </dependency >
1 2 3 4 5 6 7 8 9 10 11 @SpringBootApplication public class EnableApplication { public static void main (String[] args) { ConfigurableApplicationContext context = SpringApplication.run(EnableApplication.class, args); Jedis jedis = (Jedis) context.getBean("jedis" ); System.out.println(jedis); } }
事件监听 Java中的事件监听机制
事件:Event
继承 java.util.EventObject 类的对象
事件源:Source
任意对象Object
监听器:Listener
实现 java.util.EventListener 接口 的对象
监听器 SpringBoot 在项目启动时,会对几个监听器进行回调,可以实现这些监听器接口,在项目启动时完成一些操作
ApplicationRunner
1 2 3 4 5 6 7 8 @Component public class MyApplicationRunner implements ApplicationRunner { @Override public void run (ApplicationArguments args) throws Exception { System.out.println("ApplicationRunner run() 执行" ); } }
当项目启动后执行,使用@Component放入容器即可使用
CommandLineRunner
1 2 3 4 5 6 7 @Component public class MyCommandLineRunner implements CommandLineRunner { @Override public void run (String... args) throws Exception { System.out.println("CommandLineRunner run() 执行" ); } }
当项目启动后执行,使用@Component放入容器即可使用
ApplicationContextInitializer
1 2 3 4 5 6 7 @Component public class MyApplicationContextInitializer implements ApplicationContextInitializer { @Override public void initialize (ConfigurableApplicationContext configurableApplicationContext) { System.out.println("ApplicationContextInitializer initialize() 执行" ); } }
在resource文件夹下添加META-INF/spring.factories
1 org.springframework.context.ApplicationContextInitializer = com.dream.xiaobo.listener.MyApplicationContextInitializer
SpringApplicationRunListener
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 public class MySpringApplicationRunListener implements SpringApplicationRunListener { public MySpringApplicationRunListener (SpringApplication application, String[] args) { } @Override public void starting () { System.out.println("starting...项目启动中" ); } @Override public void environmentPrepared (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) { System.out.println("started...上下文对象加载完成" ); } @Override public void running (ConfigurableApplicationContext context) { System.out.println("running...项目启动完成,开始运行" ); } @Override public void failed (ConfigurableApplicationContext context, Throwable exception) { System.out.println("failed...项目启动失败" ); } }
在resource文件夹下添加META-INF/spring.factories
1 org.springframework.boot.SpringApplicationRunListener = com.dream.xiaobo.listener.MySpringApplicationRunListener
SpringBoot启动流程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 @SuppressWarnings({ "unchecked", "rawtypes" }) public SpringApplication (ResourceLoader resourceLoader, Class<?>... primarySources) { this .resourceLoader = resourceLoader; Assert.notNull(primarySources, "PrimarySources must not be null" ); this .primarySources = new LinkedHashSet<>(Arrays.asList(primarySources)); this .webApplicationType = WebApplicationType.deduceFromClasspath(); setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); this .mainApplicationClass = deduceMainApplicationClass(); }
首先SpringApplication应用开始启动,启动的时候new 一个SpringApplication()实例应用,开始进行初始化
1 2 3 this .resourceLoader = resourceLoader;Assert.notNull(primarySources, "PrimarySources must not be null" ); this .primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
1 this .webApplicationType = WebApplicationType.deduceFromClasspath();
1 setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
1 setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
1 this .mainApplicationClass = deduceMainApplicationClass();
初始化完成之后将进行run
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 public ConfigurableApplicationContext run (String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null ; Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>(); configureHeadlessProperty(); SpringApplicationRunListeners listeners = getRunListeners(args); listeners.starting(); try { ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); configureIgnoreBeanInfo(environment); Banner printedBanner = printBanner(environment); context = createApplicationContext(); exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, context); prepareContext(context, environment, listeners, applicationArguments, printedBanner); refreshContext(context); afterRefresh(context, applicationArguments); stopWatch.stop(); if (this .logStartupInfo) { new StartupInfoLogger(this .mainApplicationClass).logStarted(getApplicationLog(), stopWatch); } listeners.started(context); callRunners(context, applicationArguments); } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, listeners); throw new IllegalStateException(ex); } try { listeners.running(context); } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, null ); throw new IllegalStateException(ex); } return context; }
1 2 StopWatch stopWatch = new StopWatch(); stopWatch.start();
打开计时器并启动起来
1 Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
1 ConfigurableApplicationContext context = null ;
1 configureHeadlessProperty();
1 2 SpringApplicationRunListeners listeners = getRunListeners(args); listeners.starting();
1 2 3 ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); configureIgnoreBeanInfo(environment);
1 Banner printedBanner = printBanner(environment);
1 context = createApplicationContext();
1 2 exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, context);
1 prepareContext(context, environment, listeners, applicationArguments, printedBanner);
1 refreshContext(context);
1 2 afterRefresh(context, applicationArguments); stopWatch.stop();
SpringBoot监控-actuator 运维人员可进行其监控
1 2 3 4 <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-actuator</artifactId > </dependency >
http://localhost:8080/actuator
可对其进行一些配置
1 2 3 4 management.endpoint.health.show-details =always management.endpoints.web.exposure.include =*
图形化界面监听 设置一个server模块,用于监听client,这里我们把启动的都当做一个client来看
server模块
1 2 3 4 <dependency > <groupId > de.codecentric</groupId > <artifactId > spring-boot-admin-starter-server</artifactId > </dependency >
1 2 3 4 5 6 7 8 9 @SpringBootApplication @EnableAdminServer public class ServerApplication { public static void main (String[] args) { SpringApplication.run(ServerApplication.class,args); } }
@EnableAdminServer
使用第三方依赖
client模块
1 2 3 4 <dependency > <groupId > de.codecentric</groupId > <artifactId > spring-boot-admin-starter-client</artifactId > </dependency >
1 2 3 4 5 spring.boot.admin.client.url =http://localhost:9000 management.endpoint.health.show-details =always management.endpoints.web.exposure.include =*
SpringBoot项目部署 就是将项目打包之后发布,springboot提供两种打包方式,一种是jar,一种是war,正常情况下都是使用jar形式
jar形式
1 2 3 4 5 6 7 8 9 <build > <finalName > springboot</finalName > <plugins > <plugin > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-maven-plugin</artifactId > </plugin > </plugins > </build >
然后直接用Maven的package即可打成jar包形式
war形式 pom依赖中添加
1 <packaging > war</packaging >
1 2 3 4 5 6 7 8 9 10 11 12 13 @SpringBootApplication public class SpringbootWarApplication extends SpringbootWarApplication { public static void main (String[] args) { SpringApplication.run(SpringbootWarApplication.class, args); } @Override protected SpringApplicationBuilder configure (SpringApplicationBuilder builder) { return builder.sources(SpringbootWarApplication.class); } }
继承 SpringbootWarApplication重写configure方法
正确的开始 微小的长进 然后持续 嘿 我是小博 带你一起看我目之所及的世界