Backend Development 7 min read

Mastering the Chain of Responsibility Pattern in Spring: A Hands‑On Guide

This article explains the Chain of Responsibility design pattern, showing how to refactor order processing in a Spring 5.2 Java 8 application by defining abstract handlers, implementing concrete handlers, configuring bean ordering, and extending the chain for new order types.

Ops Development Stories
Ops Development Stories
Ops Development Stories
Mastering the Chain of Responsibility Pattern in Spring: A Hands‑On Guide

Introduction

Definition: The Chain of Responsibility pattern gives multiple objects a chance to handle a request, reducing coupling between sender and receiver. Handlers are linked in a chain; the request is passed along until one handler processes it.

Mnemonic: Responsibility passing

Examples: financial reimbursement, passing the drum, Sentinel (CtSph.java), Zookeeper, Nacos.

Create order → consume coupon → ship → rebate

Environment: JDK 1.8, Spring 5.2.x

Code Implementation

The implementation uses an abstract class

AbstractOrderHandler

to define the handler contract. In the example there are four concrete handlers:

CreateOrderHandler

,

UseCouponOrderHandler

,

GoodsDeliverOrderHandler

, and

RebateOrderHandler

. This design splits a large method into reusable, low‑coupling handler classes.

Define Abstract Methods

The abstract class defines two key methods:

<code>public abstract class AbstractOrderHandler {
    /**
     * Distinguish type
     */
    protected abstract OrderTypeEnum getTypeEnum();

    /**
     * Core processing
     */
    public void doHandle(OrderHandleContext context, OrderHandlerChain chain, Object... args) {
        // Can I handle?
        if (Objects.isNull(getTypeEnum()) || Objects.equals(context.getTypeEnum(), getTypeEnum())) {
            // Let me handle
            doHandle(context, args);
        }
        // Pass to next handler
        chain.handle(context, args);
    }

    /**
     * Concrete business logic
     */
    protected abstract void doHandle(OrderHandleContext context, Object... args);
}
</code>

Chain Implementation

Two concrete handlers are shown:

CreateOrderHandler

and

RebateOrderHandler

. Each overrides

getTypeEnum

and implements its own

doHandle

logic.

<code>// Create order
@Slf4j
@Service
@Order(100)
public class CreateOrderHandler extends AbstractOrderHandler {
    @Override
    protected OrderTypeEnum getTypeEnum() {
        return null;
    }
    @Override
    protected void doHandle(OrderHandleContext context, Object... args) {
        log.info("default create order ... ");
        // lock inventory
        lockSku(context, args);
        // save order
        saveOrder(context);
        // deduct inventory
        deductSku(context, args);
    }
}

// Rebate order
@Service
@Slf4j
@Order(200)
public class RebateOrderHandler extends AbstractOrderHandler {
    @Override
    protected OrderTypeEnum getTypeEnum() {
        return null;
    }
    @Override
    protected void doHandle(OrderHandleContext context, Object... args) {
        log.info("default rebate order ... ");
    }
}
</code>

Define Entry Point

OrderHandlerChain

is the external entry that obtains the sorted list of

AbstractOrderHandler

beans (using Spring's @Order) and executes them.

<code>@Slf4j
@Component
public class OrderHandlerChain {
    @Autowired
    private List<AbstractOrderHandler> chain;
    @Autowired
    private ApplicationContext applicationContext;

    public void handle(OrderHandleContext context, Object... objects) {
        if (context.getPos() < chain.size()) {
            AbstractOrderHandler handler = chain.get(context.getPos());
            // move position in the chain
            context.setPos(context.getPos() + 1);
            handler.doHandle(context, this, objects);
        }
    }
}
</code>

Business Extension

When new order types appear (e.g., car orders), a new handler can be added by returning a customized

AbstractOrderHandler

bean with a specific

OrderTypeEnum

. This avoids creating a separate Java file while still generating a .class file, consuming JVM Metaspace.

<code>@Configuration
public class CarOrderHandlers {
    /**
     * Car order creation
     */
    @Bean(name = "createOrderByCar")
    public AbstractOrderHandler createOrderByCar() {
        return new CreateOrderHandler() {
            @Override
            protected OrderTypeEnum getTypeEnum() {
                return OrderTypeEnum.Car;
            }
            @Autowired
            private ApplicationContext applicationContext;
            @Override
            protected void doHandle(OrderHandleContext context, Object... args) {
                System.out.println("car order create ....");
            }
        };
    }
}
</code>

Test Code

The test simply creates a

OrderHandleContext

, sets the type to

Car

, and invokes

chain.handle

.

<code>@Slf4j
@SpringBootTest(classes = App.class)
public class OrderHandlerChainTest {
    @Resource
    private OrderHandlerChain chain;

    @Test
    public void testOrderChain() {
        OrderHandleContext context = new OrderHandleContext();
        context.setTypeEnum(OrderTypeEnum.Car);
        chain.handle(context, null);
    }
}
</code>

Conclusion

The article demonstrates how Spring’s bean ordering and @Bean definitions can be leveraged to implement the Chain of Responsibility pattern. The refactored design combines aspects of the Strategy pattern (multiple vertical routing options) with the Chain of Responsibility (horizontal processing segmentation), yielding a flexible and low‑coupling solution.

References

https://www.cnblogs.com/vcmq/p/12542399.html

http://c.biancheng.net/view/1383.html

backendChain of ResponsibilityJavaSpringdesign patternHandler
Ops Development Stories
Written by

Ops Development Stories

Maintained by a like‑minded team, covering both operations and development. Topics span Linux ops, DevOps toolchain, Kubernetes containerization, monitoring, log collection, network security, and Python or Go development. Team members: Qiao Ke, wanger, Dong Ge, Su Xin, Hua Zai, Zheng Ge, Teacher Xia.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.