当前位置: 首页 > news >正文

网站如何做宣传自治区住房和城乡建设厅官网

网站如何做宣传,自治区住房和城乡建设厅官网,企业文化墙素材图片,前端最难学的是哪部分1.概述 在我们平时的项目业务系统开发过程中#xff0c;一个需求功能的业务逻辑经常出现主线业务和副线业务之分。比如#xff0c;在当下移动端电商app进行注册账号操作#xff0c;注册成功之后会发送短信、邮箱、站内信等通知#xff0c;发放红包活动抵用券#xff0c;推…1.概述 在我们平时的项目业务系统开发过程中一个需求功能的业务逻辑经常出现主线业务和副线业务之分。比如在当下移动端电商app进行注册账号操作注册成功之后会发送短信、邮箱、站内信等通知发放红包活动抵用券推送用户注册信息给大数据系统进行数据分析以便后期个性化推荐等等。由此看出一个注册接口代码逻辑需要干这么多事情业余逻辑高度耦合并且串行执行耗时严重所以我们接下来将围绕如何解决这两个问题进行叙述。串行执行耗时这个问题只需要改成异步也就是主线逻辑注册成功之后接口就可以返回而剩下的副线业务逻辑异步执行即可说到异步解耦我想很多同学就想到了消息队列MQ因为其一大核心作用就是异步解耦不过消息队列中间件引入系统相对来说是一个比较重的操作而我们这里采取的是今天的主角Spring event来实现业务解耦。 Spring事件Spring Event是Spring框架的一项功能它允许不同组件之间通过发布-订阅机制进行解耦的通信。在Spring中事件是表示应用程序中特定事件的对象例如用户注册、订单创建、数据更新等。当这些事件发生时可以通知其他组件来执行相应的操作。 具体来说Spring事件机制包含以下几个主要的部分 事件Event 事件是一个普通的POJO类用于封装与应用程序状态变化相关的信息。通常情况下事件类继承自ApplicationEvent抽象类Spring中提供了一些内置的事件也可以自定义事件。事件发布者ApplicationEventPublisher 事件发布者是一个接口用于发布事件。在Spring中ApplicationContext就是一个事件发布者可以通过ApplicationContext的publishEvent()方法来发布事件。事件监听器ApplicationListener 事件监听器是一个接口用于监听事件并在事件发生时执行相应的逻辑。在Spring中我们可以通过实现ApplicationListener接口或使用EventListener注解来定义事件监听器。事件监听器注册 事件监听器需要注册到事件发布者ApplicationContext中以便在事件发生时被正确调用。在Spring中通常通过XML配置、注解或者编程方式将事件监听器注册到ApplicationContext中。 2.Spring Event使用示例 2.1 用户注册 下面我就基于用户注册成功之后进行短信邮箱、站内信通知发放红包优惠券推送用户信息给大数据系统进行示例展示 首先先定义一个用户类信息User: Data Builder AllArgsConstructor NoArgsConstructor public class User {private Long id;private String userNo;private String nickname;private String email;private String phone;private Integer gender;private Date birthday;private Integer isDelete; }自定义一个注册事件 getter public class RegisterEvent extends ApplicationEvent {// 携带用户信息private User user;public RegisterEvent(Object source, User user) {super(source);this.user user;} }定义事件监听器 事件监听器有两种实现方式一种是实现ApplicationListener接口另一种是使用EventListener注解。 三个监听器如下所示消息通知和发送红包监听器通过实现ApplicationListener接口 Slf4j Component // 把监听器注册到spring容器中 public class RegisterMsgNoticeListener implements ApplicationListenerRegisterEvent {Overridepublic void onApplicationEvent(RegisterEvent event) {log.info(站内信通知了);log.info(短信通知了);log.info(邮箱通知了);} }Slf4j Component Order(1) public class RegisterSendRedPacketListener implements ApplicationListenerRegisterEvent {SneakyThrowsOverridepublic void onApplicationEvent(RegisterEvent event) {log.info(发放红包了);// 睡眠一下模拟发送优惠券比较复杂TimeUnit.SECONDS.sleep(2);log.info(发放优惠券了);} }使用EventListener实现推送用户信息监听器 Slf4j Component public class RegisterPushDataListener{EventListenerpublic void onApplicationEvent(RegisterEvent event) {log.info(推送用户信息到大数据系统了user{}, event.getUser());} }事件发布 Slf4j Service public class UserServiceImpl implements UserService {Resourceprivate ApplicationContext applicationContext;Overridepublic void registerUser(User user) {log.info(user注册成功了);applicationContext.publishEvent(new RegisterEvent(this, user));} }单元测试用例 SpringBootTest RunWith(SpringRunner.class) public class UserServiceImplTest {Resourceprivate UserService userService;Testpublic void testEvent() {User user User.builder().userNo(1111).birthday(new Date()).gender(0).phone(12345677890).email(shepherd163.com).nickname(芽儿哟).build();userService.registerUser(user);}}执行结果如下 user注册成功了 站内信通知了 短信通知了 邮箱通知了 推送用户信息到大数据系统了userUser(idnull, userNo1111, nickname芽儿哟, emailshepherd163.com, phone12345677890, gender0, birthdayTue Apr 09 17:12:25 CST 2024, isDeletenull) 发放红包了 发放优惠券了 user注册完成结束了如果我们要控制监听器的执行顺序使用Order即可注意如果是实现了ApplicationListener我们把Order放到bean类上即可但如果是通过注解EventListener实现的就必须写到方法上下面就是先执行发送红包优惠券监听器再执行消息通知监听器最后才执行推送用户数据监听器。注意异步的情况下只保证按顺序将监听器丢入进线程池具体事件处理执行顺序是不确定的。 Slf4j Component Order(1) public class RegisterSendRedPacketListener implements ApplicationListenerRegisterEvent {SneakyThrowsOverridepublic void onApplicationEvent(RegisterEvent event) {log.info(发放红包了);// 睡眠一下模拟发送优惠券比较复杂TimeUnit.SECONDS.sleep(2);log.info(发放优惠券了);} }Slf4j Component // 把监听器注册到spring容器中 Order(2) public class RegisterMsgNoticeListener implements ApplicationListenerRegisterEvent {Overridepublic void onApplicationEvent(RegisterEvent event) {log.info(站内信通知了);log.info(短信通知了);log.info(邮箱通知了);} }Slf4j Component public class RegisterPushDataListener{EventListenerOrder(3)public void onApplicationEvent(RegisterEvent event) {log.info(推送用户信息到大数据系统了user{}, event.getUser());} }你知道Spring Event发布订阅事件处理默认是同步还是异步的基于前面示例执行结果知道默认是同步的很多同学因为基于消息队列MQ异步解耦的思想自然而然以为是Spring Event的事件处理是异步的这是一个误区。Spring Boot并不会自动默认维护一个线程池来处理event事件要想异步处理事件使用 Async 标记即可注意前提条件是使用 EnableAsync 开启 Spring 异步 SpringBootApplication EnableAsync public class BaseDemoApplication {public static void main(String[] args) {SpringApplication.run(BaseDemoApplication.class, args);} }使用Async 的时候一般都会自定义线程池因为Async的默认线程池为 SimpleAsyncTaskExecutor不是真的线程池这个类不重用线程默认每次调用都会创建一个新的线程。 Configuration public class InitConfig {/*** 初始化一个线程池放入spring beanFactory* return*/Bean(name asyncExecutor)public Executor taskExecutor() {ThreadPoolTaskExecutor executor new ThreadPoolTaskExecutor();executor.setCorePoolSize(10);executor.setMaxPoolSize(20);executor.setQueueCapacity(200);executor.setKeepAliveSeconds(60);executor.setThreadNamePrefix(asyncExecutor-);executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());return executor;} }分别在监听器加上Async注解 Slf4j Component // 把监听器注册到spring容器中 Order(2) Async(asyncExecutor) public class RegisterMsgNoticeListener implements ApplicationListenerRegisterEvent {Overridepublic void onApplicationEvent(RegisterEvent event) {log.info(站内信通知了);log.info(短信通知了);log.info(邮箱通知了);} }Slf4j Component Order(1) Async(asyncExecutor) public class RegisterSendRedPacketListener implements ApplicationListenerRegisterEvent {SneakyThrowsOverridepublic void onApplicationEvent(RegisterEvent event) {log.info(发放红包了);// 睡眠一下模拟发送优惠券比较复杂TimeUnit.SECONDS.sleep(2);log.info(发放优惠券了);} }Slf4j Component public class RegisterPushDataListener{EventListenerOrder(3)Async(asyncExecutor)public void onApplicationEvent(RegisterEvent event) {log.info(推送用户信息到大数据系统了user{}, event.getUser());} }通过执行结果日志打印可以看到开启多线程异步执行了并且每次执行结果不确定验证了上面所说的异步情况下Order不再能控制监听器的执行顺序了。 2.2 借助事件进行启动初始化 在日常开发中我们经常碰到需要再项目系统服务启动时进行一些业务上逻辑处理、数据初始化等操作比如基础数据的写入、缓存的加载、任务的开启等等。实现这个功能的方式有很多这里我们就用Spring提供的事件ContextRefreshedEvent来实现当ApplicationContext被初始化或刷新之后触发该事件。 Slf4j Component public class InitListener implements ApplicationListenerContextRefreshedEvent {Overridepublic void onApplicationEvent(ContextRefreshedEvent event) {log.info(服务启动了执行业务初始化操作了);} }项目推荐基于SpringBoot2.x、SpringCloud和SpringCloudAlibaba企业级系统架构底层框架封装解决业务开发时常见的非功能性需求防止重复造轮子方便业务快速开发和企业技术栈框架统一管理。引入组件化的思想实现高内聚低耦合并且高度可配置化做到可插拔。严格控制包依赖和统一版本管理做到最少化依赖。注重代码规范和注释非常适合个人学习和企业使用 Github地址https://github.com/plasticene/plasticene-boot-starter-parent Gitee地址https://gitee.com/plasticene3/plasticene-boot-starter-parent 微信公众号Shepherd进阶笔记 交流探讨qunShepherd_126 3.Spring Event实现原理 Spring Event是一种基于观察者模式Observer Pattern的实现。观察者模式Observer Design Pattern也被称为发布订阅模式。其定义是在对象之间定义一个一对多的依赖当一个对象状态改变的时候所有依赖的对象都会自动收到通知。Spring Event发布订阅的流程如下图所示 直接从入口发布applicationContext.publishEvent()开始分析会来到AbstractApplicationContext#publishEvent() protected void publishEvent(Object event, Nullable ResolvableType eventType) {Assert.notNull(event, Event must not be null);// Decorate event as an ApplicationEvent if necessaryApplicationEvent applicationEvent;if (event instanceof ApplicationEvent) {applicationEvent (ApplicationEvent) event;}else {applicationEvent new PayloadApplicationEvent(this, event);if (eventType null) {eventType ((PayloadApplicationEvent?) applicationEvent).getResolvableType();}}// Multicast right now if possible - or lazily once the multicaster is initialized// ApplicationEventMulticaster 未初始化完成时先将applicationEvent 暂存if (this.earlyApplicationEvents ! null) {this.earlyApplicationEvents.add(applicationEvent);}else {// 获取监听管理器ApplicationEventMulticaster并进行广播事件处理核心入口所在getApplicationEventMulticaster().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);}}}ApplicationEventMulticaster getApplicationEventMulticaster() throws IllegalStateException {if (this.applicationEventMulticaster null) {throw new IllegalStateException(ApplicationEventMulticaster not initialized - call refresh before multicasting events via the context: this);}return this.applicationEventMulticaster; }ApplicationEventMulticaster是在Spring启动时核心方法AbstractApplicationContext#refresh()中进行注入的 Overridepublic void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {// Prepare this context for refreshing.prepareRefresh();// Tell the subclass to refresh the internal bean factory.//初始化beanfactorConfigurableListableBeanFactory beanFactory obtainFreshBeanFactory();// Prepare the bean factory for use in this context.// beanFactory赋值prepareBeanFactory(beanFactory);try {// Allows post-processing of the bean factory in context subclasses.//空实现提供子类覆盖的额外处理即子类处理自定义的beanFactorypostProcesspostProcessBeanFactory(beanFactory);// Invoke factory processors registered as beans in the context.//增强beanFactory功能如自动装配等invokeBeanFactoryPostProcessors(beanFactory);// Register bean processors that intercept bean creation.//创建注册beanPostProcessorregisterBeanPostProcessors(beanFactory);// Initialize message source for this context.//国际化处理initMessageSource();// Initialize event multicaster for this context.//初始化多播器initApplicationEventMulticaster();// Initialize other special beans in specific context subclasses.// 初始化web服务器等beanonRefresh();// Check for listener beans and register them.//将所有的ApplicationListener添加到事件多播器中registerListeners();// Instantiate all remaining (non-lazy-init) singletons.//实例化所有非懒加载的单例beanfinishBeanFactoryInitialization(beanFactory);// Last step: publish corresponding event.//启动servelt服务器等finishRefresh();}protected void initApplicationEventMulticaster() {ConfigurableListableBeanFactory beanFactory getBeanFactory();if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {this.applicationEventMulticaster beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);if (logger.isTraceEnabled()) {logger.trace(Using ApplicationEventMulticaster [ this.applicationEventMulticaster ]);}}else {this.applicationEventMulticaster new SimpleApplicationEventMulticaster(beanFactory);beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);if (logger.isTraceEnabled()) {logger.trace(No APPLICATION_EVENT_MULTICASTER_BEAN_NAME bean, using [ this.applicationEventMulticaster.getClass().getSimpleName() ]);}} }注册ApplicationEventMulticaster的逻辑很简单如果Spring容器中有了ApplicationEventMulticaster就使用自定义的不然就会创建默认的SimpleApplicationEventMulticaster放入容器中。 接下来我们就进入事件处理核心所在SimpleApplicationEventMulticaster#multicastEvent() Overridepublic void multicastEvent(final ApplicationEvent event, Nullable ResolvableType eventType) {ResolvableType type (eventType ! null ? eventType : resolveDefaultEventType(event));// 获取线程池Executor executor getTaskExecutor();// 循环遍历调用监听器for (ApplicationListener? listener : getApplicationListeners(event, type)) {// 是否存在线程池 异步执行逻辑if (executor ! null) {executor.execute(() - invokeListener(listener, event));}else {// 非异步线程处理invokeListener(listener, event);}}} 这里就可以看出在处理事件会先获取线程池没有的话就同步执行这也解释上面所说的Spring Event默认是同步处理事件的。接着往下看执行监听器处理逻辑 protected void invokeListener(ApplicationListener? listener, ApplicationEvent event) {ErrorHandler errorHandler getErrorHandler();// 是否存在 ErrorHandler if (errorHandler ! null) {try {doInvokeListener(listener, event);}catch (Throwable err) {errorHandler.handleError(err);}}else {doInvokeListener(listener, event);}}private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {try {// 执行监听器的onApplicationEvent()listener.onApplicationEvent(event);}catch (ClassCastException ex) {String msg ex.getMessage();if (msg null || matchesClassCastMessage(msg, event.getClass())) {// Possibly a lambda-defined listener which we could not resolve the generic event type for// - lets suppress the exception and just log a debug message.Log logger LogFactory.getLog(getClass());if (logger.isTraceEnabled()) {logger.trace(Non-matching event type for listener: listener, ex);}}else {throw ex;}}}从方法#invokeListener()可以看出会先判断是否定义了ErrorHandler有的话在事件处理过程中出现异常会进行异常捕获并做相应处理如果没有就是直接报错毫无处理。结论就是**最终事件的执行是由同一个线程按顺序来完成的任何一个报错都会导致后续的监听器执行不了。**这里我就不做演示了把上面案例改为同步然后某个监听器的处理逻辑报错就可以验证了我们可以通过自定义一个事件广播器来解决从上面Spring启动初始化可以看出只是new了一个SimpleApplicationEventMulticaster对象放入容器中并没有为其线程池Exector属性进行赋值这也是为啥默认是单线程同步处理事件的原因所在所以我们可以自定义一个事件广播器设置好线程池这样事件处理默认就是异步的了不需要再在监听器是使用Async。与此同时我们也可以自定义一个事件异常处理器来对处理事件过程中发生异常进行相应处理保证不同监听器的事件处理互不干扰逻辑如下所示 Slf4j Configuration public class InitConfig {/*** 自定义事件广播器异步处理事件这样监听器就不需要使用Async注解了* param executor* return*/Bean(AbstractApplicationContext.APPLICATION_EVENT_MULTICASTER_BEAN_NAME)public SimpleApplicationEventMulticaster simpleApplicationEventMulticaster(Qualifier(asyncExecutor) Executor executor,ErrorHandler errorHandler) {SimpleApplicationEventMulticaster simpleApplicationEventMulticaster new SimpleApplicationEventMulticaster();simpleApplicationEventMulticaster.setTaskExecutor(executor);simpleApplicationEventMulticaster.setErrorHandler(errorHandler);return simpleApplicationEventMulticaster;}/*** 注入一个事件异常处理器* return*/Beanpublic ErrorHandler errorHandler() {return (t) - {log.error(listener handle error: , t);};}/*** 初始化一个线程池放入spring beanFactory* return*/Bean(name asyncExecutor)public Executor taskExecutor() {ThreadPoolTaskExecutor executor new ThreadPoolTaskExecutor();executor.setCorePoolSize(10);executor.setMaxPoolSize(20);executor.setQueueCapacity(200);executor.setKeepAliveSeconds(60);executor.setThreadNamePrefix(asyncExecutor-);executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());return executor;} }整体类图如下 4.Spring Event与消息队列MQ的区别 Spring Event和消息队列MQ是两种不同的消息传递机制它们在实现消息通信方面有各自的优缺点。 Spring Event的优缺点 优点 简单易用 Spring Event是Spring框架提供的一个内置的事件发布-订阅机制使用起来非常简单无需引入额外的依赖。 无中间件依赖 Spring Event不依赖于任何消息中间件适用于小型项目或者简单的消息通信场景。 模块解耦 Spring Event可以帮助实现模块之间的解耦提高系统的灵活性和可维护性。 缺点 单点问题 Spring Event是在单个应用内部的事件通知机制如果应用崩溃或者重启事件将会丢失。 不支持分布式 Spring Event只能在单个应用内部传递消息不支持分布式环境下的消息传递。 性能问题 Spring Event在大规模消息通信场景下可能会存在性能问题因为它是同步执行的消息发布者需要等待所有订阅者处理完消息后才能继续执行。 消息队列MQ的优缺点 优点 异步处理 消息队列支持异步消息处理提高系统的并发能力和响应速度。 可靠性 消息队列通常具有消息持久化、消息重试等特性能够保证消息传递的可靠性。 分布式支持 消息队列支持分布式环境下的消息传递可以实现跨服务、跨应用的消息通信。 缺点 复杂性 使用消息队列需要引入额外的消息中间件并且需要配置和管理这些中间件增加了系统的复杂性。 维护成本 消息队列需要维护消息中间件的稳定性和可用性需要投入一定的维护成本。 一致性问题 消息队列在消息传递过程中可能会出现一致性问题需要额外的设计和处理。 综上所述Spring Event适用于简单的应用内部消息通信场景操作简单但有一定的局限性消息队列适用于分布式、高并发的消息通信场景可以提供更高的可靠性和灵活性但需要考虑复杂性和维护成本。在选择使用哪种方式时需要根据具体的业务需求和系统架构来进行权衡和选择。 5.总结 综上所述Spring Event在业务系统中的实际使用案例包括订单支付成功事件、用户注册事件等可以带来模块解耦、异步处理、增强扩展性等优点。然而对于复杂的业务场景、事件失效风险以及调试困难等缺点需要进行注意和权衡。在使用Spring Event时需要根据具体业务需求和系统特点进行合理的选择和使用。在使用需注意一下几点 监听器默认同步执行不要误认为和消息队列MQ一样异步消费消息的Spring Event是应用内部发布-订阅机制如果事件处理逻辑过于复杂同步阻塞可能对当前主流程带来影响建议使用异步的方式。 不要依赖监听器执行顺序首先我认为监听器之间有依赖关系就说明设计是有问题的这不就是耦合依赖吗和我们使用Spring Event的初衷有点背道而驰如果两个监听器事件处理有前后依赖顺序就应该想办法合并成一个。虽然我们可以使用 Order 来控制监听器之间的执行顺序但是仅在同步执行的场景下有效监听器异步执行的情况下实际执行顺序仍然是不可控的。 监听器的事件处理并不绝对可靠 多个监听器事件处理的执行是由同一个线程按顺序来完成的任何一个报错都会导致后续的监听器执行不了程序关闭时可能发生监听事件未处理完成。 事务事件Spring Event同步执行的时候是和主业务方法事务一起的可能会出现下面这种异常情况用户注册成功后发布消息通知事件但在后续的事务处理中处理异常导致事务回滚会出现用户收到注册成功短信但实际没有注册成功。所以我们一般认为Spring 事件是子任务和主业务事务不需要强一致性。
http://www.zqtcl.cn/news/737009/

