Implementing a Responsibility Chain Pattern with Spring Boot and MyBatis Plus
The article demonstrates how to build a dynamic Chain of Responsibility in a Spring Boot and MyBatis‑Plus application by defining an abstract handler, implementing concrete @Component beans that modify a shared Lombok‑based context, retrieving them via an ApplicationContext‑aware proxy utility, and invoking them in a client‑specified order through a REST endpoint, while suggesting LiteFlow as a production alternative.
Background : The project exposes an OpenAPI interface that contains dozens of functional points (parameter validation, configuration checks, data persistence, messaging, etc.). Different downstream clients require different subsets of these functions.
Idea : Split each functional point into an independent component and link them using the Chain of Responsibility pattern. The execution order can be defined dynamically (e.g., stored in a database or passed via a request).
Key Implementation :
Define an abstract class ComponentAbstract.java that provides handlerRequest(Contxt contxt) to measure execution time and delegate to an abstract doHandler(Contxt contxt) method.
Create concrete handlers ( Test1.java , Test2.java , Test3.java , Test4.java ) annotated with @Component("1") , @Component("2") … Each overrides doHandler to modify a shared context.
Shared context class Contxt.java holds fields such as name , age , adrss , userid and is annotated with Lombok’s @Data , @Builder , etc.
Utility AopProxyUtils.java implements ApplicationContextAware to retrieve Spring‑managed beans by name.
Controller LiteFlowController.java exposes /test/chain . It parses the index query parameter (e.g., 2,1,3,4 ), obtains the corresponding beans via AopProxyUtils.getProxyBean(className) , invokes handlerRequest in the specified order, and returns the final Contxt as JSON.
Sample Code Snippets :
public abstract class ComponentAbstract {
public void handlerRequest(Contxt contxt) {
// measure execution time
this.doHandler(contxt);
}
public abstract void doHandler(Contxt contxt);
} @Component("1")
public class Test1 extends ComponentAbstract {
@Override
public void doHandler(Contxt contxt) {
log.info("Test1-顺序1-上下文内容为:{}", JSON.toJSONString(contxt));
contxt.setName("Test1");
// other fields set …
}
} @Data @Builder @AllArgsConstructor @NoArgsConstructor
public class Contxt {
private String name;
private String age;
private String adrss;
private String userid;
} @RestController
@RequestMapping("/test")
public class LiteFlowController {
@GetMapping("chain")
public String pattern(@RequestParam String index) {
Contxt contxt = Contxt.builder()
.name("初始化").age("初始化").adrss("初始化").userid("初始化").build();
for (String className : index.split(",")) {
ComponentAbstract handler = (ComponentAbstract) AopProxyUtils.getProxyBean(className);
if (handler != null) {
handler.handlerRequest(contxt);
}
}
return JSON.toJSONString(contxt);
}
}Note : While a custom implementation is shown, the author mentions that the LiteFlow framework would be a more suitable choice for production use.
Java Tech Enthusiast
Sharing computer programming language knowledge, focusing on Java fundamentals, data structures, related tools, Spring Cloud, IntelliJ IDEA... Book giveaways, red‑packet rewards and other perks await!
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.