怎么做网站站长视频,徐州通域网架公司,装饰工程有限公司,容桂顺德网站建设一、介绍
1、简介
当某个事件触发的时候#xff0c;就会执行的方法块。 当然#xff0c;springboot很贴心地提供了一个 EventListener 注解来实现监听。
2、源码#xff1a;
package org.springframework.context;import java.util.EventListener;
import java.util.fu…一、介绍
1、简介
当某个事件触发的时候就会执行的方法块。 当然springboot很贴心地提供了一个 EventListener 注解来实现监听。
2、源码
package org.springframework.context;import java.util.EventListener;
import java.util.function.Consumer;FunctionalInterface
public interface ApplicationListenerE extends ApplicationEvent extends EventListener {void onApplicationEvent(E event);default boolean supportsAsyncExecution() {return true;}static T ApplicationListenerPayloadApplicationEventT forPayload(ConsumerT consumer) {return (event) - {consumer.accept(event.getPayload());};}
}3、与其他Listener的区别
看下ApplicationListener与SpringApplicationRunListener、EventPublishingRunListener的区别和联系。前提springboot是基于spring的一个springboot应用其核心是调用了spring的SpringApplication.run()方法也就是说springboot是为简化spring开发进行的封装。现在我们来分析三者关系。
1SpringApplicationRunListener 和 EventPublishingRunListener是由springboot提供的且EventPublishingRunListener是SpringApplicationRunListener 的唯一实现。
2ApplicationListener是由spring提供的监听目标是ApplicationEvent类或者其子类所有定制化的事件都直接或间接的继承ApplicationEvent也就是说定制化的事件都是ApplicationEvent的子类都是ApplicationListener监听器的监听目标EventPublishingRunListener发布的定制化事件间接受ApplicationListener监听。
二、原理
ApplicationListener监听器本身是一个函数式接口监听对象为ApplicationEvent事件的子类ApplicationEvent事件本身是一个抽象类它拥有各式各样的子类这些子类就是定制化的事件专门用于特定的场景。ApplicationEvent事件继承EventObject这个事件本体EventObject事件本体是所有事件的基础EventObject事件本体拥有一个protected transient Object source;这样一个Object类型的source属性用于存放事件。
那这个事件数据是如何传递的呢通过观察源码我们发现在事件类继承的层层嵌套链中子类都需要通过super()方法调用父类的构造方法通过在super()中传递事件参数可以实现事件数据的层层传递最终传递到EventObject然后在EventObject的构造方法中就可以完成source属性的初始化也就完成了事件的传递以及最终存储。
三、使用
1、监听器
两个步骤先实现 ApplicationListenerE extends ApplicationEvent 接口来自定义监听器再注册监听器。注册监听器有以下几个方法
1通过启动类注册
SpringBootApplication
public class MyApplication {public static void main(String[] args) {//SpringApplication.run(MyApplication.class, args);//等价于上面的启动只不过把过程进行拆分扩展了中间操作SpringApplication application new SpringApplication(MyApplication.class);application.addListeners(new MyApplicationListener());application.run(args);}
}
2通过自动配置文件spring.factories文件注册
org.springframework.context.ApplicationListener\com.classloader.listener.CustomeApplicationListener
3通过注解注册
直接在自定义监听器上加上Component、Configuration等注解注册这是自定义监听器常用的方法。
注意通过注解注册监听不到容器加载之前的事件。
Component
public class CustomeApplicationListener implements ApplicationListenerApplicationStartedEvent , Ordered {Overridepublic void onApplicationEvent(ApplicationStartedEvent applicationStartingEvent) {System.out.println(自定义监听器CustomeApplicationListener监听springboot启动监听EventPublishingRunListener发布的启动开始事件);}Overridepublic int getOrder() {return 0;}
}
2、ApplicationEvent事件
2.1、spring的内置事件 以ContextRefreshedEvent看下结构可以看到最终都是 ApplicationEvent
package org.springframework.context.event;import org.springframework.context.ApplicationContext;public class ContextRefreshedEvent extends ApplicationContextEvent {public ContextRefreshedEvent(ApplicationContext source) {super(source);}
}package org.springframework.context.event;import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEvent;public abstract class ApplicationContextEvent extends ApplicationEvent {public ApplicationContextEvent(ApplicationContext source) {super(source);}public final ApplicationContext getApplicationContext() {return (ApplicationContext)this.getSource();}
}
2.2、自定义事件
extends ApplicationEvent 自定义事件
public class MyEvent extends ApplicationEvent {private String time new SimpleDateFormat(hh:mm:ss).format(new Date());private String msg;public MyEvent(Object source, String msg) {super(source);this.msg msg;}public MyEvent(Object source) {super(source);}public String getTime() {return time;}public void setTime(String time) {this.time time;}public String getMsg() {return msg;}public void setMsg(String msg) {this.msg msg;}
}Slf4j
Component
public class MyTask implements ApplicationListener {private static boolean aFlag false;Overridepublic void onApplicationEvent(ApplicationEvent event) {if (event instanceof ContextRefreshedEvent) {log.info(监听到 ContextRefreshedEvent...);}if (event instanceof MyEvent) {log.info(监听到 MyEvent...);MyEvent myEvent (MyEvent) event;System.out.println(时间 myEvent.getTime() 信息 myEvent.getMsg());}}
}内置事件不需要手动触发自定义监听事件需要主动触发通过applicationContext.publishEvent(event)来触发写法有
1
SpringBootApplication
public class TaskApplication {public static void main(String[] args) {ConfigurableApplicationContext run SpringApplication.run(TaskApplication.class, args);MyEvent event new MyEvent(event, 忙中岁月忙中遣我本愚来性不移);// 发布事件run.publishEvent(event);}
}2 常用方法
SpringBootApplication
public class TaskApplication implements CommandLineRunner {public static void main(String[] args) {SpringApplication.run(TaskApplication.class, args);}Resourceprivate ApplicationContext applicationContext;Overridepublic void run(String... args) throws Exception {MyEvent event new MyEvent(event, 忙中岁月忙中遣我本愚来性不移);// 发布事件applicationContext.publishEvent(event);}
}四、demo
pom
?xml version1.0 encodingUTF-8?
project xmlnshttp://maven.apache.org/POM/4.0.0xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersiongroupIdorg.example/groupIdartifactIdlistener-demo/artifactIdversion1.0-SNAPSHOT/versionpropertiesmaven.compiler.source17/maven.compiler.sourcemaven.compiler.target17/maven.compiler.targetproject.build.sourceEncodingUTF-8/project.build.sourceEncoding/propertiesparentgroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-parent/artifactIdversion3.2.4/versionrelativePath//parentdependenciesdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scope/dependencydependencygroupIdorg.springframework/groupIdartifactIdspring-aop/artifactId/dependencydependencygroupIdorg.aspectj/groupIdartifactIdaspectjweaver/artifactId/dependencydependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactId/dependency/dependencies
/project
启动类
package com.listener.demo;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;SpringBootApplication
public class ListenerApplication {public static void main(String[] args) {SpringApplication.run(ListenerApplication.class, args);}
}1、内置事件
package com.listener.demo.listener;import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;Slf4j
Component
public class MyListener implements ApplicationListenerContextRefreshedEvent {Overridepublic void onApplicationEvent(ContextRefreshedEvent event) {log.info(启动start...);}
}启动项目控制台打印 注意有时会加个标志位
Slf4j
Component
public class MyTask implements ApplicationListenerContextRefreshedEvent {private static boolean aFlag false;Overridepublic void onApplicationEvent(ContextRefreshedEvent event) {if (!aFlag) {aFlag true;log.info(我已经监听到了);}}
}因为web应用会出现父子容器这样就会触发两次监听任务所以需要一个标志位保证监听任务log.info(“我已经监听到了”)只会触发一次 。
2、自定义事件
如现在自定义一个注解在controller接口加这个注解--aop拦截获取相关信息并触发事件监听--在监听器中处理业务如存储、发送mq等等。
1自定义注解
package com.listener.demo.annotation;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;// 声明注解作用于方法
Target(ElementType.METHOD)
// 声明注解运行时有效
Retention(RetentionPolicy.RUNTIME)
public interface MyLog {String url() ;String detail() ;
}package com.listener.demo.controller;import com.listener.demo.annotation.MyLog;
import com.listener.demo.dto.UserDTO;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;RestController
RequestMapping(/user)
public class UserController {MyLog(url /user/add,detail addUser)RequestMapping(/add)public String add(UserDTO userDTO) {return add success;}MyLog(url /user/update,detail updateUser)RequestMapping(/update)public String update() {return update success;}
}2DTO
package com.listener.demo.dto;import lombok.Data;Data
public class UserDTO {private String userName;private String userAccount;private Integer age;
}package com.listener.demo.dto;import lombok.Builder;
import lombok.Data;Data
Builder
public class UserLogDTO {private String url;private String detail;
}3aop
package com.listener.demo.aop;import com.listener.demo.annotation.MyLog;
import com.listener.demo.dto.UserLogDTO;
import com.listener.demo.event.MyLogEvent;
import jakarta.annotation.Resource;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;import java.lang.reflect.Method;Aspect
Component
public class LogAspect {Resourceprivate ApplicationContext applicationContext;Around(value annotation(com.listener.demo.annotation.MyLog))public Object around(ProceedingJoinPoint joinPoint) throws Throwable {Signature signature joinPoint.getSignature();MethodSignature methodSignature (MethodSignature) signature;Method targetMethod methodSignature.getMethod();MyLog annotation targetMethod.getAnnotation(MyLog.class);//非AuthVerify权限类注解放开if (annotation null) {return joinPoint.proceed();}//触发listenerUserLogDTO userLogDTO UserLogDTO.builder().detail(annotation.detail()).url(annotation.url()).build();applicationContext.publishEvent(new MyLogEvent(userLogDTO));return joinPoint.proceed();}
}4监听
package com.listener.demo.event;import com.listener.demo.dto.UserLogDTO;
import org.springframework.context.ApplicationEvent;public class MyLogEvent extends ApplicationEvent {public MyLogEvent(UserLogDTO log) {super(log);}public UserLogDTO getSource() {return (UserLogDTO) super.getSource();}}package com.listener.demo.listener;import com.listener.demo.dto.UserLogDTO;
import com.listener.demo.event.MyLogEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;Slf4j
Component
public class MyListener implements ApplicationListenerMyLogEvent {Overridepublic void onApplicationEvent(MyLogEvent event) {UserLogDTO source event.getSource();log.info(监听到:url{},detail{},source.getUrl(),source.getDetail());//其他处理比如存储日志}
}5测试访问localhost:4444/listenerDemo/user/add?userNamezhangsanuserAccountzs
控制台打印