Spring高级特性-监听事件[观察者模式]

1、定义一个事件

     订单支付之后的扩展业务,可直接动态扩展不用改动之前任何的代码

package com.milla.navicat.spring.study.event;

import org.springframework.context.ApplicationEvent;

/**
 * @Package: com.milla.navicat.spring.study.event
 * @Description: <卖出事件[观察者模式,可扩展业务:推送邮件、推送订单完成信息、推送物流信息、推送获取优惠券信息]>
 * @Author: MILLA
 * @CreateDate: 2019/11/1 19:04
 * @UpdateUser: MILLA
 * @UpdateDate: 2019/11/1 19:04
 * @UpdateRemark: <>
 * @Version: 1.0
 */
public class OrderServiceEvent extends ApplicationEvent {
    /**
     * Create a new ApplicationEvent.
     *
     * @param source the object on which the event initially occurred (never {@code null})
     */
    public OrderServiceEvent(Object source) {
        super(source);
    }
}

2、定义监听器

2.1 定义邮件监听器 

package com.milla.navicat.spring.study.event.listener;

import com.milla.navicat.spring.study.event.OrderServiceEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

/**
 * @Package: com.milla.navicat.spring.study.event.listener
 * @Description: <发送邮件业务>
 * @Author: MILLA
 * @CreateDate: 2019/11/1 19:07
 * @UpdateUser: MILLA
 * @UpdateDate: 2019/11/1 19:07
 * @UpdateRemark: <>
 * @Version: 1.0
 */
@Component
@Slf4j
public class EmailListener implements ApplicationListener<OrderServiceEvent> {
    @Override
    public void onApplicationEvent(OrderServiceEvent event) {
        Object source = event.getSource();
        log.info("邮件发送服务,参数:{}", source);
        log.info("Email...1.根据帐号获取用户邮箱信息");
        log.info("Email...2.发送邮件");

    }
}

    2.2 定义优惠券发放监听器

package com.milla.navicat.spring.study.event.listener;

import com.milla.navicat.spring.study.event.OrderServiceEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

/**
 * @Package: com.milla.navicat.spring.study.event.listener
 * @Description: <优惠券业务类>
 * @Author: MILLA
 * @CreateDate: 2019/11/4 16:04
 * @UpdateUser: MILLA
 * @UpdateDate: 2019/11/4 16:04
 * @UpdateRemark: <>
 * @Version: 1.0
 */
@Slf4j
@Component
public class DiscountCouponListener implements ApplicationListener<OrderServiceEvent> {
    @Override
    public void onApplicationEvent(OrderServiceEvent event) {
        Object source = event.getSource();
        log.info("优惠券业务,参数:{}", source);
        log.info("优惠券...1.根据帐号获取用户信息");
        log.info("优惠券...2.分发优惠券");
        log.info("优惠券...3.其他优惠券业务");

    }
}

3、发布事件

package com.milla.navicat.spring.study.service.impl;

import com.google.common.collect.Maps;
import com.milla.navicat.spring.study.event.OrderServiceEvent;
import com.milla.navicat.spring.study.service.CalculateAmountService;
import com.milla.navicat.spring.study.service.OrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * @Package: com.milla.navicat.spring.study.service.impl
 * @Description: <六大设计原则>
 * @Author: MILLA
 * @CreateDate: 2019/11/1 16:32
 * @UpdateUser: MILLA
 * @UpdateDate: 2019/11/1 16:32
 * @UpdateRemark: <>
 * @Version: 1.0
 */
@Service
@Slf4j
public class OrderServiceImpl implements OrderService {
    @Autowired
    private Map<String, CalculateAmountService> calculateAmountServiceMap;

    @Autowired
    private ApplicationContext applicationContext;

    @Override
    public double getPaymentAmount(String userType, double amount) {
        log.debug("所有的折扣对象:{}", calculateAmountServiceMap);
        CalculateAmountService service = calculateAmountServiceMap.get(userType);
        if (Objects.isNull(service)) {
            return amount;
        }
        return service.getPaymentAmountByDisCount(amount);
    }

    @Override
    public boolean payment(String userType, double amount, double discountAmount) {
        double paymentAmount = this.getPaymentAmount(userType, amount);
        Assert.isTrue(discountAmount != paymentAmount, "折扣计算有误");
        HashMap<Object, Object> map = Maps.newHashMap();
        map.put("account", "唯一账户信息");//用以获取业务中需要的信息,比如电话号、邮箱、订单信息等等
        map.put("userType", userType);
        map.put("payAmount", discountAmount);
        //支付操作;支付成功,做推送业务
        OrderServiceEvent event = new OrderServiceEvent(map);
        applicationContext.publishEvent(event);//发布事件
        return true;
    }

}

