动态代理实现规则的简单降级

在业务系统中实现对已有的各个业务校验规则Rule的增强,因为太多的Rule实现依赖了外部系统而变得不可控,并且系统对规则基本定位成强校验,这样我们系统的可用性以及稳定性会被外部系统所左右,于是提出了对规则可以动态降级,实现运行时绕过一些规则的校验(当然,需要在业务容忍一致性和系统可用性之间权衡)。同事的想法:提供一个基类来负责执行是否降级的功能,然后每个具体的实现类继承这个基类,在执行真正的规则校验逻辑之前,调用父类的方法判断是否走校验。我觉得这样做的问题有两点,首先,规则本身不应该去关注降级的问题,这样规则的职责更加纯粹。其次,之前已经有很多规则实现,这样做要去改变之前的规则实现,而且是通过继承的方式来修改,但是JAVA受限于单继承,同时对每个实现的改动都是类似的,比较机械化。考虑了下,决定使用动态代理对规则实现降级管理。代码实现很简单:

public class DegraderableRuleWrapper implements FactoryBean, BeanNameAware {  
      
    private final static Logger LOG = LoggerFactory.getLogger(DegraderableRuleWrapper.class);  
      
    private final static String ITEM_RULE_NAME_SKIP_NAME = "com.***.ruleSkipNameList";  
    /** 
     * 需要跳过的规则列表 
     */  
    private static Set<String> skipRuleNameList = Sets.newHashSet();  
      
    /** 
     * 用于分隔字符串的工具类 
     */  
    private static final Splitter SPLITTER = Splitter.on(',').omitEmptyStrings().trimResults();  
      
    private Rule target;  
      
    private String ruleName;   
      
    private Object delegate;  
      
    public void setTarget(Rule target) {  
        this.target = target;  
        //ruleName = target.getClass().getSimpleName();  
    }  
      
    @Override  
    public void setBeanName(String name) {  
        ruleName = name;  
    }  
      
    @Override  
    public Object getObject() throws Exception {  
          
        if (delegate == null) {  
            delegate = createProxy();  
        }  
        return delegate;  
    }  
  
    private Object createProxy() {  
        @SuppressWarnings("unchecked")  
        Class<?>[] allInterfaces = (Class<?>[]) ClassUtils.getAllInterfaces(target.getClass()).toArray(new Class<?>[0]);  
        Object wrapperedRule = Proxy.newProxyInstance(target.getClass().getClassLoader(), allInterfaces, new SwitchListener());  
          
        LOG.warn("create a degraderableRule for rule {}.", ruleName);  
          
        return wrapperedRule;  
    }  
  
    @Override  
    public Class<? extends Rule> getObjectType() {  
        return Rule.class;  
    }  
  
    @Override  
    public boolean isSingleton() {  
        return false;  
    }  
      
    static{  
        initialSkipRuleListAndListenChange();  
    }  
      
    private static void initialSkipRuleListAndListenChange() {  
        /* 
         * 开始并不主动拉取,而是注册监听,等待异步回调,减少应用启动时间。 
         */  
        Diamond.addListener(ITEM_RULE_NAME_SKIP_NAME, Constants.DEFAULT_GROUP, new ManagerListenerAdapter() {  
            @Override  
            public void receiveConfigInfo(String configInfo) {  
                LOG.warn("Got new skipRuleNameList, " + configInfo);  
                Iterable<String> ruleNames = SPLITTER.split(configInfo);  
                Set<String> newSkipRuleNames = Sets.newHashSet(ruleNames);  
                skipRuleNameList = newSkipRuleNames;  
            }  
        });  
    }  
  
    private class SwitchListener implements InvocationHandler {  
  
        @Override  
        public Object invoke(Object proxy, Method method, Object[] args)  
                throws Throwable {  
            if (skipRuleNameList.contains(ruleName)) {  
                LOG.warn("Rule {} is in skipList, skip it.", ruleName);  
                return RuleResult.successResult();  
            }  
            return method.invoke(target, args);  
        }  
          
    }  
  
}

实现中使用了spring的factorybean,beanname,google的guava工具类以及淘宝开源的diamond集中式静态配置管理工具。PS:diamond主要是实现对集群的配置管理,其他的方式也很多,比如使用zookeeper也可以,当然使用存储+线程定时轮询变化(其实diamond的实现方式就很类似,只不过加上了比较多的容灾功能)也OK。

对于实现需要注意的是这行代码:

Class<?>[] allInterfaces = (Class<?>[]) ClassUtils.getAllInterfaces(target.getClass()).toArray(new Class<?>[0]);
开始的时候直接使用

target.getClass().getInterfaces()

发现继承过来的实现,获取不到类实现的接口,也算是细节的一个点吧。

使用这个规则的地方只需要配置下这个bean即可,配置方式如下:

<bean id="testPlatformRule" class="com.***.rule.DegraderableRuleWrapper">  
        <property name="target">  
            <bean class="com.***.rule.impl.TestPlatformRule" />  
        </property>  
    </bean>
这样其他地方在引用这个bean的时候就已经是进行了降级管理的Rule了,这样实现了降级功能的统一管理和规则本身的职责单一性。  







转载于:https://my.oschina.net/liuyongpo/blog/172706

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值