当前位置: 首页 > 科技观察

Spring-Context注解源码的@EventListener

时间:2023-03-12 00:36:08 科技观察

注解将方法标记为应用程序事件监听器的注解。通过注解将方法标记为事件监听器。不了解spring事件监听机制的,点击查看本文彻底了解spring事件监听机制属性说明public@interfaceEventListener{/***sameclass*/@AliasFor("classes")Class[]value()default{};/***监听事件的类型*如果该属性的长度不为空,则以该属性为准*如果该属性的长度为空,则以标记方法的参数为准以*/@AliasFor("value")Class[]classes()default{};/***以spring表达式的方式计算是否需要触发事件监听*/Stringcondition()default"";}通过上面的属性,我们可以发现,相比于通过实现接口来创建事件监听器,使用注解的方式更加灵活。不仅可以指定多种类型的接受事件,还可以增加触发条件。使用示例@EventListenerpublicvoidcustomListener1(MyEventevent){System.out.println("AccepteventcustomListener1");}相关源码EventListenerMethodProcessor/***检查bean是否包含@EventListener*/privatevoidprocessBean(finalStringbeanName,finalClasstargetType){if(!this.nonAnnotatedClasses.contains(targetType)&&!targetType.getName().startsWith("java")&&!isSpringContainerClass(targetType)){MapannotatedMethods=null;try{//查找所有包含@EventListener的方法annotatedMethods=MethodIntrospector.selectMethods(targetType,(MethodIntrospector.MetadataLookup)method->AnnotatedElementUtils.findMergedAnnotation(method,beventListener.class));if(logger.isDebugEnabled()){logger.debug("Couldnotresolvemethodsforbeanwithname'"+beanName+"'",ex);}}if(CollectionUtils.isEmpty(annotatedMethods)){//如果这个类包含一个如果没有@EventListener方法,会缓存在nonAnnotatedClasses中,减少重复计算());}}else{//Non-emptysetofmethodsConfigurableApplicationContextcontext=this.applicationContext;Assert.state(context!=null,"NoApplicationContextset");//可以创建自定义的EventListenerFactory,如果不创建,默认有DefaultEventListenerFactoryListfactories=这。eventListenerFactories;Assert.state(factories!=null,"EventListenerFactoryListnotinitialized");for(Methodmethod:annotatedMethods.keySet()){for(EventListenerFactoryfactory:factories){//对每一个method,遍历所有的工厂,找到一个支持的工厂,输入即可创建并完成遍历>applicationListener=factory.createApplicationListener(beanName,targetType,methodToUse);if(applicationListenerinstanceofApplicationListenerMethodAdapter){((ApplicationListenerMethodAdapter)applicationListener).init(context,this.evaluator);}context.addApplicationListener(applicationListener);break;}}}if(logger.isDebugEnabled()){logger.debug(annotatedMethods.size()+"@EventListenermethodsprocessedonbean'"+beanName+"':"+annotatedMethods);}}}}在EventListenerMethodProcessor的processBean方法中,会遍历所有注册的bean,找到标记的Methods通过@EventListener会遍历创建的EventListenerFactory这些方法来寻找合适的工厂生成applicationListener,并将applicationListener注册到容器的事件监听器列表中。ApplicationListenerMethodAdapter/***解析时间监听器支持的事件类型*/privatestaticListresolveDeclaredEventTypes(Methodmethod,@NullableEventListenerann){intcount=method.getParameterCount();if(count>1){//如果方法本身的参数超过1,则直接抛出异常thrownewIllegalStateException("Maximumoneparameterisallowedforeventlistenermethod:"+method);}if(ann!=null){//取出注解Class[]classes=ann.classes()中的classes属性;if(classes.length>0){//如果classes属性不为空,解析classes属性,作为事件解析类型返回Listtypes=newArrayList<>(classes.length);for(ClasseventType:classes){types.add(ResolvableType.forClass(eventType));}returntypes;}}//如果传入的classes属性为空,方法没有参数,也会抛出异常if(count==0){thrownewIllegalStateException("Eventparameterismandatoryforeventlistenermethod:"+method);}returnCollections.singletonList(ResolvableType.forMethodParameter(method,0));}ApplicationListenerMethodAdapter的resolveDeclaredEventTypes方法会解析@EventListener标签的classes属性,然后根据这个属性判断事件监听如果监听器监听的事件类型超过一个方法参数,则直接抛出异常。这是在一个事件被触发后,如果接受的方法参数个数大于1,spring就无法给方法传递参数。如果classes属性为空,方法参数个数为0,也会抛出异常。这是因为spring无法推断出此侦听器需要支持什么类型的事件。除了以上两种情况,解析成功,会优先选择classes属性作为监听的事件类型。privatebooleanshouldHandle(ApplicationEventevent,@NullableObject[]args){if(args==null){returnfalse;}Stringcondition=getCondition();if(StringUtils.hasText(condition)){//如果condition属性不为空,则spring表达式计算结果并返回Assert.notNull(this.evaluator,"EventExpressionEvaluatormustnotbenull");返回this.evaluator.condition(条件,事件,this.targetMethod,this.methodKey,args,this.applicationContext);}返回真;}ApplicationListenerMethodAdaptershouldHandle方法会根据@EventListener标签的condition属性判断是否需要推送消息。如果条件不为空,则使用spring表达式计算条件得到结果,只有结果为真才推送事件。如果条件为空,不判断直接push。