4、执行onApplicationEvent方法

只要是监听了OrderServiceEvent事件的监听器,都会执行对应的void onApplicationEvent(OrderServiceEvent event)方法,然后执行扩展的业务逻辑

跟踪代码执行的顺序及逻辑如下:


package org.springframework.context;

/**
 * Interface that encapsulates event publication functionality.
 *
 * <p>Serves as a super-interface for {@link ApplicationContext}.
 *
 * @author Juergen Hoeller
 * @author Stephane Nicoll
 * @since 1.1.1
 * @see ApplicationContext
 * @see ApplicationEventPublisherAware
 * @see org.springframework.context.ApplicationEvent
 * @see org.springframework.context.event.ApplicationEventMulticaster
 * @see org.springframework.context.event.EventPublicationInterceptor
 */
@FunctionalInterface
public interface ApplicationEventPublisher {

	/**
	 * Notify all <strong>matching</strong> listeners registered with this
	 * application of an application event. Events may be framework events
	 * (such as ContextRefreshedEvent) or application-specific events.
	 * <p>Such an event publication step is effectively a hand-off to the
	 * multicaster and does not imply synchronous/asynchronous execution
	 * or even immediate execution at all. Event listeners are encouraged
	 * to be as efficient as possible, individually using asynchronous
	 * execution for longer-running and potentially blocking operations.
	 * @param event the event to publish
	 * @see #publishEvent(Object)
	 * @see org.springframework.context.event.ContextRefreshedEvent
	 * @see org.springframework.context.event.ContextClosedEvent
	 */
	default void publishEvent(ApplicationEvent event) {//1.第一步
		publishEvent((Object) event);
	}

	/**
	 * Notify all <strong>matching</strong> listeners registered with this
	 * application of an event.
	 * <p>If the specified {@code event} is not an {@link ApplicationEvent},
	 * it is wrapped in a {@link PayloadApplicationEvent}.
	 * <p>Such an event publication step is effectively a hand-off to the
	 * multicaster and does not imply synchronous/asynchronous execution
	 * or even immediate execution at all. Event listeners are encouraged
	 * to be as efficient as possible, individually using asynchronous
	 * execution for longer-running and potentially blocking operations.
	 * @param event the event to publish
	 * @since 4.2
	 * @see #publishEvent(ApplicationEvent)
	 * @see PayloadApplicationEvent
	 */
	void publishEvent(Object event);//2.第二步

}
public abstract class AbstractApplicationContext extends DefaultResourceLoader
		implements ConfigurableApplicationContext {
	/**
	 * Publish the given event to all listeners.
	 * <p>Note: Listeners get initialized after the MessageSource, to be able
	 * to access it within listener implementations. Thus, MessageSource
	 * implementations cannot publish events.
	 * @param event the event to publish (may be an {@link ApplicationEvent}
	 * or a payload object to be turned into a {@link PayloadApplicationEvent})
	 */
	@Override
	public void publishEvent(Object event) {//3.第三部
		publishEvent(event, null);
	}

	/**
	 * Publish the given event to all listeners.
	 * @param event the event to publish (may be an {@link ApplicationEvent}
	 * or a payload object to be turned into a {@link PayloadApplicationEvent})
	 * @param eventType the resolved event type, if known
	 * @since 4.2
	 */
	protected void publishEvent(Object event, @Nullable ResolvableType eventType) {//4、第四步
		Assert.notNull(event, "Event must not be null");

		// Decorate event as an ApplicationEvent if necessary
		ApplicationEvent 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
		if (this.earlyApplicationEvents != null) {
			this.earlyApplicationEvents.add(applicationEvent);
		}
		else {
                         //校验的逻辑可以忽略,主要是下面的广播方法
			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);
			}
		}
	}
}
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {

	@Nullable
	private Executor taskExecutor;

	@Nullable
	private ErrorHandler errorHandler;
	@Override
	public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
		ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
		Executor executor = getTaskExecutor();
                                               //5、根据事件类型获取所有的事件列表,然后分别调用监听器
		for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
			if (executor != null) {
				executor.execute(() -> invokeListener(listener, event));
			}
			else {
				invokeListener(listener, event);
			}
		}
	}

	/**
	 * 6、使用给定的事件调用指定的监听器
	 * @param listener the ApplicationListener to invoke
	 * @param event the current event to propagate
	 * @since 4.1
	 */
	protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
		ErrorHandler errorHandler = getErrorHandler();
		if (errorHandler != null) {
			try {
				doInvokeListener(listener, event);
			}
			catch (Throwable err) {
				errorHandler.handleError(err);
			}
		}
		else {
			doInvokeListener(listener, event);
		}
	}
    //7、真正执行调用的方法
	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
				// -> let's 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;
			}
		}
	}
}

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值