`
ieye
  • 浏览: 31646 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

动态代理实现规则降级

阅读更多

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

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了,这样实现了降级功能的统一管理和规则本身的职责单一性。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics