spring事件学习和浅析

本文介绍了如何使用Spring的事件驱动机制将订单创建与手续费计算逻辑解耦。通过创建一个发布事件的工具类EventUtils,定义事件模型OrderSubmitEvent,订单服务类OrderService来发布事件,以及编写监听器OrderSubmitListener来处理事件,实现了业务流程的异步处理。测试结果显示,订单创建后立即返回,手续费计算在事务提交后异步执行。

业务场景:在一个业务系统中,订单提交后并计算该笔订单的手续费。

       为了下单这个逻辑的完整性和代码执行更高效,我们可以把“下单”和“计算手续费”拆分成两个不同的业务逻辑。

一、定义一个发布事件的工具类EventUtils

这个工具类只负责发布事件

public class EventUtils implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

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

    public static void publishEvent(final ApplicationEvent event) {
        if (TransactionSynchronizationManager.isActualTransactionActive()) {
            TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
                @Override
                public void afterCommit() {
                    applicationContext.publishEvent(event);
                    super.afterCommit();
                }

            });
        } else {
            applicationContext.publishEvent(event);
        }
    }
}

二、定义一个事件模型

就是创建一个普通java类并继承org.springframework.context.ApplicationEvent,它主要负责数据传输

public class OrderSubmitEvent extends ApplicationEvent{

    private static final long serialVersionUID = -726198855342137539L;

    public OrderSubmitEvent(Object source) {
        super(source);
    }
}

三、 定义一个订单服务类

@Service
public class OrderService {

    static final Logger logger = LoggerFactory.getLogger(OrderService.class);

    // 创建订单方法    ps:这只是测试代码,如果写正式代码建议定义接口
    public void create(){

        logger.info("OrderService.create");

        // 执行创建订单逻辑
        // do something...

        // 要传输的信息,这里可以是object类型,我为了演示就直接传一个字符串过去
        String message = "订单提交成功了!";

        // 发布事件
        EventUtils.publishEvent(new OrderSubmitEvent(message));

        logger.info("OrderService.publishEvent");
    }
}

四、写监听器

既然订单创建好了并发布了事件,那我们就需要监听这个“订单已提交”的事件,去执行自己的逻辑,这个监听器需要实现 org.springframework.context.ApplicationListener 然后重写它的方法。

@Component
public class OrderSubmitListener implements ApplicationListener<OrderSubmitEvent>{

    final static Logger logger = LoggerFactory.getLogger(OrderSubmitListener.class);

    @Async
    @Override
    public void onApplicationEvent(OrderSubmitEvent orderCompleteEvent) {
        Object source = orderCompleteEvent.getSource();
        logger.info("OrderSubmitListener onApplicationEvent source:[{}]", ToStringBuilder.reflectionToString(source));
    }
}

五、配置文件

直接贴代码,如果直接复制下面配置,需要修改一下你们的包路径

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:aop="http://www.springframework.org/schema/aop" xmlns:task="http://www.springframework.org/schema/task"
       xsi:schemaLocation="http://www.springframework.org/schema/mvc
		http://www.springframework.org/schema/mvc/spring-mvc.xsd
		http://www.springframework.org/schema/beans
		http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context
		http://www.springframework.org/schema/context/spring-context.xsd
		http://www.springframework.org/schema/aop
		http://www.springframework.org/schema/aop/spring-aop.xsd
		http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd">


    <!-- 扫描远程服务类注解 !!!记得自己改包名!!!-->
    <context:component-scan base-package="com.xxx.**.**" use-default-filters="false">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Service" />
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Component" />
    </context:component-scan>

    <!-- 方便在非spring管理环境中获取bean !!!记得自己改包名-->
    <bean id="eventUtils" class="com.xxx.util.EventUtils"/>

    <!-- 视图解析器 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/views/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

</beans>

六、测试

@RestController
@RequestMapping(value = "api/test",produces = "text/plain;charset=UTF-8")
public class TestController {

    static final Logger logger = LoggerFactory.getLogger(TestController.class);

    @Autowired
    private Configuration configuration;

    @Autowired
    private OrderService orderService;

    @RequestMapping(value = "/index")
    public String order(){
        logger.info("TestController create order run");
        orderService.create();
        return "index";
    }
}

控制台结果:

17:10:53.936 [qtp1899280551-20] INFO  com.xxx.web.controller.TestController - TestController create order run
17:10:53.937 [qtp1899280551-20] INFO  com.xxx.springevent.OrderService - OrderService.create
17:10:53.947 [qtp1899280551-20] INFO  com.xxx.springevent.OrderSubmitListener - OrderSubmitListener onApplicationEvent source:[java.lang.String@73bd9107[value={订,单,提,交,成,功,了,!},hash=171729329]]
17:10:53.947 [qtp1899280551-20] INFO  com.xxx.springevent.OrderService - OrderService.publishEvent

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值