版权声明:来一来,看一看,有钱的捧个人场,没钱的你不得捧个人场 https://blog.csdn.net/wait_for_eva/article/details/82948765
IDEA快捷键
Ctrl
+h
: 查看接口实现类Ctrl
+Alt
+<-
:上一步Ctrl
+Alt
+->
:下一步
需要了解细节自己追吧,版本差异不大,主体流程还是一致。
注入接口
SpringApplicationRunListener
ApplicationContextInitializer
ApplicationRunner
CommandLineRunner
- 这些方法注入比较安全,不会对
SpringBoot
本身有太大负担----别把入参玩坏了就行- 如果要定制环境什么的,高深一点就不行,只是插入流程而已
- 相同点
四种都是接口
- 差异点
后三种都只有一个方法,但是
SpringApplicationRunListener
流程监听器,生命周期决定了方法较多
接口结构
SpringApplicationRunListener
public interface SpringApplicationRunListener {
void starting();
void environmentPrepared(ConfigurableEnvironment environment);
void contextPrepared(ConfigurableApplicationContext context);
void contextLoaded(ConfigurableApplicationContext context);
void started(ConfigurableApplicationContext context);
void running(ConfigurableApplicationContext context);
void failed(ConfigurableApplicationContext context, Throwable exception);
}
starting
:开启environmentPrepared
:环境准备完毕contextPrepared
:上下文准备contextLoaded
:上下文加载完毕started
:应用正式启动running
:应用运行中failed
:失败
SpringApplicationRunListener
方法贯穿SpringApplication
,不用翻阅源码,也能大致了解
ApplicationContextInitializer
public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext> {
void initialize(C applicationContext);
}
initialize
:就一个方法
ApplicationRunner
public interface ApplicationRunner {
void run(ApplicationArguments args) throws Exception;
}
run
:没啥说的,结构不是重点
CommandLineRunner
public interface CommandLineRunner {
void run(String... args) throws Exception;
}
run
:参数不一样而已
接口顺序
- 主体依照
SpringApplicationRunListener
顺序 environmentPrepared
>ApplicationContextInitializer
>contextPrepared
started
>ApplicationRunner
>CommandLineRunner
>running
生效办法
classpath:META-INF/spring.factories
org.springframework.boot.SpringApplicationRunListener=\
com.godme.order.listener.MyRunListener
org.springframework.context.ApplicationContextInitializer=\
com.godme.order.initializer.MyInitializer
@Component
@Component
public class MyApplicationRunner implements ApplicationRunner
@Component
public class MyCommandRunner implements CommandLineRunner
SpringApplicationRunListener
和ApplicationContextInitializer
必须写配置,没有则手动创建ApplicationRunner
和CommandLineRunner
用@Component
注入容器就自动加载了
验证测试
- 日志清理
# 笨办法,直接写文件,屏蔽控制台输出
logging.config=classpath:logback-godme.xml
<configuration>
<appender name="syslog" class="ch.qos.logback.core.rolling.RollingFileAppender">
<File>sys.log</File>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>ys.%d.%i.log</fileNamePattern>
<maxHistory>30</maxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>1KB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder>
<pattern>
%d %p (%file:%line\)- %m%n
</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<logger name="com.godme.order.OrderApplication" level="DEBUG">
<appender-ref ref="syslog" />
</logger>
</configuration>
随便写点,不再干扰控制台输出就行。
Banner
关闭
@SpringBootApplication
public class OrderApplication {
public static void main(String[] args) {
SpringApplication app = new SpringApplication(OrderApplication.class);
app.setBannerMode(Banner.Mode.OFF);
app.run(args);
}
}
追源码就能清楚这个逻辑,关键在于
BannerMode
。
- 打印办法
public class Printer {
private Printer(){}
public static void print(){
StackTraceElement trace = new Throwable().getStackTrace()[1];
String className = trace.getClassName();
String methodName = trace.getMethodName();
String msg = className + getSpace(50 - className.length()) + methodName;
System.err.println(msg);
}
public static String getSpace(int count){
String spaces = "";
while(count>0){
spaces += " ";
count--;
}
return spaces;
}
}
- 静态打印工具类, 格式为
className
+spaces
+methodName
,有疑问的话参看静态方法获取调用类- 分列两行,格式化方便查看
System.err.println
,err
标红,显眼然后把
Printer.print
方法填充进入全部实现接口类的方法中
阻塞
当遇见可能不会的情况,
Ctrl
+h
,通过查看接口已实现类,或许能够获得灵感
SpringApplicationRunListener
构造
public MyRunListener(SpringApplication application, String[] args) {
Printer.print();
}
需要有参构造,这就是
Ctrl
+h
扒出来的
- 运行结果
com.godme.order.listener.MyRunListener <init>
com.godme.order.listener.MyRunListener starting
com.godme.order.listener.MyRunListener environmentPrepared
com.godme.order.initializer.MyInitializer initialize
com.godme.order.listener.MyRunListener contextPrepared
com.godme.order.listener.MyRunListener contextLoaded
com.godme.order.listener.MyRunListener started
com.godme.order.runner.MyApplicationRunner run
com.godme.order.runner.MyCommandRunner run
com.godme.order.listener.MyRunListener running
可以看到,和追查逻辑一致
可能作用
SpringApplicationRunListener
public interface SpringApplicationRunListener {
void starting();
void environmentPrepared(ConfigurableEnvironment environment);
void contextPrepared(ConfigurableApplicationContext context);
void contextLoaded(ConfigurableApplicationContext context);
void started(ConfigurableApplicationContext context);
void running(ConfigurableApplicationContext context);
void failed(ConfigurableApplicationContext context, Throwable exception);
}
除了
environment
之外,基本都是context
,exception
需要尽量避免的,精确处理也没太大必要性个人觉得更多的是流程上的操作吧,关键在于
context
的利用程度加上操作时机
ApplicationContextInitializer
public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext> {
void initialize(C applicationContext);
}
这个,除了时机错开之外,只能探究
ApplicationContextInitializer
周边关联了要不一个
ConfigurableApplicationContext
玩啥啊,自定义一个也会有新玩法
ApplicationRunner
public interface ApplicationRunner {
void run(ApplicationArguments args) throws Exception;
}
除了时机的话,这个会有参数,或许可以制定些参数操作
CommandLineRunner
public interface CommandLineRunner {
void run(String... args) throws Exception;
}
同上
杂烩
同时实现多个接口,同时添加关联参数的话,也是一个新天地。