将一个流程做成低耦合可扩展性能:

1.注册一个用户person

2.注册之后给用户发送短信注册成功

3.注册之后给用户发送邮件最近活动信息

事件机制:

事件驱动模型也就是我们常说的观察者,或者发布-订阅模型;理解它的几个关键点

 

 

 

Spring 中事件机制中各角色:

  • 事件 ApplicationEvent 是所有事件对象的父类,也就是说当某个业务发生改变 Spring 可以发出一个事件出来(当然这边可能是具体的某一个事件,Spring 中常用的事件请看第二节介绍)。
  • 事件监听 ApplicationListener,也就是观察者,继承自 JDK 的 EventListener,该类中只有一个方法 onApplicationEvent。当监听的事件发生后该方法会被执行。
  • 事件源 ApplicationContext,ApplicationContext 是 Spring 中的核心容器,在事件监听中 ApplicationContext 可以作为事件的发布者,也就是事件源。
  • 事件管理 ApplicationEventMulticaster,用于事件监听器的注册和事件的广播。监听器的注册就是通过它来实现的,它的作用是把 Applicationcontext 发布的 Event 广播给它的监听器列表。

事件:注册一个用户

 

监听器:发送短信、发送邮件

增加了一个Listener来解耦UserService和其他服务,即注册成功后,只需要通知相关的监听器,不需要关系它们如何处理。增删功能非常容易。这就是一个典型的事件处理模型/观察者,解耦目标对象和它的依赖对象,目标只需要通知它的依赖对象,具体怎么处理,依赖对象自己决定。比如是异步还是同步,延迟还是非延迟等。

具体示例:

1.定义事件

public class UserRegisterEvent extends ApplicationEvent {

    private String userName;
    //source事件源
    public UserRegisterEvent(Object source, String userName) {
        super(source);
        this.userName = userName;
    }
    public String getUserName() {
        return userName;
    }

}

2.定义监听器(两种方式)

方式1)实现接口方式:

/**
 * 事件监听器:监听广播,发送邮件
 */
@Component
public class UserRegisterEventListener implements ApplicationListener<UserRegisterEvent> {
    @Override
    public void onApplicationEvent(UserRegisterEvent userRegisterEvent) {
        System.out.println(String.format("接口模式给用户[%S]发送邮件成功",userRegisterEvent.getUserName()));
    }
}

 

方式2)注解方式:

/**
 * 事件监听器:监听广播,发送邮件
 */
@Component
public class UserRegisterEventListener2 {

    @EventListener(classes = {UserRegisterEvent.class})
    public void sendMail(UserRegisterEvent userRegisterEvent){
        System.out.println("注解1给用户"+userRegisterEvent.getUserName()+"发送邮件成功");
    }
    @EventListener(UserRegisterEvent.class)
    public void sendCompon(UserRegisterEvent userRegisterEvent){
        System.out.println(String.format("注解2给用户[%s]发送邮件成功",userRegisterEvent.getUserName()));
    }

}

第三、第四种摘取往上,

第三种方式:有序监听器实现SmartApplicationListener接口:

package com.br.listener;

import com.br.bean.User;
import com.br.event.UserRegisterEvent;
import com.br.service.UserService;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.event.SmartApplicationListener;
import org.springframework.stereotype.Component;

/**
 * @author 10400
 * @create 2018-02-27 15:03
 * @deprecated 有序监听
 */
@Component
public class SmartRegisterListener implements SmartApplicationListener {
    @Override
    public boolean supportsEventType(Class<? extends ApplicationEvent> aClass) {
        //只有UserRegisterEvent监听类型才会执行下面逻辑
        return aClass == UserRegisterEvent.class;
    }

    @Override
    public boolean supportsSourceType(Class<?> aClass) {
        //只有在UserService内发布的UserRegisterEvent事件时才会执行下面逻辑
        return aClass == UserService.class;
    }

    @Override
    public void onApplicationEvent(ApplicationEvent applicationEvent) {
        //转换事件类型
        UserRegisterEvent userRegisterEvent = (UserRegisterEvent) applicationEvent;
        //获取注册用户对象信息
        User user = userRegisterEvent.getUser();
        //.../完成注册业务逻辑

        System.out.println("SmartRegisterListener" + user.getName());

    }

    /**
     * return 的数值越小证明优先级越高,执行顺序越靠前。
     * @return
     */
    @Override
    public int getOrder() {
        return 10;
    }
}
SmartApplicationListener接口继承了全局监听ApplicationListener,
并且泛型对象使用的ApplicationEvent来作为全局监听,
可以理解为使用SmartApplicationListener作为监听父接口的实现,监听所有事件发布。

