@EventListener注解详细使用(IT枫斗者)
@EventListener注解详细使用
简介
- @EventListener是一种事件驱动编程在spring4.2的时候开始有的,早期可以实现ApplicationListener接口, 为我们提供的一个事件监听、订阅的实现,内部实现原理是观察者设计模式;为的就是业务系统逻辑的解耦,提高可扩展性以及可维护性。事件发布者并不需要考虑谁去监听,监听具体的实现内容是什么,发布者的工作只是为了发布事件而已。
- 比如我们做一个电商系统,用户下单支付成功后,我们一般要发短信或者邮箱给用户提示什么的,这时候就可以把这个通知业务做成一个单独事件监听,等待通知就可以了;把它解耦处理。
使用@EventListener注解
-
建立事件对象,当调用publishEvent方法是会通过这个bean对象找对应事件的监听。AddDataEvent.java
-
package com.rw.article.pay.event.bean;import org.springframework.context.ApplicationEvent;/*** 新增mongodb数据事件*/ public class AddDataEvent extends ApplicationEvent {public AddDataEvent(Object source) {super(source);}public AddDataEvent(Object source, Class clz, Object data) {super(source);this.clz = clz;this.data = data;}public AddDataEvent(Object source, Class clz, Object data, String modelName, String userAgent) {super(source);this.clz = clz;this.data = data;this.modelName = modelName;this.userAgent = userAgent;}/** 要更新的表对象 **/private Class clz;/** 操作的数据**/private Object data;/** 模块名称**/private String modelName;/** 浏览器标识 **/private String userAgent;public Class getClz() {return clz;}public void setClz(Class clz) {this.clz = clz;}public Object getData() {return data;}public void setData(Object data) {this.data = data;}public String getModelName() {return modelName;}public void setModelName(String modelName) {this.modelName = modelName;}public String getUserAgent() {return userAgent;}public void setUserAgent(String userAgent) {this.userAgent = userAgent;} } -
对应的监听AddDataEventListener .java
-
package com.rw.article.pay.event.listener; import com.alibaba.fastjson.JSON; import com.rw.article.pay.event.bean.AddDataEvent; import org.slf4j.Logger; import org.slf4j.LoggerFactory;import org.springframework.context.event.EventListener; import org.springframework.stereotype.Component;/*** 新增数据的事件监听*/ @Component public class AddDataEventListener {private static Logger log = LoggerFactory.getLogger(AddDataEventListener.class);/** 在AnnotationConfigUtils#registerAnnotationConfigProcessors注册了BeanDefinition 对应的是EventListenerMethodProcessor对象 , AnnotationConfigUtils在AnnotationConfigServletWebServerApplicationContext构造方法里被加载* *//*** DefaultListableBeanFactory#中preInstantiateSingletons -> (beanName为org.springframework.context.event.internalEventListenerProcessor时得到EventListenerMethodProcessor)EventListenerMethodProcessor#afterSingletonsInstantiated this.processBean(factories, beanName, type)* 然后把要执行的方法封装为ApplicationListenerMethodAdapter -> 添加到listener中 AbstractApplicationEventMulticaster#addApplicationListener* */// 该方法在 ApplicationListenerMethodAdapter 利用反射执行/*** 处理新增数据的事件**/@EventListenerpublic void handleAddEvent(AddDataEvent event) {log.info("发布的data为:{} ", JSON.toJSONString(event));} } -
建立测试类
-
package com.rw.article.pay.action;import com.rw.article.pay.event.bean.AddDataEvent; import org.springframework.context.ApplicationContext; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody;import javax.annotation.Resource;/*** 测试的controller*/ @Controller @RequestMapping("/test") public class TestController {@Resourceprivate ApplicationContext applicationContext;@ResponseBody@RequestMapping("/testListener")public String testListener(){applicationContext.publishEvent(new AddDataEvent(this,TestController.class,"test"));return "success";} } -
结果是能够监听到的
-
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pHjkZeUm-1680567653256)(C:%5CUsers%5Cquyanliang%5CAppData%5CRoaming%5CTypora%5Ctypora-user-images%5C1680567079331.png)]
-
如果要使用异步加上
@EnableAsync注解,方法上加@Async注解,如下spring boot项目配置 -
@SpringBootApplication @EnableAsync public class XApplication{public static void main(String[] args) {ConfigurableApplicationContext run = new SpringApplicationBuilder(XApplication.class).web(true).run(args);run.publishEvent("test");} } -
@Async@EventListenerpublic void test(String wrapped){System.out.println("当前线程 "+Thread.currentThread().getName());System.out.println(wrapped);} -
还可以配置线程池
taskExecutor -
@Configuration public class GenericConfiguration {@Beanpublic Executor taskExecutor() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();//核心线程数:线程池创建时候初始化的线程数//最大线程数:线程池最大的线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程//缓冲队列:用来缓冲执行任务的队列//允许线程的空闲时间60秒:当超过了核心线程出之外的线程在空闲时间到达之后会被销毁//线程池名的前缀:设置好了之后可以方便我们定位处理任务所在的线程池//线程池对拒绝任务的处理策略:这里采用了CallerRunsPolicy策略,当线程池没有处理能力的时候,该策略会直接在 execute 方法的调用线程中运行被拒绝的任务;如果执行程序已关闭,则会丢弃该任务executor.setCorePoolSize(5);executor.setMaxPoolSize(10);executor.setQueueCapacity(20);executor.setKeepAliveSeconds(60);executor.setThreadNamePrefix("taskExecutor-");executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());return executor;} }
源码解析
-
原理还得从org.springframework.context.event.internalEventListenerProcessor
说起。 -
在AnnotationConfigUtils#registerAnnotationConfigProcessors注册了BeanDefinition 对应的是EventListenerMethodProcessor对象 , 而AnnotationConfigUtils是在AnnotationConfigServletWebServerApplicationContext构造方法里被加载。这里要提一下AnnotationConfigServletWebServerApplicationContext,他是spring boot启动入口的重要类(我这里用的是spring boot所以是这个类),可以相当于以前用xml的ClassPathXmlApplicationContext。
-
public static final String EVENT_LISTENER_PROCESSOR_BEAN_NAME ="org.springframework.context.event.internalEventListenerProcessor";public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(BeanDefinitionRegistry registry, @Nullable Object source) {................... // 注册EventListenerMethodProcessor对象if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));}...........................return beanDefs;} -
注册的EventListenerMethodProcessor对象会在初始化非懒加载对象的时候运行它的afterSingletonsInstantiated方法。
AbstractApplicationContext#finishBeanFactoryInitialization -
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {............. // 初始化非懒加载对象beanFactory.preInstantiateSingletons(); } -
DefaultListableBeanFactory#preInstantiateSingletons
-
@Override public void preInstantiateSingletons() throws BeansException {..................// 触发所有适用bean的初始化后回调 主要是afterSingletonsInstantiated方法for (String beanName : beanNames) { //如果beanName传入org.springframework.context.event.internalEventListenerProcessor 因为已经上面代码已经初始化,将从缓存中得到一个EventListenerMethodProcessor对象Object singletonInstance = getSingleton(beanName);if (singletonInstance instanceof SmartInitializingSingleton) {final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;if (System.getSecurityManager() != null) {AccessController.doPrivileged((PrivilegedAction<Object>) () -> {smartSingleton.afterSingletonsInstantiated();return null;}, getAccessControlContext());}else { // 调用其afterSingletonsInstantiated方法smartSingleton.afterSingletonsInstantiated();}}} } -
EventListenerMethodProcessor#afterSingletonsInstantiated
-
@Override public void afterSingletonsInstantiated() {List<EventListenerFactory> factories = getEventListenerFactories();ConfigurableApplicationContext context = getApplicationContext();String[] beanNames = context.getBeanNamesForType(Object.class);for (String beanName : beanNames) {if (!ScopedProxyUtils.isScopedTarget(beanName)) {Class<?> type = null;try {type = AutoProxyUtils.determineTargetClass(context.getBeanFactory(), 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(context.getBeanFactory(), 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 {// 重点是这个方法 处理beanprocessBean(factories, beanName, type);}catch (Throwable ex) {throw new BeanInitializationException("Failed to process @EventListener " +"annotation on bean with name '" + beanName + "'", ex);}}}} } -
EventListenerMethodProcessor#processBean;这里有一个重要的类就是ApplicationListenerMethodAdapter,spring把加入了@EventListener注解的方法封装进ApplicationListenerMethodAdapter对象里,然后我们publishEvent方法是,其实是调用的对应的ApplicationListenerMethodAdapter,然后里面是执行这个方法,这里可以看下ApplicationListenerMethodAdapter类的属性。
-
public class ApplicationListenerMethodAdapter implements GenericApplicationListener {protected final Log logger = LogFactory.getLog(getClass());private final String beanName;private final Method method;private final Method targetMethod;private final AnnotatedElementKey methodKey;private final List<ResolvableType> declaredEventTypes;@Nullableprivate final String condition;private final int order;@Nullableprivate ApplicationContext applicationContext;@Nullableprivate EventExpressionEvaluator evaluator;.................................. } -
protected void processBean(final List<EventListenerFactory> factories, final String beanName, final Class<?> targetType) {if (!this.nonAnnotatedClasses.contains(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)) {this.nonAnnotatedClasses.add(targetType);if (logger.isTraceEnabled()) {logger.trace("No @EventListener annotations found on bean class: " + targetType.getName());}}else {// Non-empty set of methodsConfigurableApplicationContext context = getApplicationContext();for (Method method : annotatedMethods.keySet()) {for (EventListenerFactory factory : factories) {// 判断是否支持该方法 这里用的DefaultEventListenerFactory spring5.0.8 写死的返回trueif (factory.supportsMethod(method)) {//选择方法 beanName 这里是AddDataEventListener的beanName 默认是addDataEventListenerMethod methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName));// 这里是创建一个ApplicationListenerMethodAdapter对象ApplicationListener<?> applicationListener =factory.createApplicationListener(beanName, targetType, methodToUse);if (applicationListener instanceof ApplicationListenerMethodAdapter) {// 如果是ApplicationListenerMethodAdapter对象 就把context和evaluator传进去((ApplicationListenerMethodAdapter) applicationListener).init(context, this.evaluator);}// 添加到ApplicationListener事件Set集合中去context.addApplicationListener(applicationListener);break;}}}if (logger.isDebugEnabled()) {logger.debug(annotatedMethods.size() + " @EventListener methods processed on bean '" +beanName + "': " + annotatedMethods);}}} } -
后面就是触发事件监听了AbstractApplicationContext#publishEvent
-
@Override public void publishEvent(ApplicationEvent event) {publishEvent(event, null); }protected void publishEvent(Object event, @Nullable ResolvableType eventType) {..............................// Multicast right now if possible - or lazily once the multicaster is initializedif (this.earlyApplicationEvents != null) {this.earlyApplicationEvents.add(applicationEvent);}else {// 进入multicastEventgetApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);}// Publish event via parent context as well...if (this.parent != null) {if (this.parent instanceof AbstractApplicationContext) {((AbstractApplicationContext) this.parent).publishEvent(event, eventType);}else {this.parent.publishEvent(event);}}} -
SimpleApplicationEventMulticaster#multicastEvent->invokeListener->doInvokeListener
-
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {try {listener.onApplicationEvent(event);}catch (ClassCastException ex) {String msg = ex.getMessage();if (msg == null || matchesClassCastMessage(msg, event.getClass().getName())) {// Possibly a lambda-defined listener which we could not resolve the generic event type for// -> let's suppress the exception and just log a debug message.Log logger = LogFactory.getLog(getClass());if (logger.isDebugEnabled()) {logger.debug("Non-matching event type for listener: " + listener, ex);}}else {throw ex;}} } -
ApplicationListenerMethodAdapter#onApplicationEvent]
-
@Override public void onApplicationEvent(ApplicationEvent event) {processEvent(event); } ApplicationListenerMethodAdapter#processEventpublic void processEvent(ApplicationEvent event) {Object[] args = resolveArguments(event);if (shouldHandle(event, args)) {// 执行真正的方法Object result = doInvoke(args);if (result != null) {handleResult(result);}else {logger.trace("No result object given - no result to handle");}} } -
ApplicationListenerMethodAdapter#doInvoke
-
protected Object doInvoke(Object... args) {Object bean = getTargetBean();ReflectionUtils.makeAccessible(this.method);try {return this.method.invoke(bean, args);}catch (IllegalArgumentException ex) {assertTargetBean(this.method, bean, args);throw new IllegalStateException(getInvocationErrorMessage(bean, ex.getMessage(), args), ex);}catch (IllegalAccessException ex) {throw new IllegalStateException(getInvocationErrorMessage(bean, ex.getMessage(), args), ex);}catch (InvocationTargetException ex) {// Throw underlying exceptionThrowable targetException = ex.getTargetException();if (targetException instanceof RuntimeException) {throw (RuntimeException) targetException;}else {String msg = getInvocationErrorMessage(bean, "Failed to invoke event listener method", args);throw new UndeclaredThrowableException(targetException, msg);}} } -
ApplicationListenerMethodAdapter#getTargetBean
-
protected Object getTargetBean() {Assert.notNull(this.applicationContext, "ApplicationContext must no be null");return this.applicationContext.getBean(this.beanName); }
相关文章:
@EventListener注解详细使用(IT枫斗者)
EventListener注解详细使用 简介 EventListener是一种事件驱动编程在spring4.2的时候开始有的,早期可以实现ApplicationListener接口, 为我们提供的一个事件监听、订阅的实现,内部实现原理是观察者设计模式;为的就是业务系统逻辑的解耦,提高…...
[c++17新增语言特性] --- [[nodiscard]]和[[maybe_unused]]
1 [[nodiscard]] 介绍和应用示例 [[nodiscard]] 是C++17引入的一个属性(Attribute),它用于向编译器提示一个函数的返回值应该被检查,避免其被忽略或误用。它可以被用于函数、结构体、类、枚举和 typedef 等声明上,表示如果函数返回值未被使用,或者结构体、类、枚举和 type…...
Centos7安装和使用docker的笔记
最近项目要求用容器部署,所以需要将docker的用法搞清楚,在操作过程中,积累了一些操作方法和技巧,作为笔记,为后面使用做个参考。 首先安装docker需要给centos增加源(参考https://www.runoob.com/docker/cen…...
结构像与功能像
导读现代神经成像技术使我们能够研究活体大脑的结构和功能。活体神经成像的益处是显而易见的,而且在基础和临床神经科学中,神经成像已经取得了巨大进展。本文概述了利用活体神经成像研究大脑结构和功能的工作和成就。介绍了几种不同类型的结构MRI成像方法…...
【IAR工程】STM8S基于ST标准库读取DS1302数据
【IAR工程】STM8S基于ST标准库读取DS1302数据✨申明:本文章仅发表在CSDN网站,任何其他网站,未注明来源,见此内容均为盗链和爬取,请多多尊重和支持原创!🍁对于文中所提供的相关资源链接将作不定期更换。&…...
【SpringBoot】实现后端服务器发送QQ邮件验证码的功能
步骤一、添加邮件相关依赖二、配置邮件服务器三、发送邮件PS:SMTP 发送失败的解决方案一、添加邮件相关依赖 在 pom.xml 文件中添加 JavaMail 和 Spring Mail 相关的依赖。示例代码如下: <dependency><groupId>com.sun.mail</groupId&g…...
vue在input中输入后,按回车,提交数据
vue在input中输入后,按回车,提交数据 1.展示效果如下: 2.代码展示: <div><el-input v-model"toAddNameText" keyup.enter.native"toAddName()" placeholder"回车,即新增该竖杆名称…...
【YOLOX】用YOLOv5框架YOLOX
【YOLOX】用YOLOv5框架YOLOX一、新建common_x.py二、修改yolo.py三、新建yolox.yaml四、训练最近在跑YOLO主流框架的对比实验,发现了一个很奇怪的问题,就是同一个数据集,在不同YOLO框架下训练出的结果差距竟然大的离谱。我使用ultralytics公司…...
【python机器学习实验】——逻辑回归与感知机进行线性分类,附可视化结果!
【python机器学习实验】——逻辑回归与感知机进行线性分类,附可视化结果! 下载链接 下载链接 下载链接 可视化效果图: 感知机模型结果为例: 首先,我们有训练数据和测试数据,其每一行为(x,y,label)的形式…...
wps删除的文件怎么恢复
在办公中,几乎每个人都会用到WPS办公软件。它可以帮助我们快速有效地处理各种Word文档、ppt幻灯片、excel表格等。但有文件就会有清理,如果我们不小心删除了wps文件呢?那些wps删除的文件怎么恢复?针对这种情况,小编为大家带来一些恢复WPS文…...
NIO消息黏包和半包处理
1、前言 我们在进行NIO编程时,通常会使用缓冲区进行消息的通信(ByteBuffer),而缓冲区的大小是固定的。那么除非你进行自动扩容(Netty就是这么处理的),否则的话,当你的消息存进该缓冲…...
day018 第六章 二叉树 part05
一、513.找树左下角的值 这个题目的主要思路是使用广度优先搜索(BFS)遍历整棵树,最后返回最后一层的最左边的节点的值。具体的实现可以使用队列来存储每一层的节点,并且在遍历每一层节点时,不断更新最左边的节点的值。…...
如何下载ChatGPT-ChatGPT如何写作
CHATGPT能否改一下文章 ChatGPT 作为一种自然语言处理技术,生成的文章可能存在表达不够准确或文风不符合要求等问题。在这种情况下,可以使用编辑和修改来改变输出的文章,使其符合特定的要求和期望。 具体来说,可以采用以下步骤对…...
微策略再次买入
原创:刘教链* * *隔夜,比特币再次小幅回升至28k上方。微策略(Microstrategy)创始人Michael Saylor发推表示,微策略再次出手,买入1045枚比特币。此次买入大概花费2930万美元,平均加仓成本28016美…...
express框架
Express 是基于 Node.js 平台,快速、开放、极简的 Web 开发框架. 创建一个基本的express web服务器 // 1.导入express const express require(express); // 2.创建web服务器 const app express(); // 3.启动web服务器 app.listen(80, ()>{console.log(expres…...
完蛋的goals
...
Javase学习文档------面象对象初探
引入面向对象 面向对象的由来: 面向对象编程(Object-Oriented Programming, OOP)是一种编程范型,其由来可以追溯到20世纪60年代。在此之前,主流编程语言采用的是“过程化编程”模式,即面向过程编程模式。在这种模式下&…...
ChatGPT能够干翻谷歌吗?
目前大多数人对于ChatGPT的喜爱,主要源自于其强大的沟通能力,当我们向ChatGPT提出问题时,它不仅能够为我们提供结论,而且还能够与我们建立沟通,向ChatGPT提出任何问题,感觉都像是在与一个真实的人类进行交谈…...
PCL 使用点云创建数字高程模型DEM
目录 一、DEM1、数字高程模型二、代码实现三、结果展示1、点云2、DEM四、相关链接一、DEM 1、数字高程模型 数字高程模型(Digital Elevation Model),简称DEM,是通过有限的地形高程数据实现对地面地形的数字化模拟(即地形表面形态的数字化表达),它是用一组有序数值阵列形…...
我体验了首个接入GPT-4的代码编辑器,太炸裂了
最近一款名为Cursor的代码编辑器已经传遍了圈内,受到众多编程爱好者的追捧。 它主打的亮点就是,通过 GPT-4 来辅助你编程,完成 AI 智能生成代码、修改 Bug、生成测试等操作。 确实很吸引人,而且貌似也能大大节省人为的重复工作&…...
从钟形曲线到假设检验:用Python可视化带你理解正态分布在数据分析中的实际应用
从钟形曲线到假设检验:用Python可视化理解正态分布的核心价值 第一次接触统计学时,我被那些复杂的公式和抽象概念搞得晕头转向。直到有一天,导师在咖啡杯旁画了一条钟形曲线:"看,这就是正态分布——它像不像我们部…...
OpenClaw成本优化方案:ollama GLM-4-7-Flash替代OpenAI API实测
OpenClaw成本优化方案:ollama GLM-4-7-Flash替代OpenAI API实测 1. 为什么需要寻找OpenAI API的替代方案 去年我开始在个人项目中使用OpenClaw实现自动化办公流程时,很快被OpenAI API的token消耗速度震惊了。一个简单的"读取邮件附件-解析内容-生…...
3步打造你的专属阅读系统:开源工具如何重构数字阅读体验
3步打造你的专属阅读系统:开源工具如何重构数字阅读体验 【免费下载链接】legado-Harmony 开源阅读鸿蒙版仓库 项目地址: https://gitcode.com/gh_mirrors/le/legado-Harmony 你是否曾遇到这样的困扰:阅读APP充斥广告弹窗、书源受限无法找到心仪内…...
精益生产方式的核心功能拆解:精益生产方式如何解决多品种小批量场景下的库存积压难题
在当前制造业从“少品种大批量”向“多品种小批量”急剧转型的背景下,精益生产方式已成为企业打破库存僵局的唯一出路,它通过准时化拉动和消除浪费的核心逻辑,精准解决了传统模式下因预测失效导致的严重库存积压问题;面对多变的订…...
ADS 2025瞬态仿真实战:手把手教你搞定PCB微带线串扰分析(含变量单位避坑指南)
ADS 2025瞬态仿真实战:手把手教你搞定PCB微带线串扰分析(含变量单位避坑指南) 作为一名硬件工程师,在高速PCB设计中遇到串扰问题就像在迷宫里寻找出口——看似简单却处处暗藏陷阱。特别是当你在ADS 2025中按照教程一步步设置参数&…...
【AI工程化硬核考点】:FastAPI 2.0 + async/await + StreamingResponse三重协程调度机制精讲
第一章:FastAPI 2.0 异步 AI 流式响应 面试题汇总FastAPI 2.0 原生强化了对异步流式响应(StreamingResponse)的支持,尤其适用于大语言模型(LLM)推理、实时日志推送、AI 生成内容分块返回等场景。面试官常聚…...
RWKV7-1.5B-g1a惊艳案例:将复杂段落压缩为三条逻辑闭环要点
RWKV7-1.5B-g1a惊艳案例:将复杂段落压缩为三条逻辑闭环要点 1. 模型能力展示:从复杂到简洁的文本处理 RWKV7-1.5B-g1a作为一款轻量级文本生成模型,在信息压缩和提炼方面展现出令人惊喜的能力。我们通过一个实际案例来展示它如何将复杂内容转…...
GTE文本向量助力智能写作:文本分类与情感倾向双重把关
GTE文本向量助力智能写作:文本分类与情感倾向双重把关 1. 智能写作的核心挑战:内容质量的多维评估 在内容创作领域,我们常常面临一个基本矛盾:如何同时保证文本的专业性和情感表达?传统写作辅助工具往往只能解决单一…...
对话意图识别新选择:轻量ESFT模型高效易用
对话意图识别新选择:轻量ESFT模型高效易用 【免费下载链接】ESFT-token-intent-lite 基于HuggingFace平台,deepseek-ai团队推出的ESFT-token-intent-lite模型,是ESFT-vanilla-lite的精简版,专为意图识别优化,性能卓越&…...
文艺复兴,什么是XSS,常见形式(二)
前言 本文将继续介绍XSS的常见形状,依赖于portswigger提供的免费Lab环境,将重点介绍关于使用脚本来进行表单XSS验证以及针对标签的模糊测试。 Lab: Stored DOM XSS 这是一个存储型的DOM类的XSS,具体的是当你将内容提交到评论区,…...
