1.原理分析
1.1.自动配置
1.1.1Condition概述
- spring帮我们创建bean
- 之前只要配置,spring会帮我们创建bean,现在可以加一些条件,满足条件,再帮我创建bean
- 举例:导入spring-boot-starter-data-redis起步依赖,springboot就帮我们创建了redisTemplate,如果没有导入这个起步依赖,会不会帮我创建redisTemplate,而且springboot如何知道到底有没有导这个起步依赖呢
-
代码演示,直接在引导类获取spring的ioc容器,通过名称获取redisTemplate,没有导入redis起步依赖,会报错,导入了依赖就可以成功获取
1.1.2Condition案例一
- user这个bean两种写法,一种是直接在类上加注解@Component,另外一种是写一个UserConfig类(这种方法实际上是注解引入第三方类的写法,第三方类无法在源码上加@Component)
-
@Conditional注解,需要写一个Condition的实现类,该实现类就一个matches方法,返回值为true,表示满足条件,加载bean。
1.1.3.Condition案例二
动态指定某个类存在,就加载User- 自定义注解,注解上面加上@Conditional以及@Conditional所有的元注解,定义一个字符串数组的属性,用于动态接收某个类的全路径。
- Condition的自定义实现类通过matches注解元对象参数,获取自定义注解指定的属性
1.1.4.Condition在SpringBoot官方提供的jar中
- 是否有对应的字节码文件
- ioc容器是否有bean
- 配置文件是否有指定的属性
-
redis自动配置
有字节码文件,并且ioc容器中没有bean(没有自定义redisTemplate)才帮你创建
1.1.5.配置文件有某个配置,就创建bean
1.1.6.Condition小结
1.1.7.切换内置web服务器
-
不引入web起步依赖,直接启动引导类,启动之后就结束了
-
引入web起步依赖
-
springboot提供内置服务器的种类如何查看
- @ConditionalOnWebApplication当web环境下才会加载下列所有的bean
- Tomcat工厂初始化需要两个字节码文件,这两个class必须导入tomcat坐标才会有
- 所以,导入不同web服务器的坐标就可以实现服务器的动态切换
-
starter-web内部就依赖了tomcat的坐标
-
现在想用jetty,首先要把tomcat排除掉
- 内部还是使用的condition
1.1.8.@Enable*注解
- 点击引导类的@SpringBootApplication注解,可以发现上面一堆注解,其中点击@SpringBootConfiguration,发现上面有@Configuration,所以引导类是一个配置类,里面可以定义bean的
-
@EnableAutoConfiguration是自动配置的核心,点击进入发现也是组合注解
- 答案是不可以。为啥redisTemplate是jar包定义的bean,我们引入了redis起步依赖之后就直接可以获取到呢?
-
演示不能获取第三方jar包中定义的bean:新建一个模块,定义User类和UserConfig类
再新建一个模块,依赖刚才的模块,直接在引导类通过ioc容器获取user报错 -
解决
- 不用Enable注解,获取不到这个bean,就无法开启功能
- Enable的实质是import
1.1.9.@Import注解
- selector返回值是一个数组,一次可以导入很多类,registar导入bean的同时可以指定对象名称
- @SpringBootApplication--@EnableAutoConfiguration--@Import(AutoConfigurationImportSelector.class)第三种方式--AutoConfigurationImportSelector implements DeferredImportSelector--public interface DeferredImportSelector extends ImportSelector
- AutoConfigurationImportSelector里面具体完成了什么事情
1.1.10.@EnableAutoConfiguration注解
-
自动配置的核心
1.1.11.自动配置案例
- 导入Mybatis坐标,参考命名规则,spring自己的叫spring-boot-starter-xx,第三方定义的叫xx-spring-boot-starter
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
-
查看mybatis-starter里面的坐标,包含自动配置的坐标
-
查看源码
-
思路分析
-
实操redis-spring-boot-autoconfigure:
-
实操redis-spring-boot-starter:
-
实操测试
1.1.12.自动配置案例升级
-
本地启动redis服务端和客户端
-
jedis获取到之后进行set get操作,客户端也get
-
配置一个错误的redis端口号6666,哪个地方用jedis,就在哪配
- 引导类中 jedis存储会失败 说明配置的端口生效了
-
加两个条件,如果Jedis在,加载这个Bean,如果用户自己定义了jedis的bean,就不提供
-
redis官方源码
1.2.监听机制
js中定义一个按钮,按钮绑定一个单击事件,一点击就会触发一个函数。js里面的监听机制。按钮是一个事件源,事件发生的地方,点击的动作是事件,点击事件后执行的逻辑代码操作就是监听器。按钮绑定或者注册某个监听器之后,用户操作就会进行监听器代码的回调。一个事件源可以注册多个监听器。-
编写四个实现类,分别实现四个监听器接口,分别加上@Component,交给spring容器管理。启动项目发现只有ApplicationRunner和CommandLineRunner两个接口的实现类自动运行了。另外两个监听器想要运行需要配置
-
可以获取run方法的参数,就是运行时配置的参数
-
配置SpringApplicationRunListener启动项目报错
- SpringApplication是项目启动的事件源
-
源码
1.3.启动流程分析
1.3.1.初始化
- primarySources引导类可以是多个
- this.webApplicationType = WebApplicationType.deduceFromClasspath();判断是否是web环境,判断有没有Servlet对应的class
- setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));设置初始化的东西,包含自定义的Initializers,来源SpringFactories配置文件
- setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));设置监听器,不包含自定义监听器,因为我们定义的SpringRunListener和ApplicationListener(原生)不一样,是对他的的封装,来源SpringFactories配置文件
- 只是获取配置文件中初始化类和监听器类的名字,放在集合中
1.3.2.run
- StopWatch stopWatch = new StopWatch();时间控制,监控整个启动耗时
- ConfigurableApplicationContext context = null;ioc容器声明
- SpringApplicationRunListeners listeners = getRunListeners(args);带s相当于是容器,包含了很多个SpringApplicationRunListener,其中就包含我们自定义的MySpringApplicationRunListener
- listeners.starting(bootstrapContext, this.mainApplicationClass);调用所有的Listener的starting方法,内部就是做了循环,我们自己定义的MySpringApplicationRunListener的starting方法就执行了
-
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);准备环境,内部又是循环listeners.environmentPrepared(bootstrapContext, environment);我们自己定义的MySpringApplicationRunListener的environmentPrepared方法就执行了。开始准备环境的时候,信息还是比较少的
- configureIgnoreBeanInfo(environment);加载环境信息
-
Banner printedBanner = printBanner(environment);图标存放的位置信息
- context = createApplicationContext();创建ioc容器
-
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);准备context,导致MyApplicationContextInitializer的initialize方法执行、MySpringApplicationRunListener的contextPrepared和contextLoaded方法执行。此时ioc容器已经创建好了,但是bean还没有完全加载进来
-
refreshContext(context);真正去配置里面找bean然后创建,过程稍慢
web工程可能要加载100多个bean
- listeners.started(context);循环调用,包含我们自定义的MySpringApplicationRunListener的started方法
- callRunners(context, applicationArguments);会使我们自定义的两个Runner执行
- listeners.running(context);循环调用,包含我们自定义的MySpringApplicationRunListener的running方法
-
监听
观察者模式有观察者和被观察者,被观察者是事件和事件源,观察者是监听器。
-
自动配置
2.监控
2.1.基本使用
- 访问http://localhost:8084/actuator得到json字符串
-
json.cn格式化字符串
-
http://localhost:8084/actuator/info返回一个空的json字符串,获取配置文件中以info开头的属性信息
-
http://localhost:8084/actuator/health
2.2.完整使用
默认是只能看info和health,其他的想看需要配置-
http://localhost:8084/actuator/beans查看ioc容器有多少bean
-
http://localhost:8084/actuator/env配置文件属性的信息
- http://localhost:8084/actuator/heapdump访问会下载一个堆栈信息的文件,需要专业的工具分析
-
http://localhost:8084/actuator/mappings查看当前所有的url路径,可以写一个controller来验证
2.3.springboot admin
- 客户端就是想被监控的springboot项目
- 服务端是admin的ui界面的提供
-
客户端需要把数据信息(通过actuator获取)发送给服务端,服务端只需要提供ui界面把数据解析展示到界面上
-
新建server模块
-
新建client模块
-
分别启动server、client
- 访问http://localhost:9000/
-
client添加controller
-
idea简单看一下
3.项目部署
3.1.jar包
3.2.war包
-
配置文件中server.port=8888不再生效,因为这个配置是针对于内置tomcat