1. Spring Boot 高级
2. 自动配置
2.1. Condition
Condition是spring 4.0 增加的条件判断功能 通个这个功能可以实现选择性的创建Bean操作
启动类返回IOC容器 获取bean对象
//启动springboot的应用 返回spring的IOC容器
ConfigurableApplicationContext context = SpringApplication.run(SpringbootProfilesApplication.class, args);
//获取bean
Object redisTemplate = context.getBean("redisTemplate");
System.out.println(redisTemplate);
创建一个类实现 Condition接口 实现matches方法 返回一个布尔值 true为允许创建bean false为不允许
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
public class ClassCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
try {
//获取指定的class 是否加载 没有则不允许创建新的bean
Class<?> cls = Class.forName("redis.clients.jedis.Jedis");
} catch (ClassNotFoundException e) {
return false;
}
return true;
}
}
使用注解@Conditional
@Configuration
public class UserConfig {
@Bean
//如果为true则创建该bean
@Conditional(ClassCondition.class)
public User user(){
return new User();
}
}
2.2. 自定义Conditional注解
创建注解
package com.itheima.springbootprofiles.condtion;
import org.springframework.context.annotation.Conditional;
import java.lang.annotation.*;
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(ClassCondition.class)
public @interface ConditionOnClass {
String[] value();
}
创建一个类实现 Condition接口 实现matches方法 返回一个布尔值 true为允许创建bean false为不允许
package com.itheima.springbootprofiles.condtion;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
import java.util.Map;
public class ClassCondition implements Condition {
/**
*
* @param context 上下文对象 用于获取环境 ioc容器 classloader对象
* @param metadata 注解元对象 可以用于获取注解定义的属性值
* @return
*/
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Map<String, Object> map = metadata.getAnnotationAttributes(ConditionOnClass.class.getName()); //获取注解中的元数据
String[] value = (String[]) map.get("value"); //获取value中值
try {
//获取指定的class 是否加载 没有则不允许创建新的bean
for (String classNmae : value) {
Class<?> cls = Class.forName(classNmae);
}
} catch (ClassNotFoundException e) {
return false;
}
return true;
}
}
使用注解
@Configuration
public class UserConfig {
@Bean
// @Conditional(ClassCondition.class)
@ConditionOnClass("com.alibaba.fastjson.Json")
public User user(){
return new User();
}
}
2.3. 常用条件注解
- @ConditionalOnProperty 判断配置文件中是否有对应属性和值才初始化Bean
- @ConditionalOnClass 判断环境中是否有对应的字节码文件才初始化Bean
- @ConditionalOnMissingBean 判断环境中没有对应的Bean时才初始化Bean
- @ConditionalOnBean 判断容器中有指定组件时才注册该被标注的组件
@Bean
//当application配置文件中有此键值对时才创建此bean
@ConditionalOnProperty(name = "name",havingValue = "zhangsan")
public User user2(){
return new User();
}
@ConditionalOnBean(name = "tomcat")
@Bean // 给容器注册添加组件 用bean声明 返回的值,就是组件在容器中的实例
public User user01() {
User zhangsan = new User("zhangsan",18);
zhangsan.setPet(tomcatpet());
return zhangsan;
}
2.4. 切换内置web服务器
SpringBoot的web环境默认为tomcat作为内置服务器,Springboot提供了4种内置服务器让我们选择
- 排除tomcat 引入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>
2.5. @Enable* 注解
SpringBoot中提供了很多Enable开头的注解,这些注解都是用于动态启用某些功能的,而底层原理是使用了@Import注解导入一些配置类,实现Bean的动态加载
2.5.1. 第三方包导入
在项目或者POM中添加坐标
Springboot并不会加载到我们自己手动导入的第三方包
- 使用@ComponentScan(“引用路径”) 重新定义扫描目录 SpringBoot默认为启动类的根路径下Bean
- 使用@Import(字节码) 导入第三方jar包
- 自定义注解 实现@Import 并继承其之前的注解 简化我们书写
2.5.2. @Import注解
@Enable*底层依赖于@Import注解导入一些类,使用@Import导入的类会被Spring加载到IOC容器中,而@Import提供4种用法
导入Bean
导入配置类
导入ImportSelector实现类 一般用于加载配置文件中的类 ```java public class MyImportSelector implements ImportSelector { //实现selectImports方法 需要一个元数据 @Override public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{"com.itheima.domain.user"};
} }
//使用@Import导入实现类 @Import(MyImportSelector.class)
4.
导入 ImportBeanDefinitionRegistrar 实现类
```java
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
//Bean对象
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(User.class).getBeanDefinition();
//创建bean的名称 以及需要一个bean对象
registry.registerBeanDefinition("user",beanDefinition);
}
}
//使用@Import导入实现类
@Import(MyImportBeanDefinitionRegistrar.class)
2.5.3. @EnableAutoConfiguration
- @EnableAutoConfiguration 注解内部使用@Import(AutoConfigurationImporttSelector.class) 来加载配置类
- 配置文件位置: META-INF/spring.factories 该配置文件中定义了大量的配置类 当SpringBoot应用启动时,会自动加载这些配置类 初始化Bean
- 并不是所有Bean都会被初始化 在配置类中使用Condition来加载满足条件的Bean
2.6. 自定义自动配置
配置redis 配置类
package com.itheima.redisspringbootautoconfigure.redis.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
@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;
}
}
自动配置类
package com.itheima.redisspringbootautoconfigure.redis.config;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import redis.clients.jedis.Jedis;
@Configuration
@EnableConfigurationProperties(RedisProperties.class)
@ConditionalOnClass(Jedis.class)
public class RedisAutoConfiguration {
@Bean
@ConditionalOnMissingBean(name = "jedis")
public Jedis jedis(RedisProperties redisProperties) {
return new Jedis(redisProperties.getHost(), redisProperties.getPort());
}
}
在resource 下创建META-INF目录 创建spring.factories文件
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.itheima.redisspringbootautoconfigure.redis.config.RedisAutoConfiguration
- 使用 在项目pom中引入自定义自动配置的项目坐标
启动时自动配置
3. 监听机制
SpringBoot的监听机制,其实是对java提供的事件监听机制的封装
Java中的事件监听机制定义了以下几个角色:
- 事件: Event, 继承java.util.EventObject类的对象
- 事件源: Source , 任意对象Object
- 监听器: Listener 实现java.util.EventListener接口的对象
SpringBoot在项目启动时,会对几个监听器进行回调,我们可以实现这些监听器接口,在项目启动时完成一些操作
- ApplicationContextInitializer 项目图标加载后监听 ```java package com.itheima.springbootinit.listener;
import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.stereotype.Component;
@Component public class MyApplicationContextInitializer implements ApplicationContextInitializer { @Override public void initialize(ConfigurableApplicationContext applicationContext) { System.out.println(“ApplicationContextInitializer…initialize”); } }
<br />并且配置resource下的 META-INF 的spring.factories配置
org.springframework.context.ApplicationContextInitializer=com.itheima.springbootinit.listener.MyApplicationContextInitializer
-
SpringApplicationRunListener 生命周期监听
```java
package com.itheima.springbootinit.listener;
import org.springframework.boot.ConfigurableBootstrapContext;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringApplicationRunListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.stereotype.Component;
public class MySpringApplicationRunListener implements SpringApplicationRunListener {
public MySpringApplicationRunListener(SpringApplication application, String[] args) {
}
@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) {
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配置
org.springframework.boot.SpringApplicationRunListener=com.itheima.springbootinit.listener.MySpringApplicationRunListener
- CommandLineRunner ```java package com.itheima.springbootinit.listener;
import org.springframework.boot.CommandLineRunner; import org.springframework.stereotype.Component;
import java.util.Arrays;
@Component public class MyCommandLineRunner implements CommandLineRunner { @Override public void run(String… args) throws Exception { System.out.println(“CommandLineRunner…run”); System.out.println(Arrays.toString(args)); //java运行传递的参数 } }
-
ApplicationRunner
```java
package com.itheima.springbootinit.listener;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
import java.util.Arrays;
@Component
public class MyApplicationRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println("ApplicationRunner...run");
System.out.println(Arrays.toString(args.getSourceArgs())); //java运行传递的参数
}
}
3.1. 启动流程
4. 监控
SpringBoot自带监控功能Actuator,可以帮助实现对程序内部运行情况监控,比如监控状况 Bean加载情况 配置属性 日志信息
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
访问localhost:8080/acruator
- 开启(health)健康检查完整信息
management.endpoint.health.show-details=always
- 将所有的监控endpoint暴露出来
management.endpoints.web.exposure.include=*
5. Spring Boot Admin
Spring Boot Admin是一个开源社区项目 用于管理和监控SpringBoot应用程序
分服务端和客户端 客户端用于查看监控 服务端用于监控Spring
服务端
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-server</artifactId>
<version>2.5.0</version>
</dependency>
在启动类中加上 注解 @EnableAdminServer 用于监控springboot
客户端
创建另外一个项目
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
<version>2.5.0</version>
</dependency>
在application配置admin.server地址
spring.boot.admin.client.url=http://localhost:8080 #对应的是server的ip和端口
management.endpoint.health.show-details=always
management.endpoints.web.exposure.include=*
6. 部署
SpringBoot项目开发完毕后,支持两种方式部署到服务器上
jar包(官方推荐)
直接在maven中打包即可war包
在pom文件中packageing定义为war包
启动类继承 SpringBootServletInitializer 类 重写configure方法@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(SpringbootProfilesApplication.class); //将启动类字节码文件传递过去
}
放置war包到tomcat的webapps的目录下启动tomcat即可