spring boot源码解析(二)番外篇

前言

这篇作为番外篇,在第二篇学习后,进行自定义实现一些接口实现,更好的理解其过程。

扩展实现

SpringApplicationRunListener

自定义SpringApplicationRunListener接口实现:

public class CustomSpringApplicationRunListener implements SpringApplicationRunListener, Ordered {

	public CustomSpringApplicationRunListener(SpringApplication application, String[] args) {
		System.out.println("spring application main class is: " + application.getMainApplicationClass().getName());
		System.out.println("spring application main class args: " + args);
	}

	@Override
	public void starting() {
		System.out.println("spring application starting");
	}

	@Override
	public void environmentPrepared(ConfigurableEnvironment environment) {
		System.out.println("spring environment Prepared");
		System.out.println("environment default profiles: " + environment.getDefaultProfiles());
		System.out.println("environment active profiles: " + environment.getActiveProfiles());
	}

	@Override
	public void contextPrepared(ConfigurableApplicationContext context) {
		System.out.println("spring context Prepared");
		System.out.println("spring context application name is: " + context.getApplicationName());
		System.out.println("spring context is active: " + context.isActive());
	}

	@Override
	public void contextLoaded(ConfigurableApplicationContext context) {
		System.out.println("spring context loaded");
		System.out.println("spring context application name is: " + context.getApplicationName());
		System.out.println("spring context is active: " + context.isActive());
	}

	@Override
	public void started(ConfigurableApplicationContext context) {
		System.out.println("spring started");
		System.out.println("spring context application name is: " + context.getApplicationName());
		System.out.println("spring context is active: " + context.isActive());
	}

	@Override
	public void running(ConfigurableApplicationContext context) {
		System.out.println("spring running");
		System.out.println("spring context application name is: " + context.getApplicationName());
		System.out.println("spring context is active: " + context.isActive());
	}

	@Override
	public void failed(ConfigurableApplicationContext context, Throwable exception) {
		System.out.println("spring start failed");
		System.out.println("spring start failed error: " + exception.getMessage());
	}

	@Override
	public int getOrder() {
		return 1;
	}
}

这里有三个要注意的点:

  1. 上篇介绍过,SpringApplicationRunListener接口实现的获取是通过spring.factories,类似于SPI机制,所以需要在META-INF文件夹下创建该文件,并填写内容
# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
sample.simple.extension.CustomSpringApplicationRunListener
  1. 上篇说到过,SpringApplicationRunListener实现构造的时候,传递了构造参数,SpringApplication和args,所以自定义实现类也要有该构造方法,否则会报如下错误:
Caused by: java.lang.NoSuchMethodException: sample.simple.extension.CustomSpringApplicationRunListener.<init>(org.springframework.boot.SpringApplication, [Ljava.lang.String;)
	at java.lang.Class.getConstructor0(Class.java:3082)
	at java.lang.Class.getDeclaredConstructor(Class.java:2178)
	at org.springframework.boot.SpringApplication.createSpringFactoriesInstances(SpringApplication.java:455)
	... 4 more
  1. 可以实现接口Ordered接口排序,当然也可以不实现,默认为0。

SpringApplicationRunListener接口定义了spring boot的启动过程接口,根据需要可以扩展实现,当然也可以扩展ApplicationListener,这样更轻便和灵活。而且SpringApplicationRunListener是spring boot包中的,而ApplicationListener是spring context包中,可以看出ApplicationListener更加适用。

ApplicationListener

参考内置的listener其实可以看出,一般实现ApplicationListener接口采用两种常见的方式:
模式一:

public class CustomApplicationListener implements ApplicationListener<ApplicationEvent>, Ordered {
	@Override
	public void onApplicationEvent(ApplicationEvent applicationEvent) {
		System.out.println(applicationEvent.getClass().getName());
	}

	@Override
	public int getOrder() {
		return 0;
	}
}

模式二:

public class CustomGenericApplicationListener implements GenericApplicationListener {

	@Override
	public boolean supportsEventType(ResolvableType resolvableType) {
		System.out.println(resolvableType.getType().getTypeName());
		return true;
	}

	@Override
	public void onApplicationEvent(ApplicationEvent applicationEvent) {
		System.out.println(applicationEvent.getClass().getName());
	}

	@Override
	public boolean supportsSourceType(Class<?> sourceType) {
		return true;
	}

	@Override
	public int getOrder() {
		return 0;
	}
}

其实还有一个SmartApplicationListener,但感觉和GenericApplicationListener没什么区别,所以不再讲。

这两种模式其实就是针对两种使用场景,都是为了控制根据eventType来进行触发,一个是通过硬编码泛型的方式,一个是通过实现方法判断,返回true or false的方式。

其实从输出结果来看,会发现触发的不只是application run过程的event,其实从接口定义的泛型ApplicationEvent来看,就该猜到,ApplicationEvent是一个非常底层的接口,在spring里面的事件都是采用这种模式。如果只是想接受application run过程的event,可以实现的时候将event定在SpringApplicationEvent。

AOP

之前介绍到SimpleApplicationEventMulticaster.addApplicationListener时进行了AOP判断,这里我试着对自定义listener做AOP,但似乎没有生效,暂时原因不明,不知道是不是SimpleApplicationEventMulticaster.addApplicationListener中的AOP判断不是对启动时做的。而且尝试在启动后主动用context.publishEvent方法似乎也没有成功。
不知道是不是这些listener没有在IOC容器中还是什么情况,如果有大佬能解答下更好。

猜你喜欢

转载自blog.csdn.net/caohao1210/article/details/88646609