前言
项目里多出用到了spring的事件监听机制,然后今天无聊就翻了翻源码,看看spring底层是如何实现的。
先梳理一下,首先Ioc容器启动的时候,ApplicationContext
的refresh
模板方法中,initApplicationEventMulticaster()
方法中那个初始化了SimpleApplicationEventMulticaster
。
发送事件还是使用 applicationContext.publishEvent
(或者applicationEventPublisher.publishEvent
),并且底层还是使用SimpleApplicationEventMulticaster
发送。只是原来使用的是固定方法名称onApllicationEvent
进行调用,那拿到监听的类则可以使用父类调用子类的方法
就可以了。但是现在是自己写了一个随意定的名称那么怎么进行调用呢?其实自己去写框架的时候也可以思考一下,当然知道方法上有固定注解(@EventListener
)则还是可以找到该方法的。
在看@EventListener之前需要先知道 继承EventListener方式在底层是怎么实现了,可以参见前一篇博客Spring源码-事件监听机制(实现EventListener接口)。
一、@EventListener方式的实现
定义事件类型,这里的SysUser对象省略
/**
* @author ZhuZiKai
* @Description 发送消息事件
* @date 2021-05-28 16:40
*/
public class SendMobileMsgEvent extends ApplicationEvent {
private SysUser sysUser;
public SendMobileMsgEvent(Object source, SysUser sysUser) {
super(source);
this.sysUser= sysUser;
}
public SysUser getSysUser () {
return sysUser;
}
public void setSysUser (SysUser sysUser) {
this.sysUser= sysUser;
}
}
两种发送事件的方式:
@Service("eventUserService")
public class UserService implements ApplicationContextAware, ApplicationEventPublisherAware {
private ApplicationContext applicationContext;
private ApplicationEventPublisher applicationEventPublisher;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.applicationEventPublisher = applicationEventPublisher;
}
public BaseResp addUser(SysUser sysUser) {
// 新增用户
{
.....
}
// 发生事件(发邮件、发短信、、、)
applicationContext.publishEvent(new SendMobileMsgEvent(sysUser));
// 两种发生方式一致
applicationEventPublisher.publishEvent(new SendMobileMsgEvent(sysUser));
return new BaseResp<>(ResultStatus.SUCCESS);;
}
}
@EvnetListener监听实现
@Component
public class UserListener {
@Async
@EventListener
public void getUserEvent(UserEvent userEvent) {
System.out.println("getUserEvent-接受到事件:" + userEvent);
}
@Async
@EventListener
public void getUserEvent2(UserEvent userEvent) {
System.out.println("getUserEvent2-接受到事件:" + userEvent);
}
}
测试
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = KevinToolApplication.class )
public class AnnotationEventListenerTest {
@Autowired
private UserService userService;
@Test
public void annotationEventTest() {
userService.addUser(new SysUser());
}
}
二、@EventListener方式的源码分析
@EventListener做什么了
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface EventListener {
@AliasFor("classes")
Class<?>[] value() default {};
@AliasFor("value")
Class<?>[] classes() default {};
String condition() default "";
}
该注解可以定义在方法或者类
上,可以定义监听的Clas
s,可以定义监听的条件(Spring EL
表达式)。那么问题来了,定义了Class当然可以找到是谁发送事件过来,没有定义呢(可能是通过方法发入参,因为事件可以定义ApplicationEvent或者Object类型
)。
如果idea导入了source和document(个人比较喜欢),则在注解中可以看见@see EventListenerMethodProcessor
,结构如下:
public class EventListenerMethodProcessor
implements SmartInitializingSingleton, ApplicationContextAware, BeanFactoryPostProcessor {
protected final Log logger = LogFactory.getLog(getClass());
@Nullable
private ConfigurableApplicationContext applicationContext;
@Nullable
private ConfigurableListableBeanFactory beanFactory;
@Nullable
private List<EventListenerFactory> eventListenerFactories;
private final EventExpressionEvaluator evaluator = new EventExpressionEvaluator();
private final Set<Class<?>> nonAnnotatedClasses = Collections.newSetFromMap(new ConcurrentHashMap<>(64));
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
Assert.isTrue(applicationContext instanceof ConfigurableApplicationContext,
"ApplicationContext does not implement ConfigurableApplicationContext");
this.applicationContext = (ConfigurableApplicationContext) applicationContext;
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
this.beanFactory = beanFactory;
Map<String, EventListenerFactory> beans = beanFactory.getBeansOfType(EventListenerFactory.class, false, false);
List<EventListenerFactory> factories = new ArrayList<>(beans.values());
AnnotationAwareOrderComparator.sort(factories);
this.eventListenerFactories = factories;
}
@Override
public void afterSingletonsInstantiated() {
ConfigurableListableBeanFactory beanFactory = this.beanFactory;
Assert.state(this.beanFactory != null, "No ConfigurableListableBeanFactory set");
String[] beanNames = beanFactory.getBeanNamesForType(Object.class);
for (String beanName : beanNames) {
if (!ScopedProxyUtils.isScopedTarget(beanName)) {
Class<?> type = null;
try {
type = AutoProxyUtils.determineTargetClass(beanFactory, beanName);
}
catch (Throwable ex) {
// An unresolvable bean type, probably from a lazy bean - let's ignore it.
if (logger.isDebugEnabled()) {
logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex);
}
}
if (type != null) {
if (ScopedObject.class.isAssignableFrom(type)) {
try {
Class<?> targetClass = AutoProxyUtils.determineTargetClass(
beanFactory, ScopedProxyUtils.getTargetBeanName(beanName));
if (targetClass != null) {
type = targetClass;
}
}
catch (Throwable ex) {
// An invalid scoped proxy arrangement - let's ignore it.
if (logger.isDebugEnabled()) {
logger.debug("Could not resolve target bean for scoped proxy '" + beanName + "'", ex);
}
}
}
try {
processBean(beanName, type);
}
catch (Throwable ex) {
throw new BeanInitializationException("Failed to process @EventListener " +
"annotation on bean with name '" + beanName + "'", ex);
}
}
}
}
}
private void processBean(final String beanName, final Class<?> targetType) {
if (!this.nonAnnotatedClasses.contains(targetType) &&
AnnotationUtils.isCandidateClass(targetType, EventListener.class) &&
!isSpringContainerClass(targetType)) {
Map<Method, EventListener> annotatedMethods = null;
try {
annotatedMethods = MethodIntrospector.selectMethods(targetType,
(MethodIntrospector.MetadataLookup<EventListener>) method ->
AnnotatedElementUtils.findMergedAnnotation(method, EventListener.class));
}
catch (Throwable ex) {
// An unresolvable type in a method signature, probably from a lazy bean - let's ignore it.
if (logger.isDebugEnabled()) {
logger.debug("Could not resolve methods for bean with name '" + beanName + "'", ex);
}
}
if (CollectionUtils.isEmpty(annotatedMethods)) {
this.nonAnnotatedClasses.add(targetType);
if (logger.isTraceEnabled()) {
logger.trace("No @EventListener annotations found on bean class: " + targetType.getName());
}
}
else {
// Non-empty set of methods
ConfigurableApplicationContext context = this.applicationContext;
Assert.state(context != null, "No ApplicationContext set");
List<EventListenerFactory> factories = this.eventListenerFactories;
Assert.state(factories != null, "EventListenerFactory List not initialized");
for (Method method : annotatedMethods.keySet()) {
for (EventListenerFactory factory : factories) {
if (factory.supportsMethod(method)) {
Method methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName));
ApplicationListener<?> applicationListener =
factory.createApplicationListener(beanName, targetType, methodToUse);
if (applicationListener instanceof ApplicationListenerMethodAdapter) {
((ApplicationListenerMethodAdapter) applicationListener).init(context, this.evaluator);
}
context.addApplicationListener(applicationListener);
break;
}
}
}
if (logger.isDebugEnabled()) {
logger.debug(annotatedMethods.size() + " @EventListener methods processed on bean '" +
beanName + "': " + annotatedMethods);
}
}
}
}
/**
* Determine whether the given class is an {@code org.springframework}
* bean class that is not annotated as a user or test {@link Component}...
* which indicates that there is no {@link EventListener} to be found there.
* @since 5.1
*/
private static boolean isSpringContainerClass(Class<?> clazz) {
return (clazz.getName().startsWith("org.springframework.") &&
!AnnotatedElementUtils.isAnnotated(ClassUtils.getUserClass(clazz), Component.class));
}
}
实现了三个接口:
1)、实现了 ApplicationContextAware
接口将其注入进来
2)、实现了BeanFactoryPostProcessor
接口,实现方法如下(只是没想通有ApplicationContext则beanFactory的功能都有了,为什么对实现一个接口,可能是执行时机也可能是觉得工厂干工厂的事好理解):
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
this.beanFactory = beanFactory;
Map<String, EventListenerFactory> beans =
beanFactory.getBeansOfType(EventListenerFactory.class, false, false);
List<EventListenerFactory> factories = new ArrayList<>(beans.values());
AnnotationAwareOrderComparator.sort(factories);
this.eventListenerFactories = factories;
}
获取容器中所有EventBeanFactory
或子类的bean
,进行排序后存放到eventListenerFactories
,这里拿到了DefaultEventListenerFactory
这个非常的关键,在哪里注入的后续梳理。当然如果我们还添加了注解@TransactionalEventListener
肯定还会有TransactionalEventListenerFactory
3)、实现了SmartInitializingSingleton
接口,则在所以非抽象、非懒加载的单利都getBean
完成后,才会调用afterSingletonsInstantiated
方法,这也算是SmartInitializingSingleton
的使用场景分析(容器级别的处理)。主要逻辑也在这里。
@Override
public void afterSingletonsInstantiated() {
ConfigurableListableBeanFactory beanFactory = this.beanFactory;
Assert.state(this.beanFactory != null, "No ConfigurableListableBeanFactory set");
String[] beanNames = beanFactory.getBeanNamesForType(Object.class);
for (String beanName : beanNames) {
if (!ScopedProxyUtils.isScopedTarget(beanName)) {
Class<?> type = null;
try {
type = AutoProxyUtils.determineTargetClass(beanFactory, beanName);
}
catch (Throwable ex) {
// An unresolvable bean type, probably from a lazy bean - let's ignore it.
if (logger.isDebugEnabled()) {
logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex);
}
}
if (type != null) {
if (ScopedObject.class.isAssignableFrom(type)) {
try {
Class<?> targetClass = AutoProxyUtils.determineTargetClass(
beanFactory, ScopedProxyUtils.getTargetBeanName(beanName));
if (targetClass != null) {
type = targetClass;
}
}
catch (Throwable ex) {
// An invalid scoped proxy arrangement - let's ignore it.
if (logger.isDebugEnabled()) {
logger.debug("Could not resolve target bean for scoped proxy '" + beanName + "'", ex);
}
}
}
try {
processBean(beanName, type);
}
catch (Throwable ex) {
throw new BeanInitializationException("Failed to process @EventListener " +
"annotation on bean with name '" + beanName + "'", ex);
}
}
}
}
}
String[] beanNames = beanFactory.getBeanNamesForType(Object.class);
很暴力的获取容器中所以的bean,并且进行遍历(总会找到我想要的)
AutoProxyUtils.determineTargetClass
根据bean的名称获取bean的Class<?>,当然还考虑代理对象和继承等情况,最好获取当然的Class,调processBean(beanName, type)方法。
private void processBean(final String beanName, final Class<?> targetType) {
if (!this.nonAnnotatedClasses.contains(targetType) &&
AnnotationUtils.isCandidateClass(targetType, EventListener.class) &&
!isSpringContainerClass(targetType)) {
Map<Method, EventListener> annotatedMethods = null;
try {
annotatedMethods = MethodIntrospector.selectMethods(targetType,
(MethodIntrospector.MetadataLookup<EventListener>) method ->
AnnotatedElementUtils.findMergedAnnotation(method, EventListener.class));
}
catch (Throwable ex) {
// An unresolvable type in a method signature, probably from a lazy bean - let's ignore it.
if (logger.isDebugEnabled()) {
logger.debug("Could not resolve methods for bean with name '" + beanName + "'", ex);
}
}
if (CollectionUtils.isEmpty(annotatedMethods)) {
this.nonAnnotatedClasses.add(targetType);
if (logger.isTraceEnabled()) {
logger.trace("No @EventListener annotations found on bean class: " + targetType.getName());
}
}
else {
// Non-empty set of methods
ConfigurableApplicationContext context = this.applicationContext;
Assert.state(context != null, "No ApplicationContext set");
List<EventListenerFactory> factories = this.eventListenerFactories;
Assert.state(factories != null, "EventListenerFactory List not initialized");
for (Method method : annotatedMethods.keySet()) {
for (EventListenerFactory factory : factories) {
if (factory.supportsMethod(method)) {
Method methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName));
ApplicationListener<?> applicationListener =
factory.createApplicationListener(beanName, targetType, methodToUse);
if (applicationListener instanceof ApplicationListenerMethodAdapter) {
((ApplicationListenerMethodAdapter) applicationListener).init(context, this.evaluator);
}
context.addApplicationListener(applicationListener);
break;
}
}
}
if (logger.isDebugEnabled()) {
logger.debug(annotatedMethods.size() + " @EventListener methods processed on bean '" +
beanName + "': " + annotatedMethods);
}
}
}
}
1、进来先判断,在nonAnnotatedClasses中没出现过,后面会往里注入值。并且类上或者方法上有EventListener注解。
2、获取注解的方法map,key就是我们写的两个方法,value就是EventListener和上面的参数信息
annotatedMethods = MethodIntrospector.selectMethods(targetType,
(MethodIntrospector.MetadataLookup<EventListener>) method ->
AnnotatedElementUtils.findMergedAnnotation(method, EventListener.class));
3、有可能获取到没有标注注解的方法,则在这里加到上面判断的nonAnnotatedClasses中,提高效率,因为拿了所有的bean。 比如spring boot的启动类就被加进去了。
4、下面就比较清楚了,遍历标注EventListener注解的方法,遍历工厂,最主要的是:
ApplicationListener<?> applicationListener =
factory.createApplicationListener(beanName, targetType, methodToUse);
有不同的工厂创建不同的适配器对象(这里有简单工厂模式和适配器模式不知道理解对不),调用到DefaultEventListenerFactory
的方法,这个地方非常关键:
@Override
public ApplicationListener<?> createApplicationListener(String beanName,
Class<?> type, Method method) {
return new ApplicationListenerMethodAdapter(beanName, type, method);
}
这里返回了一个ApplicationListenerMethodAdapter
对象(基础自EventListener
),内部的method
属性就是我自己写的添加了@EventListener
的方法。并且将该listener
放入Spring
容器中。调用的是AbstractApplicationContext
的方法,如下:
@Override
public void addApplicationListener(ApplicationListener<?> listener) {
Assert.notNull(listener, "ApplicationListener must not be null");
if (this.applicationEventMulticaster != null) {
this.applicationEventMulticaster.addApplicationListener(listener);
}
this.applicationListeners.add(listener);
}
这样就将使用@EventListener
注解的方法使用包装的方式放入了SimpleApplicationEventMulticaster
的 defaultRetriever.applicationListeners
中,在后续发送事件时 获取监听器列表就能获取到了。
三、总结(与上面相同和不同之处)
相同:
1、ApplicationContext的refresh
方法还是初始化了SimpleApplicationEventMulticaster
2、发送事件式还是先获取ResolvableType
类型,再获取发送监听列表
不同:
1、获取监听列表返回的已经是处理过的列表。
2、添加了@EventListener
注解的自定义名称的方法,会在EventListenerMethodProcessor
中的afterSingletonsInstantiated()
方法中遍历所有 ApplicationContext容器的单利bean
。将所有添加了@EventListener的方法注入到ApplicationContext
的applicationListeners
和初始化的SimpleApplicationEventMulticaster
的defaultRetriever.applicationListeners
中,在发送事件时候获取监听列表时用。