Spring-Context注解源碼之@EventListener
注解說明
Annotation that marks a method as a listener for application events.
以注解的方式將一個方法標(biāo)記為事件監(jiān)聽器。如果對于spring事件監(jiān)聽機制還不了解的小伙伴點擊查看一文徹底搞懂spring事件監(jiān)聽機制
屬性說明
- public @interface EventListener {
- /**
- * 同class
- */
- @AliasFor("classes")
- Class<?>[] value() default {};
- /**
- * 監(jiān)聽事件的類型
- * 如果這個屬性長度不為空,則以這個屬性的為準(zhǔn)
- * 如果這個屬性長度為空,則以被標(biāo)注方法的參數(shù)為準(zhǔn)
- */
- @AliasFor("value")
- Class<?>[] classes() default {};
- /**
- * 以spring表達(dá)的方式計算事件監(jiān)聽是否需要觸發(fā)
- */
- String condition() default "";
- }
通過上述屬性,我們可以發(fā)現(xiàn),相比起實現(xiàn)接口的方式創(chuàng)建事件監(jiān)聽器,用注解的方式靈活性更加大,不僅可以指定多個接受事件類型,還可以增加是否觸發(fā)的條件。
使用示例
- @EventListener
- public void customListener1(MyEvent event) {
- System.out.println("接受事件customListener1");
- }
相關(guān)源碼
EventListenerMethodProcessor
- /**
- * 檢測bean里面是否包含 @EventListener
- */
- private void processBean(final String beanName, final Class<?> targetType) {
- if (!this.nonAnnotatedClasses.contains(targetType) &&
- !targetType.getName().startsWith("java") &&
- !isSpringContainerClass(targetType)) {
- Map<Method, EventListener> annotatedMethods = null;
- try {
- // 找到所有包含 @EventListener 的方法
- 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)) {
- // 如果這個類一個包含 @EventListener 方法都沒有則緩存到 nonAnnotatedClasses 中,減少重復(fù)計算
- 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");
- // 可以創(chuàng)建自定義 EventListenerFactory,如果不創(chuàng)建,默認(rèn)擁有 DefaultEventListenerFactory
- List<EventListenerFactory> factories = this.eventListenerFactories;
- Assert.state(factories != null, "EventListenerFactory List not initialized");
- for (Method method : annotatedMethods.keySet()) {
- for (EventListenerFactory factory : factories) {
- // 對于每一個方法遍歷所有的工廠,找到一個支持的工廠就進(jìn)入創(chuàng)建并完成遍歷
- if (factory.supportsMethod(method)) {
- // 根據(jù)方法創(chuàng)建 applicationListener,并將 applicationListener 添加給容器
- 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);
- }
- }
- }
- }
在
EventListenerMethodProcessor的processBean方法中,會遍歷已經(jīng)注冊的所有的bean,找到包含有被 @EventListener 標(biāo)注的方法。這些方法會被遍歷已經(jīng)創(chuàng)建的 EventListenerFactory 找到合適的工廠來生成 applicationListener,并將 applicationListener 注冊到容器的事件監(jiān)聽器列表。
ApplicationListenerMethodAdapter
- /**
- * 解析時間監(jiān)聽器支持的事件類型
- */
- private static List<ResolvableType> resolveDeclaredEventTypes(Method method, @Nullable EventListener ann) {
- int count = method.getParameterCount();
- if (count > 1) {
- // 如果方法本身參數(shù)超過1個,則直接拋出異常
- throw new IllegalStateException(
- "Maximum one parameter is allowed for event listener method: " + method);
- }
- if (ann != null) {
- // 取出 注解中的 classes屬性
- Class<?>[] classes = ann.classes();
- if (classes.length > 0) {
- // 如果classes屬性不為空,則解析classes屬性并返回作為事件解析類型
- List<ResolvableType> types = new ArrayList<>(classes.length);
- for (Class<?> eventType : classes) {
- types.add(ResolvableType.forClass(eventType));
- }
- return types;
- }
- }
- // 如果傳入的classes屬性為空,并且方法沒有參數(shù),也拋出異常
- if (count == 0) {
- throw new IllegalStateException(
- "Event parameter is mandatory for event listener method: " + method);
- }
- return Collections.singletonList(ResolvableType.forMethodParameter(method, 0));
- }
ApplicationListenerMethodAdapter的resolveDeclaredEventTypes方法會解析@EventListener標(biāo)簽的classes屬性,然后根據(jù)這個屬性決定事件監(jiān)聽器的監(jiān)聽的事件類型。
如果方法參數(shù)個數(shù)超過1個,直接拋出異常。這是一個事件觸發(fā)以后,如果接受的方法參數(shù)個數(shù)大于1個,spring沒辦法給方法進(jìn)行傳參。
如果classes屬性為空,并且方法參數(shù)個數(shù)為0個,也拋出異常。這是因為spring無法推斷這個監(jiān)聽器需要支持什么類型的事件。
除去上面兩種情況,解析都是成功,同時classes屬性會優(yōu)先被選擇為監(jiān)聽的事件類型。
- private boolean shouldHandle(ApplicationEvent event, @Nullable Object[] args) {
- if (args == null) {
- return false;
- }
- String condition = getCondition();
- if (StringUtils.hasText(condition)) {
- // 如果 condition 屬性不為空,則進(jìn)行spring表達(dá)式計算結(jié)果并返回
- Assert.notNull(this.evaluator, "EventExpressionEvaluator must not be null");
- return this.evaluator.condition(
- condition, event, this.targetMethod, this.methodKey, args, this.applicationContext);
- }
- return true;
- }
ApplicationListenerMethodAdapter的shouldHandle方法會根據(jù)@EventListener標(biāo)簽的condition屬性判斷是否需要推送消息。
如果condition不為空,則使用spring表達(dá)式計算condition得到結(jié)果,結(jié)果為true的時候才推送事件。如果condition為空,則不判斷直接推送。