Mastering the Chain of Responsibility Pattern in Java Spring: A Step‑by‑Step Guide
This article explains the Chain of Responsibility design pattern using a real‑world iron‑chain analogy, then demonstrates a complete Java Spring implementation for order validation, including interface definition, abstract base class, concrete handlers, Spring configuration, service, and controller code.
In real life an iron chain consists of linked rings; each ring can be likened to an object in the Chain of Responsibility pattern, where each object handles a single piece of logic and passes the request along the chain until processing is complete.
Practical Application in a Project
We apply the pattern to validate order parameters: first checking if the order ID is null, then the buyer, and finally the shipping address. The workflow diagram (image) illustrates the validation steps.
The project structure is shown in the following diagram.
Implementation Details
1. Define the chain interface
<code>public interface OrderCheckHandler {
void check(OrderCheckParam orderCheckParam);
OrderCheckHandler setNext(OrderCheckHandler nextOrderCheckHandler);
}</code>2. Extract common chain logic
<code>public abstract class BaseCheckOrderHandler implements OrderCheckHandler {
private OrderCheckHandler nextOrderCheckHandler;
@Override
public void check(OrderCheckParam orderCheckParam) {
this.currentCheck(orderCheckParam);
if (Objects.nonNull(nextOrderCheckHandler)) {
nextOrderCheckHandler.check(orderCheckParam);
}
}
protected abstract void currentCheck(OrderCheckParam orderCheckParam);
@Override
public OrderCheckHandler setNext(OrderCheckHandler nextOrderCheckHandler) {
this.nextOrderCheckHandler = nextOrderCheckHandler;
return this.nextOrderCheckHandler;
}
}</code>3. Concrete validation handlers
<code>// Order ID validation
@Service
public class OrderIdCheckHandler extends BaseCheckOrderHandler {
@Override
protected void currentCheck(OrderCheckParam orderCheckParam) {
if (orderCheckParam.getOrderId() == null) {
throw new RuntimeException("订单id为空");
}
}
}
// Buyer validation
@Service
public class BuyerCheckHandler extends BaseCheckOrderHandler {
@Override
protected void currentCheck(OrderCheckParam orderCheckParam) {
if (orderCheckParam.getBuyer() == null) {
throw new RuntimeException("用户不可以为空");
}
}
}
// Address validation
@Service
public class AddressCheckHandler extends BaseCheckOrderHandler {
@Override
protected void currentCheck(OrderCheckParam orderCheckParam) {
if (orderCheckParam.getAddress() == null) {
throw new RuntimeException("用户地址不可以为空");
}
}
}</code>4. Wire the chain with Spring
<code>@Configuration
public class OrderCheckConfig {
@Bean
public BuyerCheckHandler buyerCheckHandler() { return new BuyerCheckHandler(); }
@Bean
public OrderIdCheckHandler checkOrderIdHandler() { return new OrderIdCheckHandler(); }
@Bean
public AddressCheckHandler addressCheckHandler() { return new AddressCheckHandler(); }
// Define execution order of the chain
@Bean
public OrderCheckHandler orderCheckHandler() {
OrderIdCheckHandler orderIdCheckHandler = this.checkOrderIdHandler();
orderIdCheckHandler.setNext(this.buyerCheckHandler()).setNext(this.addressCheckHandler());
return orderIdCheckHandler;
}
}</code>5. Service invoking the chain
<code>@Service
public class OrderService {
@Resource
private OrderCheckHandler orderCheckHandler;
public String checkOrderParam(OrderCheckParam param) {
orderCheckHandler.check(param);
return "success";
}
}</code>6. Controller exposing a test endpoint
<code>@RestController
@RequestMapping("/test")
public class ZeRenLianTestController {
@Resource
private OrderService orderService;
@GetMapping("/checkOrder")
public String checkOrder() {
OrderCheckParam orderCheckParam = new OrderCheckParam();
orderCheckParam.setAddress("123");
orderCheckParam.setOrderId("1235689");
return orderService.checkOrderParam(orderCheckParam);
}
}</code>The test result is shown in the following image.
If a new validation, such as logistics verification, is needed, simply add a new handler class and include it in the Spring configuration to extend the chain.
Key Takeaways
(1) Keep the chain structure clear and avoid overly long chains to maintain performance.
(2) Each handler should have a single responsibility, focusing only on its own logic.
(3) Typical scenarios for the Chain of Responsibility include multiple objects processing the same request, such as approval workflows, parameter validation, and logging chains.
Lobster Programming
Sharing insights on technical analysis and exchange, making life better through technology.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.