SpringBoot起步依赖原理分析
spring-boot-starter-parent:在这里定义了各种技术的版本信息,组合了一套最优搭配的技术版本,在各种starter中,定义了完成该功能需要的坐标合集,其中大部分版本信息来自于父工程,我们的工程继承parent,引入starter后,通过以来传递,就可以简单方便获得需要的jar包,并且不会存在版本冲突问题
SpringBoot读取配置内容
1.@Value(“${name}”)
2.Environment:通过@Autowired注入private Environment env直接可以通过env.getProperty(“name”)获取配置内容
3.@ConfigurationProperties(prefix=“person”)可以作用在实体类上
SpringBoot整合test
引入pom依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
@SpringBootTest(classes = SpringbootInitApplication.class)
class SpringbootInitApplicationTests {
@Autowired
private TestService testService;
@Test
void contextLoads() {
testService.test();
}
}
SpringBoot原理分析
Condition: Condition是在Spring4增加的条件判断功能,通过这个功能可以实现选择性的创建Bean操作
通过自定义注解的方式代码演示:
首先自定义注解
package com.rlw.springbootinit.condition;
import org.springframework.context.annotation.Conditional;
import java.lang.annotation.*;
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
//绑定自定义的ClassConditional
@Conditional(ClassConditional.class)
public @interface MyConditionOnClass {
String[] value();
}
自定义逻辑
package com.rlw.springbootinit.condition;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
import java.util.Map;
public class ClassConditional implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
//获取这个注解标注的map
Map<String, Object> map = metadata.getAnnotationAttributes(MyConditionOnClass.class.getName());
//得到类路径
String[] value = (String[])map.get("value");
boolean flag = true;
for (String s : value) {
try {
//通过路径判断是否可以获取到值
Class<?> aClass = Class.forName(s);
} catch (ClassNotFoundException e) {
e.printStackTrace();
flag = false;
}
}
return flag;
}
}
应用
@Configuration
public class ConfigCondition {
@Bean
@MyConditionOnClass("com.rlw.springbootinit.service.TestService")
public User user() {
return new User();
}
}
小结:
自定义条件:(1)定义条件类:自定义类实现Condition接口,重写matches方法,在matches方法中进行逻辑判断,返回boolean值,matches方法两个参数一个是context可获取上下文对象、可以获取属性值、可以获取类加载器、获取BeanFactory等;另一个是metaBean可以获取元数据对象,用于获取注解属性(2)判断条件:在初始化Bean时,使用@Conditionall(条件类.class)注解
SpringBoot自动配置
@Enable**注解
SpringBoot中包含很多的@Enable开头的注解,这些都是用于动态启用某些功能的,而其底层原理是使用@Import注解导入一些配置类,实现Bean的动态加载
思考Springboot中是否可以直接获取jar包中的Bean?
答案是不可以的,原因是@SpringBootApplication注解中的@ComponentScan注解只能扫到同级别或子包下
解决方案: (1)可以使用@ComponentScan加载启动类上指定扫描扫不到的包路径;(2)也可以使用@Import引入并且会被直接放入IOC容器中
定义注解并importUser
package com.rlw.springbootinit.condition;
import com.rlw.springbootinit.bean.User;
import org.springframework.context.annotation.Import;
import java.lang.annotation.*;
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(User.class)
public @interface EnableUser {
}
把注解放在启动类上
@SpringBootApplication
@EnableUser
public class SpringbootInitApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(SpringbootInitApplication.class, args);
System.out.println(context.getBean("user"));
}
}
@Import注解
@Enable*注解依赖于@Import注解导入一些类,使用@Import导入的类会被Spring加载到IOC容器中,而@Import提供4种用法:(1)导入Bean,导入一个(2)导入配置类,根据配置的Bean导入多个(3)导入ImportSelector实现类,一般用于加载配置文件中的类(4)导入ImportBeanDefinitionRegistat实现类
导入ImportSelector实现类
public class MyImport implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{"com.rlw.springbootinit.bean.User"};
}
}
@SpringBootApplication
@Import(MyImport.class)
public class SpringbootInitApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(SpringbootInitApplication.class, args);
System.out.println(context.getBean(User.class));
}
}
SpringBoot自动配置 @EnableAutoConfiguration
1.@EnableAutoConfiguration注解内部使用了@Import({AutoConfigurationImportSelector.class})来加载配置类
2.配置文件位置:META-INF/spring.factories(多数以.autoconfigure结尾),该配置文件中定义了大量的配置类,当SpringBoot应用启动时,会自动加载这些配置类,初始化Bean
3.并不是所有的Bean都会被初始化,在配置类中使用@ConditionOn注解来判断是否需要加载
自定义stater
要求当导入redis坐标的时候,SpringBoot地洞创建Jedis的bean
(1)创建autoconfig
(2)创建starter模块,依赖autoconfig的模块
(3)在autoconfig模块中初始化Jedis的Bean,并定义META-INF/spring.factories文件
(4)在测试模块中引入自定义的starter依赖,测试获取Jedis的Bean,操作redis
SpringBoot监听机制
SpringBoot的监听事件,其实是对java提供的事件监听机制的封装
java事件监听机制定义了以下几个角色(1)事件:Event,继承java.util.EventObject类的对象(2)事件源:Source,任意对象Object(3)监听器:Listener,实现java.util.EventListener接口的对象
/**
* 需要在META-INF/spring.factories中配置好键值对信息
*/
@Component
public class MyApplicationContextInitializer implements ApplicationContextInitializer {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
System.out.println("ApplicationContextInitializer");
}
}
@Component
public class MyApplicationRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println("ApplicationRunner");
}
}
@Component
public class MyCommandLineRunner implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
System.out.println("CommandLineRunner");
}
}
/**
* 需要在META-INF/spring.factories中配置好键值对信息
*/
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, Duration timeTaken) {
System.out.println("contextLoaded...上下文对象加载完成");
}
@Override
public void ready(ConfigurableApplicationContext context, Duration timeTaken) {
}
@Override
public void failed(ConfigurableApplicationContext context, Throwable exception) {
System.out.println("contextLoaded...项目启动失败");
}
}
SpringBoot启动流程分析
初始化:从配置文件中获取初始化的信息进行赋值
1.首先创建一个新的SpringApplication对象源,构造这个对象初始化流程,然后调用他的run方法
2.初始化一些成员变量信息,判断有没有主类
3.通过WebApplicationType.deduceFromClasspath()判断是否是Web环境
4.紧接着set一系列监听器Initializers与Listeners
调用run方法启动
public ConfigurableApplicationContext run(String... args) {
//1.首先监控耗时
long startTime = System.nanoTime();
//2.创建引导上下文
DefaultBootstrapContext bootstrapContext = this.createBootstrapContext();
//3.定义ioc容器变量
ConfigurableApplicationContext context = null;
//4.注册表示运行在服务器端
this.configureHeadlessProperty();
//5.获取运行监听器
SpringApplicationRunListeners listeners = this.getRunListeners(args);
//6.启动监听器
listeners.starting(bootstrapContext, this.mainApplicationClass);
try {
//7.默认应用程序参数,将args封装为 ApplicationArguments 对象
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
//8.prepareEnvironment根据运行监听器和参数准备spring环境
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);
//9.加载BeanInfo
this.configureIgnoreBeanInfo(environment);
//10.输出图标
Banner printedBanner = this.printBanner(environment);
//11.接着调用createApplicationContext方法创建应用上下文
context = this.createApplicationContext();
context.setApplicationStartup(this.applicationStartup);
//12.准备Context
this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
//13.真正的去刷新容器,根据配置去初始化Bean
this.refreshContext(context);
//14.内部什么都没有做,留给我们自己去扩展
this.afterRefresh(context, applicationArguments);
Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
if (this.logStartupInfo) {
(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), timeTakenToStartup);
}
listeners.started(context, timeTakenToStartup);
this.callRunners(context, applicationArguments);
} catch (Throwable var12) {
this.handleRunFailure(context, var12, listeners);
throw new IllegalStateException(var12);
}
try {
Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
listeners.ready(context, timeTakenToReady);
//最后返回容器
return context;
} catch (Throwable var11) {
this.handleRunFailure(context, var11, (SpringApplicationRunListeners)null);
throw new IllegalStateException(var11);
}
}
SpringBoot监控
SpringBoot自带的监控功能Actuator,可以帮助实现对程序内部运行情况监控,比如监控状况、Bean加载情况、配置属性、日志信息等
<dependency>
<groupld>org.springframeworkboot</groupld>
<artifactld>spring-boot-starter-actuator</artifactld>
</dependency>