getOrder:return的数值越小证明优先级越高,执行顺序越靠前

第四种方式:使用@Async实现异步监听

@Aysnc其实是Spring内的一个组件,可以完成对类内单个或者多个方法实现异步调用,这样可以大大的节省等待耗时。内部实现机制是线程池任务ThreadPoolTaskExecutor,通过线程池来对配置@Async的方法或者类做出执行动作。

  • 线程任务池配置
    我们创建一个ListenerAsyncConfiguration,并且使用@EnableAsync注解开启支持异步处理,具体代码如下所示:
@Configuration
@EnableAsync
public class ListenerAsyncConfiguration implements AsyncConfigurer
{
    /**
     * 获取异步线程池执行对象
     * @return
     */
    @Override
    public Executor getAsyncExecutor() {
        //使用Spring内置线程池任务对象
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        //设置线程池参数
        taskExecutor.setCorePoolSize(5);
        taskExecutor.setMaxPoolSize(10);
        taskExecutor.setQueueCapacity(25);
        taskExecutor.initialize();
        return taskExecutor;
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return null;
    }
}
我们自定义的监听异步配置类实现了AsyncConfigurer接口并且实现内getAsyncExecutor方法以提供线程任务池对象的获取。
我们只需要在异步方法上添加@Async注解就可以实现方法的异步调用,为了证明这一点,我们在发送邮件onApplicationEvent方法内添加线程阻塞3秒,修改后的代码如下所示:

/**
     * supportsEventType & supportsSourceType 两个方法返回true时调用该方法执行业务逻辑
     * @param applicationEvent 具体监听实例,这里是UserRegisterEvent
     */
    @Override
    @Async
    public void onApplicationEvent(ApplicationEvent applicationEvent) {
        try {
            Thread.sleep(3000);//静静的沉睡3秒钟
        }catch (Exception e)
        {
            e.printStackTrace();
        }
        //转换事件类型
        UserRegisterEvent userRegisterEvent = (UserRegisterEvent) applicationEvent;
        //获取注册用户对象信息
        UserBean user = userRegisterEvent.getUser();
        System.out.println("用户:"+user.getName()+",注册成功,发送邮件通知。");
    }


网摘链接:https://www.jianshu.com/p/ef2cee8c5dd1

 

 

 

3.事件服务(任取一个事件管理实现接口即可ApplicationContextAware、ApplicationEventPublisherAware)

@Service
public class UserRegisterEventService implements ApplicationContextAware, ApplicationEventPublisherAware {

    private static ApplicationContext applicationContext;
    private static ApplicationEventPublisher applicationEventPublisher;

    //注册
    public void registerUser(String userName) {
        UserRegisterEvent userRegisterEvent = new UserRegisterEvent(UserRegisterEvent.class, userName);
        System.out.println(String.format("用户[%s]注册成功", userName));
        //发布注册成功事件
        applicationContext.publishEvent(userRegisterEvent);
        applicationEventPublisher.publishEvent(userRegisterEvent);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext)
            throws BeansException {
        this.applicationContext = applicationContext;
    }

    @EventListener(classes = {UserRegisterEvent.class})
    public void sendMail(UserRegisterEvent userRegisterEvent){
        System.out.println("注解3给用户"+userRegisterEvent.getUserName()+"发送邮件成功");
    }
    @EventListener(UserRegisterEvent.class)
    public void sendCompon(UserRegisterEvent userRegisterEvent){
        System.out.println(String.format("注解4给用户[%s]发送邮件成功",userRegisterEvent.getUserName()));
    }

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.applicationEventPublisher = applicationEventPublisher;
    }
}

测试用例(结合上一篇测试用例规范注入Service服务):

/**
 * 事件对象:用户注册事件
 */
@RunWith(SpringRunner.class)
//@SpringBootTest(classes = UserRegisterEventConfig.class)
@ContextConfiguration(classes = UserRegisterEventConfig.class)
public class UserRegisterTest {

    @Resource
    private UserRegisterEventService userRegisterEventService;

    @Test
    public void test() {
//        ApplicationContext context = new AnnotationConfigApplicationContext(UserRegisterEventService.class);
//        UserRegisterEventService userRegisterEventService = context.getBean(UserRegisterEventService.class);
        System.out.println(userRegisterEventService);
        userRegisterEventService.registerUser("userName222");
    }

}

 

posted on 2021-10-28 17:12  茫无所知  阅读(204)  评论(0编辑  收藏  举报