设计模式-责任链

工作中经常碰到一个场景:数据需要经过一系列处理后入库。最近碰巧遇到,感觉可以这个模式,就封装了一个。比较简单,直接上代码。

代码

AbstractBizHandler

使用了泛型,归属同一业务类型的责任链,子类实现时指定需要处理的数据类型。

package com.commons.chain.handler;

/**
 * AbstractBizHandler<br>
 * 业务处理抽象类,子类继承实现具体处理业务
 *
 * 使用责任链模式实现具体逻辑
 */
public abstract class AbstractBizHandler<T> {

    /**
     * 业务链中下一个业务逻辑
     */
    private AbstractBizHandler successor;

    /**
     * 模板方法,定义业务逻辑
     *
     * @param dto 子类实现泛型传入在整个处理链中需要的数据
     * @throws Exception 处理异常时返回
     */
    @SuppressWarnings("unchecked")
    public void handler(T dto) throws Exception {
        // 具体处理逻辑
        preHandler(dto);

        // 责任链还有待处理业务则继续
        if (getSuccessor() != null) {
            getSuccessor().handler(dto);
        }
    }

    /**
     * 子类实现具体处理逻辑
     */
    protected abstract void preHandler(T dto) throws Exception;

    /**
     * 子类实现,数值大小决定在每个责任链中位置
     * 数值越大,在责任链中位置越靠后
     *
     * @return 位置大小
     */
    public abstract Integer getOrder();

    public void setSuccessor(AbstractBizHandler successor) {
        this.successor = successor;
    }

    private AbstractBizHandler getSuccessor() {
        return successor;
    }

}

注解BizType

注解标识子类实现归属的业务责任链。

package com.commons.chain.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * BizType<br>
 * 业务类型
 *
 * 该注解加载{@link com.commons.chain.handler.AbstractBizHandler}的子类实现上,用于标识所归属的业务处理链
 */
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface BizType {

    /**
     * 用于标识不同业务处理链
     * 数组形式,不同的业务可以共享同一个业务处理逻辑
     */
    String[] value();
}

BizChainUtil

使用了spring的一个特性,需要引入spring的包。

package com.commons.chain.util;

import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;

import com.commons.chain.annotation.BizType;
import com.commons.chain.handler.AbstractBizHandler;

/**
 * BizChainUtil<br>
 * 业务链帮助类
 *
 * 基于spring注解,包扫描必须包含该package
 */
@Component
public class BizChainUtil implements ApplicationListener {

    private static final Logger LOGGER = LoggerFactory.getLogger(BizChainUtil.class);

    /**
     * 所有业务实现类,主键为spring中获取的beanName
     */
    private final static ConcurrentMap<String, AbstractBizHandler> CACHED_INSTANCES = new ConcurrentHashMap<String, AbstractBizHandler>();

    /**
     * 按业务分组后业务实现类,主键为业务名称
     */
    private final static Map<String, List<AbstractBizHandler>> CACHED_BIZ_CHAIN = new ConcurrentHashMap<String, List<AbstractBizHandler>>();

