Springboot之监听器
Springboot之事件监听器
- 事件监听的几种方式
- 1 方式一:实现接口
- 1.1 创建事件
- 1.2 创建事件监听器
- 1.3 发布事件
- 2 方式二:注解方式
- 2.1 创建事件
- 2.1.1 创建发送邮件事件
- 2.1.2 创建发送短信事件
- 2.2 创建事件监听器
- 2.3 发布事件
- 2.4 事件异步处理(方式二有效)
- 2.4.1 配置线程池
- 2.4.2 设置事件执行的线程池
- 3 项目使用案例
- 3.1 创建事件父类
- 3.2 创建监听器接口
- 3.3 创建事件监听器管理类
- 3.4 创建事件监听器的简单实现
- 3.5 创建用户注册事件
- 3.6 创建用户注册服务
- 3.7 创建事件监听配置类
- 3.8 创建发送邮件服务
- 3.9 创建发送短信服务
- 3.10 调用用户注册服务
- 3.11 调用赠送优惠券服务(扩展)
- 4 事件异步处理
- 4.1 启动类开启异步
- 4.2 创建线程池
- 4.3 事件方法开启异步
- 4.4 修改事件类型的获取方式
- 5 拓展
- 5.1 控制发送邮件、短信、优惠券服务的执行顺序
事件监听的几种方式
1 方式一:实现接口
场景:用户注册成功后,给用户赠送100元优惠券
1.1 创建事件
实现ApplicationEvent接口
package com.per.listener.e1;import com.per.domain.UserDto;
import org.springframework.context.ApplicationEvent;/*** @Title DemoEvent1* @ProjectName spring-boot-demo* @Description TODO* @Author Lee* @Date 2024-01-17*/
public class UserEvent extends ApplicationEvent {/*** 事件源*/private UserDto userDto;public UserEvent(UserDto userDto) {super(userDto);this.userDto = userDto;}/*** 获取事件中的用户信息** @return*/public UserDto getUserDto() {return userDto;}
}
1.2 创建事件监听器
实现ApplicationListener接口,重写onApplicationEvent方法
package com.per.listener.e1;import com.per.domain.UserDto;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;/*** @Title UserListener* @ProjectName spring-boot-demo* @Description TODO* @Author Lee* @Date 2024-01-17*/
@Slf4j
@Component
public class UserListener implements ApplicationListener<UserEvent> {@Overridepublic void onApplicationEvent(UserEvent event) {log.info("UserListener#onApplicationEvent 事件监听 开始执行...");UserDto userDto = event.getUserDto();// 给用户发优惠券log.info("给用户{}发送100元优惠卷", userDto.getName());}
}
1.3 发布事件
引入ApplicationContext,调用publishEvent方法发布事件
package com.per.service.impl;import com.per.domain.UserDto;
import com.per.listener.e1.UserEvent;
import com.per.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;/*** @Title UserServiceImpl* @ProjectName spring-boot-demo* @Description TODO* @Author Lee* @Date 2024-01-17*/
@Service
@Slf4j
public class UserServiceImpl implements UserService {@Autowiredprivate ApplicationContext applicationContext;@Overridepublic String userRegister(UserDto userDto) {log.info("用户{}注册成功,注册信息: {}", userDto.getName(), userDto.toString());// 发送优惠券UserEvent userEvent = new UserEvent(userDto);applicationContext.publishEvent(userEvent);return String.format("用户%s注册成功,并赠送了100元优惠券", userDto.getName());}
}
2 方式二:注解方式
场景:用户注册成功后,给用户发送邮件、短信通知
2.1 创建事件
继承ApplicationEvent,重写事件构造方法
2.1.1 创建发送邮件事件
package com.per.listener.e2;import org.springframework.context.ApplicationEvent;/*** @Title SendMailEvent 发送邮件事件* @ProjectName spring-boot-demo* @Description TODO* @Author Lee* @Date 2024-01-17*/
public class SendMailEvent extends ApplicationEvent {public SendMailEvent(Object source) {super(source);}}
2.1.2 创建发送短信事件
package com.per.listener.e2;import org.springframework.context.ApplicationEvent;/*** @Title SendShortMsg 发送短信事件* @ProjectName spring-boot-demo* @Description TODO* @Author Lee* @Date 2024-01-17*/
public class SendMsgEvent extends ApplicationEvent {public SendMsgEvent(Object source) {super(source);}
}
2.2 创建事件监听器
定义事件执行的方法,使用注解@EventListener标注方法,使用classes属性指定方法对应的事件
package com.per.listener.e2;import com.per.domain.UserDto;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;/*** @Title UserE2Listener* @ProjectName spring-boot-demo* @Description TODO* @Author Lee* @Date 2024-01-17*/
@Component
@Slf4j
public class UserE2Listener {/*** 发送邮件* @param sendMailEvent 发送邮件事件*/@EventListener(classes = SendMailEvent.class)@Order(1)public void sendMail(SendMailEvent sendMailEvent){UserDto userDto = (UserDto) sendMailEvent.getSource();log.info("发送邮件给用户{} ...【邮件】恭喜你注册成功", userDto.getName());}/*** 发送短信* @param sendMsgEvent 发送短信事件*/@EventListener(classes = SendMsgEvent.class)@Order(2)public void sendMsg(SendMsgEvent sendMsgEvent){UserDto userDto = (UserDto) sendMsgEvent.getSource();log.info("发送短信给用户{} ...【短信】恭喜你注册成功", userDto.getName());}}
2.3 发布事件
引入ApplicationEventPublisher,调用publishEvent方法发布事件
package com.per.service.impl;import com.per.domain.UserDto;
import com.per.listener.e2.SendMailEvent;
import com.per.listener.e2.SendMsgEvent;
import com.per.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;/*** @Title UserServiceImpl* @ProjectName spring-boot-demo* @Description TODO* @Author Lee* @Date 2024-01-17*/
@Service
@Slf4j
public class UserServiceImpl implements UserService {@Autowiredprivate ApplicationEventPublisher publisher;@Overridepublic String userRegister1(UserDto userDto) {log.info("用户{}注册成功,注册信息: {}", userDto.getName(), userDto.toString());// 发送邮件SendMailEvent sendMailEvent = new SendMailEvent(userDto);publisher.publishEvent(sendMailEvent);// 发送短息SendMsgEvent sendMsgEvent = new SendMsgEvent(userDto);publisher.publishEvent(sendMsgEvent);return String.format("用户%s注册成功,并发送邮件和短信通知", userDto.getName());}}
2.4 事件异步处理(方式二有效)
2.4.1 配置线程池
package com.per.listener.e3.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;/*** @Title ThreadPoolConfig* @Description TODO* @Author Lee* @Date 2024-01-20*/
@Configuration
public class ThreadPoolConfig {@Bean("eventListenerThreadPool")public Executor taskExecutor() {ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();taskExecutor.setCorePoolSize(5);taskExecutor.setMaxPoolSize(10);taskExecutor.setKeepAliveSeconds(60);taskExecutor.setQueueCapacity(50);taskExecutor.setThreadNamePrefix("myExecutor--");taskExecutor.setWaitForTasksToCompleteOnShutdown(true);taskExecutor.setAwaitTerminationSeconds(60);taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());taskExecutor.initialize();return taskExecutor;}}
2.4.2 设置事件执行的线程池
package com.per.listener.e3.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ApplicationEventMulticaster;
import org.springframework.context.event.SimpleApplicationEventMulticaster;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;import javax.annotation.Resource;/*** @Title EventListenerAsynConfig* @Description TODO* @Author Lee* @Date 2024-01-20*/
@Configurationpublic class EventListenerAsyncConfig {@Resourceprivate ThreadPoolTaskExecutor eventListenerThreadPool;@Beanpublic ApplicationEventMulticaster applicationEventMulticaster() {SimpleApplicationEventMulticaster eventMulticaster = new SimpleApplicationEventMulticaster();eventMulticaster.setTaskExecutor(eventListenerThreadPool);return eventMulticaster;}
}
3 项目使用案例
场景:用户注册成功,给用户发送邮件、短信通知
3.1 创建事件父类
package com.per.listener.e3.event;/*** @Title AbstractEvent 所有事件父类* @ProjectName spring-boot-demo* @Description TODO* @Author Lee* @Date 2024-01-17*/
public abstract class AbstractEvent {/*** 事件源*/protected Object source;public AbstractEvent(Object source) {this.source = source;}/*** 获取事件源** @return*/public Object getSource() {return source;}/*** 设置事件源** @param source*/public void setSource(Object source) {this.source = source;}
}
3.2 创建监听器接口
package com.per.listener.e3.listener;import com.per.listener.e3.event.AbstractEvent;/*** @Title EventListener 事件监听器接口* @ProjectName spring-boot-demo* @Description TODO* @Author Lee* @Date 2024-01-17*/
public interface EventListener<E extends AbstractEvent> {/*** 处理事件** @param event 要处理的事件*/void onEvent(E event);
}
3.3 创建事件监听器管理类
package com.per.listener.e3.listener;import com.per.listener.e3.event.AbstractEvent;/*** @Title EventListenerManager 事件监听器管理类* @ProjectName spring-boot-demo* @Description 1.负责事件监听器的管理(注册监听器&移除监听器,将事件和监听器关联起来)* 2.负责事件的广播(将事件广播给所有的监听器,对该事件感兴趣的监听器会处理该事件)* @Author Lee* @Date 2024-01-17*/
public interface EventListenerManager {/*** 广播事件给所有监听器** @param event 事件*/void pushEvent(AbstractEvent event);/*** 添加一个事件监听器** @param listener 事件监听器*/void addListener(EventListener<?> listener);/*** 删除一个事件监听器** @param listener 事件监听器*/void removeListener(EventListener<?> listener);
}
3.4 创建事件监听器的简单实现
package com.per.listener.e3.listener.impl;import com.per.listener.e3.event.AbstractEvent;
import com.per.listener.e3.listener.EventListener;
import com.per.listener.e3.listener.EventListenerManager;import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;/*** @Title SimpleEventListener 事件广播器的简单实现* @Description TODO* @Author Lee* @Date 2024-01-17*/
public class SimpleEventListener implements EventListenerManager {private Map<Class<?>, List<EventListener>> eventListenerMap = new ConcurrentHashMap<>();@Overridepublic void pushEvent(AbstractEvent event) {List<EventListener> eventListeners = this.eventListenerMap.get(event.getClass());if (eventListeners != null) {for (EventListener eventListener : eventListeners) {// 执行事件eventListener.onEvent(event);}}}@Overridepublic void addListener(EventListener<?> listener) {Class<?> eventType = this.getEventType(listener);// 查询map中事件对应的监听器List<EventListener> eventListeners = this.eventListenerMap.get(eventType);if (eventListeners == null) {// 事件对应的监听器集合为空,保存事件和监听器到map中,key:事件 value:空的监听器集合eventListeners = new ArrayList<>();this.eventListenerMap.put(eventType, eventListeners);}// 事件对应的监听器集合不为空,添加监听器到事件对应的监听器集合中eventListeners.add(listener);}@Overridepublic void removeListener(EventListener<?> listener) {Class<?> eventType = this.getEventType(listener);// 查询map中事件对应的监听器List<EventListener> eventListeners = this.eventListenerMap.get(eventType);if (eventListeners != null) {// 事件对应的监听器集合不为空,从事件对应的监听器集中删除当前监听eventListeners.remove(listener);}}protected Class<?> getEventType(EventListener eventListener) {// 获取直接实现eventListener接口的类或接口的Type// 异步@Async时使用这种方式获取
// ParameterizedType parameterizedType = (ParameterizedType)eventListener.getClass().getSuperclass().getGenericInterfaces()[0];// 同步时使用这种方式获取ParameterizedType parameterizedType = (ParameterizedType) eventListener.getClass().getGenericInterfaces()[0];// 获取EventListener中泛型的实际类型Type eventType = parameterizedType.getActualTypeArguments()[0];return (Class<?>) eventType;}
}
3.5 创建用户注册事件
package com.per.listener.e3.event;import com.per.domain.UserDto;/*** @Title RegisterSuccessEvent 用户注册成功事件* @Description TODO* @Author Lee* @Date 2024-01-17*/
public class RegisterSuccessEvent extends AbstractEvent {/*** 用户信息*/private UserDto userDto;/*** 用户注册成功事件** @param source 事件源* @param userDto 用户信息*/public RegisterSuccessEvent(Object source, UserDto userDto) {super(source);this.userDto = userDto;}public UserDto getUserDto() {return userDto;}public void setUserDto(UserDto userDto) {this.userDto = userDto;}
}
3.6 创建用户注册服务
package com.per.service.impl;import com.per.domain.UserDto;
import com.per.listener.e3.event.RegisterSuccessEvent;
import com.per.listener.e3.listener.EventListenerManager;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;/*** @Title UserRegisterService 用户注册成功服务* @Description TODO* @Author Lee* @Date 2024-01-17*/
@Slf4j
public class UserRegisterService {/*** 事件发布者*/@Autowiredprivate EventListenerManager eventListenerManager;/*** 用户注册** @param userDto 用户信息*/public void registerUser(UserDto userDto) {log.info("用户{}注册成功", userDto.getName());// 执行其他监听事件this.eventListenerManager.pushEvent(new RegisterSuccessEvent(this, userDto));}public EventListenerManager getEventListenerManager() {return eventListenerManager;}public void setEventListenerManager(EventListenerManager eventListenerManager) {this.eventListenerManager = eventListenerManager;}
}
3.7 创建事件监听配置类
package com.per.listener.e3.config;import com.per.listener.e3.listener.EventListener;
import com.per.listener.e3.listener.EventListenerManager;
import com.per.listener.e3.listener.impl.SimpleEventListener;
import com.per.service.impl.UserRegisterService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;import java.util.List;/*** @Title EventListenerConfig* @Description TODO* @Author Lee* @Date 2024-01-17*/
@Configuration
@Component
public class EventListenerConfig {/*** 注册一个事件发布者** @param eventListeners 事件* @return*/@Bean@Autowired(required = false) // 当eventListeners不存在时不抛出异常public EventListenerManager eventListenerManager(List<EventListener> eventListeners) {EventListenerManager eventListenerManager = new SimpleEventListener();if (eventListeners != null) {eventListeners.forEach(eventListener -> eventListenerManager.addListener(eventListener));}return eventListenerManager;}/*** 注册一个用户注册服务** @param eventListenerManager* @return*/@Beanpublic UserRegisterService userRegisterService(EventListenerManager eventListenerManager) {UserRegisterService userRegisterService = new UserRegisterService();userRegisterService.setEventListenerManager(eventListenerManager);return userRegisterService;}
}
3.8 创建发送邮件服务
package com.per.service.impl;import com.per.listener.e3.event.RegisterSuccessEvent;
import com.per.listener.e3.listener.EventListener;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;/*** @Title UserSendMailService 用户发送邮件服务* @Description TODO* @Author Lee* @Date 2024-01-17*/
@Component
@Slf4j
public class UserSendMailService implements EventListener<RegisterSuccessEvent> {@Overridepublic void onEvent(RegisterSuccessEvent event) {log.info("给用户{}发送邮件,内容:恭喜你注册成功", event.getUserDto().getName());}
}
3.9 创建发送短信服务
package com.per.service.impl;import com.per.listener.e3.event.RegisterSuccessEvent;
import com.per.listener.e3.listener.EventListener;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;/*** @Title UserSendMsgService 用户发送短信服务* @Description TODO* @Author Lee* @Date 2024-01-17*/
@Component
@Slf4j
public class UserSendMsgService implements EventListener<RegisterSuccessEvent> {@Overridepublic void onEvent(RegisterSuccessEvent event) {log.info("给用户{}发送短息,短信内容:恭喜你注册成功", event.getUserDto().getName());}
}
3.10 调用用户注册服务
/*** 用户注册成功后发送邮件、发送短信** @return*/@RequestMapping(value = "register", method = RequestMethod.GET)public String register() {UserDto userDto = new UserDto(11, "李四", "男");userRegisterService.registerUser(userDto);return "SUCCESS";}
3.11 调用赠送优惠券服务(扩展)
新增场景:增加一个赠送优惠券业务
package com.per.service.impl;import com.per.listener.e3.event.RegisterSuccessEvent;
import com.per.listener.e3.listener.EventListener;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;/*** @Title SendUserCouponsService 发送优惠券服务* @Description TODO* @Author Lee* @Date 2024-01-20*/
@Component
@Slf4j
@Order(3)
public class SendUserCouponsService implements EventListener<RegisterSuccessEvent> {@Overridepublic void onEvent(RegisterSuccessEvent event) {log.info("给用户{}发送100元优惠券", event.getUserDto().getName());}
}
4 事件异步处理
注意:下面的修改皆基于3 项目使用案例修改
4.1 启动类开启异步
package com.per;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;@SpringBootApplication
@EnableAsync(proxyTargetClass = true)
public class SpringBootDemoApplication {public static void main(String[] args) {SpringApplication.run(SpringBootDemoApplication.class, args);}}
4.2 创建线程池
参考 2.4.1 配置线程池
4.3 事件方法开启异步
@Component
@Slf4j
@Order(1)
public class UserSendMailService implements EventListener<RegisterSuccessEvent> {@Async("eventListenerThreadPool")@Overridepublic void onEvent(RegisterSuccessEvent event) {log.info("{}-给用户{}发送邮件,内容:恭喜你注册成功", Thread.currentThread().getName(), event.getUserDto().getName());}
}@Component
@Slf4j
@Order(2)
public class UserSendMsgService implements EventListener<RegisterSuccessEvent> {@Async("eventListenerThreadPool")@Overridepublic void onEvent(RegisterSuccessEvent event) {log.info("{}--给用户{}发送短息,短信内容:恭喜你注册成功", Thread.currentThread().getName(), event.getUserDto().getName());}
}@Component
@Slf4j
@Order(3)
public class SendUserCouponsService implements EventListener<RegisterSuccessEvent> {@Async("eventListenerThreadPool")@Overridepublic void onEvent(RegisterSuccessEvent event) {log.info("{}--给用户{}发送100元优惠券", Thread.currentThread().getName(), event.getUserDto().getName());}
}
4.4 修改事件类型的获取方式
参考 3.4 创建事件监听器的简单实现
5 拓展
5.1 控制发送邮件、短信、优惠券服务的执行顺序
可以通过@Order控制服务的加载顺序实现
相关文章:
Springboot之监听器
Springboot之事件监听器 事件监听的几种方式1 方式一:实现接口1.1 创建事件1.2 创建事件监听器1.3 发布事件 2 方式二:注解方式2.1 创建事件2.1.1 创建发送邮件事件2.1.2 创建发送短信事件 2.2 创建事件监听器2.3 发布事件2.4 事件异步处理(方…...
【02】mapbox js api加载arcgis切片服务
需求: 第三方的mapbox js api加载arcgis切片服务,同时叠加在mapbox自带底图上 效果图: 形如这种地址去加载: http://zjq2022.gis.com:8080/demo/loadmapbox.html arcgis切片服务参考链接思路:【01】mapbox js api加…...
Vue四个阶段,八个钩子函数
- 创造阶段:创建Vue实例和初始化数据事件,数据代理,监测watch - beforeCreate,只是创建实例,不能this.$el,this.msg,this.方法名() - created,数据代理了,能v…...
rancher和k8s接口地址,Kubernetes监控体系,cAdvisor和kube-state-metrics 与 metrics-server
为了能够提前发现kubernetes集群的问题以及方便快捷的查询容器的各类参数,比如,某个pod的内存使用异常高企 等等这样的异常状态(虽然kubernetes有自动重启或者驱逐等等保护措施,但万一没有配置或者失效了呢)࿰…...
idea编译打包前端vue项目
网上download了一个前端vue项目 第一次接触前端记录一下编译打包遇到的问题 1、idea前端项目打包一般是依赖 <groupId>org.codehaus.mojo</groupId> <artifactId>exec-maven-plugin</artifactId> <version>3.0…...
Unity中URP下的 额外灯 逐像素光 和 逐顶点光
文章目录 前言一、额外灯 的 逐像素灯 和 逐顶点灯1、存在额外灯的逐像素灯2、存在额外灯的逐顶点灯 二、测试这两个宏的作用1、额外灯的逐像素灯2、额外灯的逐顶点灯 前言 在之前的文章中,我们了解了 主光相关的反射计算。 Unity中URP下的SimpleLit的 Lambert漫反…...
《WebKit 技术内幕》学习之五(2): HTML解释器和DOM 模型
2.HTML 解释器 2.1 解释过程 HTML 解释器的工作就是将网络或者本地磁盘获取的 HTML 网页和资源从字节流解释成 DOM 树结构。 这一过程中,WebKit 内部对网页内容在各个阶段的结构表示。 WebKit 中这一过程如下:首先是字节流,经过解码之…...
Redis实战之-分布式锁-redission
一、分布式锁-redission功能介绍 基于setnx实现的分布式锁存在下面的问题: 重入问题:重入问题是指 获得锁的线程可以再次进入到相同的锁的代码块中,可重入锁的意义在于防止死锁,比如HashTable这样的代码中,他的方法都…...
离线数据仓库-关于增量和全量
数据同步策略 数据仓库同步策略概述一、数据的全量同步二、数据的增量同步三、数据同步策略的选择 数据仓库同步策略概述 应用系统所产生的业务数据是数据仓库的重要数据来源,我们需要每日定时从业务数据库中抽取数据,传输到数据仓库中,之后…...
09 STM32 - PWM
9.1 PWM简介 脉冲宽度调制(Pulse Width Modulation,简称PWM),是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术。简单一点,就是对脉冲宽度的控制。 9.2 PWM波原理 如下图所示,使用定时器定时,从0开始&#x…...
三勾点餐系统java+springboot+vue3,开源系统小程序点餐系统
项目简述 前台实现:用户浏览菜单、菜品分类筛选、查看菜品详情、菜品多属性、菜品加料、添加购物车、购物车结算、个人订单查询、门店自提、外卖配送、菜品打包等。 后台实现:菜品管理、订单管理、会员管理、系统管理、权限管理等。 项目介绍 三勾点…...
《WebKit 技术内幕》学习之五(1): HTML解释器和DOM 模型
第五章 HTML 解释器和 DOM 模型 1.DOM 模型 1.1 DOM标准 DOM (Document Object Model)的全称是文档对象模型,它可以以一种独立于平台和语言的方式访问和修改一个文档的内容和结构。这里的文档可以是 HTML 文档、XML 文档或者 XHTML 文档。D…...
小程序学习-21
目前小程序分包大小有以下限制: 整个小程序所有分包大小不超过 20M单个分包/主包大小不能超过 2M 独立分包:"independent": true...
Spring第七天(AOP)
简介 AOP(Aspect Oriented Programing)面向切面编程,一种编程范式,指导开发者如何组织程序结构 作用 在不惊动原始设计的基础上为其进行功能增强 Spring理念:无入侵式/无侵入式 基本概念 连接点(JoinPoint) : 程序执行过程中的任意位置&a…...
【0247】PG内核checkpoint实现机制分析(2)
文章目录 1. 前言2. checkpoint2.1 checkpoint工作机制2.2 项目实战3. 故障恢复(recovery)3.1 故障模拟3.2 规章恢复相关文章:...
单例模式分享
Java的单例模式详解与案例解析 单例模式是一种常见的设计模式,它确保一个类只有一个实例,并提供一个全局访问点。在Java中,实现单例模式有多种方式,我们将深入讨论其中的几种,并通过丰富的案例演示它们的用法。 1. 饿…...
Linux查找日志常用命令
tail tail命令常使用选项-f -f, --follow[{name|descriptor}]output appended data as the file grows;an absent option argument means descriptor例如: tail -1000f sys.log按回车键增加空白行,按Ctrl C 结束 vi / vim vi 文件名 如:…...
中国国际光伏展
中国国际光伏展是一个专注于光伏技术和行业的展览会。该展览会每年在中国举办,吸引了来自全球各地的光伏企业、专业人士和观众参加。 中国国际光伏展展览的主要内容包括光伏组件、光伏电池、光伏逆变器、光伏并网系统、光伏材料、光伏维护和管理等。展览会同时举办一…...
openai assistants api接入微信机器人,实现类GPTs功能
chatgpt网址:https://chat.xutongbao.top 比普通gpt多了代码解释器功能,和上传训练数据文件的功能,这两个功能就是GPTs拥有的,而普通gpt没有拥有的...
性能优化-OpenCL kernel 开发
「发表于知乎专栏《移动端算法优化》」 本文主要介绍OpenCL的 Kernel,包括代码的实例以及使用注意的详解。 🎬个人简介:一个全栈工程师的升级之路! 📋个人专栏:高性能(HPC)开发基础教…...
docker详细操作--未完待续
docker介绍 docker官网: Docker:加速容器应用程序开发 harbor官网:Harbor - Harbor 中文 使用docker加速器: Docker镜像极速下载服务 - 毫秒镜像 是什么 Docker 是一种开源的容器化平台,用于将应用程序及其依赖项(如库、运行时环…...
大话软工笔记—需求分析概述
需求分析,就是要对需求调研收集到的资料信息逐个地进行拆分、研究,从大量的不确定“需求”中确定出哪些需求最终要转换为确定的“功能需求”。 需求分析的作用非常重要,后续设计的依据主要来自于需求分析的成果,包括: 项目的目的…...
golang循环变量捕获问题
在 Go 语言中,当在循环中启动协程(goroutine)时,如果在协程闭包中直接引用循环变量,可能会遇到一个常见的陷阱 - 循环变量捕获问题。让我详细解释一下: 问题背景 看这个代码片段: fo…...
Java 8 Stream API 入门到实践详解
一、告别 for 循环! 传统痛点: Java 8 之前,集合操作离不开冗长的 for 循环和匿名类。例如,过滤列表中的偶数: List<Integer> list Arrays.asList(1, 2, 3, 4, 5); List<Integer> evens new ArrayList…...
跨链模式:多链互操作架构与性能扩展方案
跨链模式:多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈:模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展(H2Cross架构): 适配层…...
Linux-07 ubuntu 的 chrome 启动不了
文章目录 问题原因解决步骤一、卸载旧版chrome二、重新安装chorme三、启动不了,报错如下四、启动不了,解决如下 总结 问题原因 在应用中可以看到chrome,但是打不开(说明:原来的ubuntu系统出问题了,这个是备用的硬盘&a…...
WordPress插件:AI多语言写作与智能配图、免费AI模型、SEO文章生成
厌倦手动写WordPress文章?AI自动生成,效率提升10倍! 支持多语言、自动配图、定时发布,让内容创作更轻松! AI内容生成 → 不想每天写文章?AI一键生成高质量内容!多语言支持 → 跨境电商必备&am…...
Docker 本地安装 mysql 数据库
Docker: Accelerated Container Application Development 下载对应操作系统版本的 docker ;并安装。 基础操作不再赘述。 打开 macOS 终端,开始 docker 安装mysql之旅 第一步 docker search mysql 》〉docker search mysql NAME DE…...
无人机侦测与反制技术的进展与应用
国家电网无人机侦测与反制技术的进展与应用 引言 随着无人机(无人驾驶飞行器,UAV)技术的快速发展,其在商业、娱乐和军事领域的广泛应用带来了新的安全挑战。特别是对于关键基础设施如电力系统,无人机的“黑飞”&…...
纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join
纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join 1、依赖1.1、依赖版本1.2、pom.xml 2、代码2.1、SqlSession 构造器2.2、MybatisPlus代码生成器2.3、获取 config.yml 配置2.3.1、config.yml2.3.2、项目配置类 2.4、ftl 模板2.4.1、…...