相关文章:

  • 网站用户体验解决方案个人网页设计作品赏析
  • 常州网站建设方案外包网站开发用到的技术
  • 防伪网站模板如何找百度做网站
  • 网站建设与维护成绩查询云南app开发系统
  • 自己做网站的难度建设专门网站 强化信息宣传
  • 公职单位建设网站的目的如何查看小程序的开发公司
  • 网页模板网站推荐青岛 php 网站建设
  • joomla 网站建设3d网站建设
  • 网站开发与维护专业前景网站被禁止访问怎么打开
  • 山东 网站建设青海公路建设市场信用信息服务网站
  • 济南正规做网站公司wordpress一键还原
  • 免费的购物网站源码百度网站优化
  • 企业需要做网站吗深圳装修公司前十强
  • 合肥做网站推广哪家好软文写作的十大技巧
  • 哪里做网站的wordpress歌词插件
  • 网站改版做301重定向百度站长平台查询
  • 织梦网站后台网址妙影免费模板下载
  • 甘肃网站建设开发怎么利用花生壳做自己的网站
  • 怎么查询网站开通时间建个短视频网站
  • 物流网站建设广东网站建设效果
  • 网站推广工作流程图天蝎网站建设
  • 备案ip 查询网站查询网站校园门户网站建设方案
  • 网站seo快速优化技巧建设网站的需要学习哪些课程
  • 网站建设微信托管wordpress p=
  • 专业手机网站制作哪家好吉林建筑大学本科招生网
  • 建立一个网站需要哪些google和百度等相关网站的广告词
  • 手机开发网站教程做古建的那些网站比较适合
  • 网站建设公司的前景长沙商城网站开发
  • 大型网站tag标签 索引自己做网站需要哪些软件
  • 石排做网站万网网站备案流程