    /**
     * 按业务分组后业链,主键为业务名称
     */
    private final static Map<String, AbstractBizHandler> BIZ_CHAIN = new ConcurrentHashMap<String, AbstractBizHandler>();

    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        if (event instanceof ContextRefreshedEvent) {
            if (((ContextRefreshedEvent) event).getApplicationContext().getParent() == null) {
                ApplicationContext applicationContext = ((ContextRefreshedEvent) event).getApplicationContext();

                // 从spring中获取所有业务逻辑实现类
                Map<String, AbstractBizHandler> beans = applicationContext.getBeansOfType(AbstractBizHandler.class, true, false);

                // 构建业务链
                buildBizChain(beans);
            }
        }
    }

    /**
     * 构建业务链
     *
     * @param beans 业务实现类
     */
    private void buildBizChain(Map<String, AbstractBizHandler> beans) {
        for (Map.Entry<String, AbstractBizHandler> entry : beans.entrySet()) {
            String beanName = entry.getKey();
            AbstractBizHandler handler = entry.getValue();

            if (handler.getClass().isAnnotationPresent(BizType.class)) {
                // 缓存所有业务实现类
                CACHED_INSTANCES.putIfAbsent(beanName, handler);

                // 获取实现类所属业务,按业务归属分组
                List<String> allBizTypeName = Arrays.asList(handler.getClass().getAnnotation(BizType.class).value());

                for (String bizTypeName : allBizTypeName){
                    List<AbstractBizHandler> bizHandlerList = CACHED_BIZ_CHAIN.get(bizTypeName);
                    if (bizHandlerList == null || bizHandlerList.isEmpty()) {
                        bizHandlerList = new LinkedList<AbstractBizHandler>();
                        bizHandlerList.add(handler);
                        CACHED_BIZ_CHAIN.put(bizTypeName, bizHandlerList);
                    } else {
                        bizHandlerList.add(handler);
                    }
                }
            }
        }

        // 重构业务链
        refreshAllBizChain();
    }

    /**
     * 刷新所有业务链
     */
    public static void refreshAllBizChain() {
        if (!CACHED_BIZ_CHAIN.isEmpty()) {
            for (Map.Entry<String, List<AbstractBizHandler>> entry : CACHED_BIZ_CHAIN.entrySet()) {
                String bizTypeName = entry.getKey();
                List<AbstractBizHandler> bizHandlerList = entry.getValue();

                refreshBizChain(bizTypeName, bizHandlerList);
            }
        }
    }

    /**
     * 刷新指定业务链
     *
     * @param bizTypeName 业务类型名称
     */
    public static void refreshSpecailBizChain(String bizTypeName) {
        List<AbstractBizHandler> bizHandlerList = CACHED_BIZ_CHAIN.get(bizTypeName);
        if (bizHandlerList == null || bizHandlerList.isEmpty()){
            LOGGER.error("指定的业务类型{}不存在",bizTypeName);
            return;
        }

        refreshBizChain(bizTypeName, bizHandlerList);
    }

    /**
     * 手动添加业务实现类到指定业务链
     * 添加后会自动触发刷新构建新的业务链
     *
     * @param bizTypeName 业务类型名称
     * @param bizHandler 业务处理
     */
    public static void addBizHandler(String bizTypeName, AbstractBizHandler bizHandler) {
        List<AbstractBizHandler> bizHandlerList = CACHED_BIZ_CHAIN.get(bizTypeName);
        if (bizHandlerList == null || bizHandlerList.isEmpty()){
            LOGGER.error("指定的业务类型{}不存在",bizTypeName);
            return;
        }

        bizHandlerList.add(bizHandler);
        refreshBizChain(bizTypeName, bizHandlerList);
    }

    /**
     * 获取所有业务链
     */
    public static Map<String, AbstractBizHandler> getAllBizChain() {
        if (BIZ_CHAIN.isEmpty()){
            LOGGER.error("业务链还未初始化");
            return null;
        }

        return BIZ_CHAIN;
    }

    /**
     * 获取指定业务链
     *
     * @param bizTypeName 业务类型名称
     */
    public static AbstractBizHandler getSpecailBizChain(String bizTypeName) {
        AbstractBizHandler baseBizHandler = BIZ_CHAIN.get(bizTypeName);
        if (baseBizHandler == null){
            LOGGER.error("指定的业务类型{}不存在",bizTypeName);
            return null;
        }

        return baseBizHandler;
    }

    /**
     * 刷新指定业务链
     *
     * @param bizTypeName 业务类型名称
     */
    private static void refreshBizChain(String bizTypeName, List<AbstractBizHandler> bizHandlerList) {
        if (!bizHandlerList.isEmpty()) {
            // 按照order排序,数值越小,优先执行
            Collections.sort(bizHandlerList, new Comparator<AbstractBizHandler>() {
                @Override
                public int compare(AbstractBizHandler o1, AbstractBizHandler o2) {
                    return o1.getOrder().compareTo(o2.getOrder());
                }
            });

            // 组装业务处理责任链
            AbstractBizHandler baseHandler = null;
            for (int i = bizHandlerList.size() - 1; i >= 0; i--) {
                final AbstractBizHandler last = bizHandlerList.get(i);
                last.setSuccessor(baseHandler);
                baseHandler = last;
            }

            BIZ_CHAIN.put(bizTypeName, baseHandler);
        }
    }

}

applicationConsumer.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
         http://www.springframework.org/schema/context/spring-context-3.0.xsd
        ">
    <context:component-scan base-package="com.commons.chain.util" />
    <context:component-scan base-package="com.commons.chain.demo.handler" />

    <context:annotation-config/>

</beans>

demo

2条实现抽象类的业务链。

第一条业务链

CustomerRequest.java

package com.commons.chain.demo.handler.filter;

/**
 * CustomerRequest<br>
 *
 */
public class CustomerRequest {

    private String name;

    private String age;

    public CustomerRequest(){}

    public CustomerRequest(String name, String age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAge() {
        return age;
    }

    public void setAge(String age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "CustomerRequest{" +
                "name='" + name + '\'' +
                ", age='" + age + '\'' +
                '}';
    }
}

AgeFilter.java

package com.commons.chain.demo.handler.filter;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import com.commons.chain.annotation.BizType;
import com.commons.chain.handler.AbstractBizHandler;

/**
 * AgeFilter<br>
 *
 */
@BizType("filter")
@Service
public class AgeFilter extends AbstractBizHandler<CustomerRequest>  {

    private static final Logger LOGGER = LoggerFactory.getLogger(AgeFilter.class);

    @Override
    protected void preHandler(CustomerRequest dto) throws Exception {
        if (dto.getAge() == null){
            throw new Exception("请求年龄为null");
        }

        LOGGER.info("请求年龄{}", dto.getAge());
    }

