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、只要是監聽了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;
}
}
}
}