一、业务背景
Kafka接收消息,需要A,B,C...多种策略做处理,再通过http请求发送给下游。多种策略混在一起很难维护,通过责任链模式把每种策略的代码收敛到自己的Handler中
二、具体设计
classDiagram
Handler <|-- StrategyAHandler
Handler <|-- StrategyBHandler
Handler <|-- UploadHandler
Handler: +void handleUserData(UserContext, HandlerChain)
Handler: +void handleOrderData(OrderContext, HandlerChain)
class StrategyAHandler {
+void handleUserData(UserContext, HandlerChain)
+void handleOrderData(OrderContext, HandlerChain)
}
class StrategyBHandler {
+void handleUserData(UserContext, HandlerChain)
+void handleOrderData(OrderContext, HandlerChain)
}
class UploadHandler {
+void handleUserData(UserContext, HandlerChain)
+void handleOrderData(OrderContext, HandlerChain)
}
HandlerChain o--o Handler
class HandlerChain {
+List~Handler~ chain
+void doHandle(AbstractContext context)
}
HandlerChain --> AbstractContext
class AbstractContext {
+JSONObject param
+int position
}
AbstractContext <|-- UserContext
AbstractContext <|-- OrderContext
class UserContext {
+UserInfo userInfo
}
class OrderContext {
+OrderInfo orderInfo
}
三、代码实现
1.HandlerChain类
java
public class HandlerChain {
List<Handler> chain;
public HandlerChain() {
chain = new ArrayList<>();
}
public void doHandle(AbstractContext context) {
// 截止条件
if (context.getPosition() >= chain.size()) {
return;
}
// 获取当前要执行的handler
Handler handler = chain.get(context.getPosition());
// 移动到下一个要执行的handler位置
context.setPosition(context.getPosition() + 1);
// 利用Context类的多态,判断执行的具体方法
if (context instanceof UserContext) {
handler.handleUserData((UserContext) context, this);
} else if (context instanceof OrderContext) {
handler.handleOrderData((OrderContext) context, this);
}
}
public void addHandler(Handler handler) {
chain.add(hander);
}
}
2.Handler类
- Handler接口:定义需要处理的消息
java
public interface Handler {
// 处理用户数据消息
void handleUserData(UserContext userContext, HandlerChain chain);
// 处理订单数据消息
void handleOrderData(OrderContext orderContext, HandlerChain chain);
}
- Handler实现类:子类结构相同,执行各自的具体逻辑
java
@Component
public class StrategyAHandler implements Handler {
// 处理用户数据消息
public void handleUserData(UserContext userContext, HandlerChain chain) {
// ...
// 核心方法,触发流转到下一个handler
chain.doHandle(userContext);
}
// 处理订单数据消息
public void handleOrderData(OrderContext orderContext, HandlerChain chain) {
...
// 核心方法,触发流转到下一个handler
chain.doHandle(orderContext);
}
}
@Component
public class StrategyBHandler implements Handler {
// ...
}
@Component
public class UploadHandler implements Handler {
// ...
}
3.Context类
- Context抽象类 :定义公共参数
- param:处理到最后要发http请求,因此构建一个公共的JSONObject类型参数
- position:标记即将执行的handler所在位置
java
@Data
public abstract class AbstractContext {
private JSONObject param = new JSONObject();
private int position = 0;
}
- Context实现类:定义每一种消息独有的参数
java
@Data
public class UserContext extends AbstractContext {
private UserInfo userInfo;
public UserContext(UserInfo userInfo) {
this.userInfo = userInfo;
}
}
java
@Data
public class OrderContext extends AbstractContext {
private OrderInfo orderInfo;
public OrderContext(OrderInfo orderInfo) {
this.orderInfo = orderInfo;
}
}
4.Handler组装类
- 作用:接收Kafka消息,把各种策略按任意顺序组装
java
@Component
public class DemoService {
@Autowired
private StrategyAHandler strategyAHandler;
@Autowired
private StrategyBHandler strategyBHandler;
@Autowired
private UploadHandler uploadHandler;
// 处理Kafka发来的用户信息
public void handleUserData(UserInfo userInfo) {
HandlerChain chain = new HandlerChain();
chain.addHandler(strategyAHandler);
chain.addHandler(strategyBHandler);
chain.addHandler(uploadHandler);
UserContext userContext = new UserContext(userInfo);
chain.doHandle(userContext);
}
// 处理Kafka发来的订单信息
public void handleOrderData(OrderInfo orderInfo) {
HandlerChain chain = new HandlerChain();
chain.addHandler(strategyBHandler);
chain.addHandler(strategyAHandler);
chain.addHandler(uploadHandler);
OrderContext orderContext = new OrderContext(orderInfo);
chain.doHandle(orderContext);
}
}
四、总结
- Handler实现类交给Spring框架来管理,Context和HandlerChain则是每次调用创建一份
- 实现效果是可以把某个策略的代码收敛在一个Handler实现类中
- 如果需要去掉某个策略,直接把该策略从chain中去除即可