    @Override
    public Integer getOrder() {
        return 2;
    }
}

NameFilter.java

package com.commons.chain.demo.handler.filter;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import com.commons.chain.annotation.BizType;
import com.commons.chain.handler.AbstractBizHandler;

/**
 * NameFilter<br>
 *
 */
@BizType("filter")
@Service
public class NameFilter extends AbstractBizHandler<CustomerRequest>  {

    private static final Logger LOGGER = LoggerFactory.getLogger(NameFilter.class);

    @Override
    protected void preHandler(CustomerRequest dto) throws Exception {
        if (dto.getName() == null){
            throw new Exception("请求名称为null");
        }

        LOGGER.info("请求姓名{}", dto.getName());
    }

    @Override
    public Integer getOrder() {
        return 1;
    }
}

第二条业务链

Policy.java

package com.commons.chain.demo.handler.policy;

/**
 * Policy<br>
 *
 */
public class Policy {

    private String type;

    private String insureDate;

    public Policy() {
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public String getInsureDate() {
        return insureDate;
    }

    public void setInsureDate(String insureDate) {
        this.insureDate = insureDate;
    }

    @Override
    public String toString() {
        return "Policy{" +
                "type='" + type + '\'' +
                ", insureDate='" + insureDate + '\'' +
                '}';
    }
}

CheckPolicy.java

package com.commons.chain.demo.handler.policy;

import org.springframework.stereotype.Service;

import com.commons.chain.annotation.BizType;
import com.commons.chain.handler.AbstractBizHandler;

/**
 * CheckPolicy<br>
 *
 */
@BizType("policy")
@Service
public class CheckPolicy extends AbstractBizHandler<Policy> {

    @Override
    protected void preHandler(Policy dto) throws Exception {
        if (dto == null || dto.getType() == null || dto.getInsureDate() == null){
            throw new Exception("入参为空");
        }
    }

    @Override
    public Integer getOrder() {
        return 1;
    }
}

SavePolicy.java

package com.commons.chain.demo.handler.policy;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import com.commons.chain.annotation.BizType;
import com.commons.chain.demo.handler.filter.AgeFilter;
import com.commons.chain.handler.AbstractBizHandler;

/**
 * SavePolicy<br>
 *
 */
@BizType("policy")
@Service
public class SavePolicy extends AbstractBizHandler<Policy> {

    private static final Logger LOGGER = LoggerFactory.getLogger(AgeFilter.class);

    @Override
    protected void preHandler(Policy dto) throws Exception {
        LOGGER.info("入库成功");
    }

    @Override
    public Integer getOrder() {
        return 2;
    }
}

test

BizChainTest.java

package com.commons.chain.demo.test;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.commons.chain.demo.handler.filter.CustomerRequest;
import com.commons.chain.demo.handler.policy.Policy;
import com.commons.chain.handler.AbstractBizHandler;
import com.commons.chain.util.BizChainUtil;

/**
 * BizChainTest<br>
 *
 */
public class BizChainTest {

    public static void main(String[] args){
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
                new String[] { "applicationConsumer.xml" });


        AbstractBizHandler<CustomerRequest> filterChain = BizChainUtil.getSpecailBizChain("filter");
        CustomerRequest request = new CustomerRequest();
        try {
            if (filterChain != null){
                filterChain.handler(request);
            }
        } catch (Exception e) {
            System.out.println("过滤业务链调用异常:"+e.getMessage());
        }

        try {
            request.setName("chris");
            if (filterChain != null){
                filterChain.handler(request);
            }
        } catch (Exception e) {
            System.out.println("过滤业务链调用异常:"+e.getMessage());
        }

        AbstractBizHandler<Policy> policyChain = BizChainUtil.getSpecailBizChain("policy");
        Policy policy = new Policy();
        try {
            if (policyChain != null){
                policyChain.handler(policy);
            }
        } catch (Exception e) {
            System.out.println("保单业务链调用异常:"+e.getMessage());
        }

        try {
            policy.setType("延迟保修");
            policy.setInsureDate("2018-01-30");
            if (policyChain != null){
                policyChain.handler(policy);
            }
            System.out.println("保单入库成功");
        } catch (Exception e) {
            System.out.println("保单业务链调用异常:"+e.getMessage());
        }
    }
}

总结

好像代码贴完了,没什么写的了,说一个写时出现的问题,BizChainUtil中有一段代码:

 @Override
    public void onApplicationEvent(ApplicationEvent event) {
        if (event instanceof ContextRefreshedEvent) {
            if (((ContextRefreshedEvent) event).getApplicationContext().getParent() == null) {
                // ....
            }
        }
    }

当时项目中使用时候第一版没这么写,用的是下面这样做的判断:

@Override
    public void onApplicationEvent(ApplicationEvent event) {
        if (ContextRefreshedEvent.class.getName().equals(event.getClass().getName())) {
            ....
}

结果导致业务链代码运行时偶发出现栈溢出,碰巧代码运行到框架的dao层调用,然后傻不拉几就去找了公司组件框架的负责人,最后也没找出来。
后来发现是spring的context问题,spring的root applicationcontext和mvc的dispatch Servlet 里面context,都会调用这边,后面就改成上面那一版。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值