首先在spring容器啓動時加載所有規則校驗類。
在SpringObjectCheckManagerFactory類的afterPropertiesSet()方法中進行加載。所有規則校驗類都實現自ObjectCheck接口。
package com.taobao.member.prop.ao.check;
import com.alibaba.common.logging.Logger;
import com.alibaba.common.logging.LoggerFactory;
import com.taobao.member.prop.ao.check.concreteObjectCheck.CheckForReceiveTime;
import com.taobao.member.prop.ao.check.concreteObjectCheck.CheckForUseTime;
import com.taobao.member.prop.ao.check.impl.ObjectCheckManagerImpl;
import com.taobao.member.prop.timetask.PropTimerTask;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import java.util.Map;
/**
*
* @author zirou
*
*/
@Component("objectCheckManager")
public class SpringObjectCheckManagerFactory implements InitializingBean, FactoryBean, ApplicationContextAware {
private Logger logger = LoggerFactory.getLogger(SpringObjectCheckManagerFactory.class);
private ApplicationContext context;
public void setApplicationContext(ApplicationContext applicationContext)throws BeansException {
this.context = applicationContext;
}
@Autowired
private ObjectCheckManagerImpl objectCheckManager;
@Autowired
private PropTimerTask propTimerTask;
public Object getObject() throws Exception {
return objectCheckManager;
}
public Class<ObjectCheckManager> getObjectType() {
return ObjectCheckManager.class;
}
public boolean isSingleton() {
return true;
}
public void afterPropertiesSet() throws Exception {
propTimerTask.start();
Map<String, ObjectCheck> objectCheckListMap = objectCheckManager.getObjectCheckListMap();
String[] objectCheckNames = context.getBeanNamesForType(ObjectCheck.class, true, false);//String[] getBeanNamesForType(Class type, boolean includePrototypes, boolean includeFactoryBeans);
if ((objectCheckNames != null) && (objectCheckNames.length > 0)) {
for (String objectCheckName : objectCheckNames) {
ObjectCheck objectCheck = (ObjectCheck) context.getBean(objectCheckName, ObjectCheck.class);
ObjectCheck objectCheckInMap = objectCheckListMap.get(objectCheck.getCheckName());
if (objectCheckInMap == null) {
objectCheckListMap.put(objectCheck.getCheckName(), objectCheck);
}
}
} else {
logger.warn("No ObjectCheck is defined in the spring container");
}
objectCheckManager.setObjectCheckListMap(objectCheckListMap);
//領取時間
ObjectCheck checkForReceiveTime= objectCheckListMap.get("com.taobao.member.prop.ao.check.concreteObjectCheck.CheckForReceiveTime");
Map<String, ConditionValue> receiveMap = ((CheckForReceiveTime) checkForReceiveTime).getConditionValueMap();
String[] conditionValueNames = context.getBeanNamesForType(ConditionValue.class, true, false);
if ((conditionValueNames != null) && (conditionValueNames.length > 0)) {
for (String conditionValueName : conditionValueNames) {
ConditionValue conditionValue = (ConditionValue) context.getBean(conditionValueName, ConditionValue.class);
ConditionValue conditionValueInMap = receiveMap.get(conditionValue.getConditionValueName());
if (conditionValueInMap == null) {
receiveMap.put(conditionValue.getConditionValueName(), conditionValue);
}
}
} else {
logger.warn("No ObjectCheck is defined in the spring container");
}
((CheckForReceiveTime) checkForReceiveTime).setConditionValueMap(receiveMap);
//使用時間
ObjectCheck checkForUseTime= objectCheckListMap.get("com.taobao.member.prop.ao.check.concreteObjectCheck.CheckForUseTime");
Map<String, ConditionValue> useMap = ((CheckForUseTime) checkForUseTime).getConditionValueMap();
if ((conditionValueNames != null) && (conditionValueNames.length > 0)) {
for (String conditionValueName : conditionValueNames) {
ConditionValue conditionValue = (ConditionValue) context.getBean(conditionValueName, ConditionValue.class);
ConditionValue conditionValueInMap = useMap.get(conditionValue.getConditionValueName());
if (conditionValueInMap == null) {
useMap.put(conditionValue.getConditionValueName(), conditionValue);
}
}
} else {
logger.warn("No ObjectCheck is defined in the spring container");
}
((CheckForUseTime) checkForUseTime).setConditionValueMap(useMap);
}
}
SpringObjectCheckManagerFactory類的afterPropertiesSet()方法首先通過String[] objectCheckNames = context.getBeanNamesForType(ObjectCheck.class, true, false);從applicationContext中取所有繼承了ObjectCheck的校驗類的名稱,通過ObjectCheck objectCheck = (ObjectCheck) context.getBean(objectCheckName,
ObjectCheck.class);取名稱對應的類實例。然後將類名稱和實例分別作爲key和value,put到ObjectCheckManagerImpl的objectCheckListMap中。
下面是ObjectCheck的一個實現類,特意選這個對使用時間進行校驗的例子,是爲了跟SpringObjectCheckManagerFactory中“使用時間”部分聯繫起來看,看看是如何僅在數據庫中配置了類名卻通過這個類的實例來進行使用時間的校驗的。從上面已經put好的objectCheckListMap中取“使用時間”的類實例,再取它的conditionValueMap,將所有實現了ConditionValue接口的類都put進conditionValueMap,set回去。通過這樣的方式,我們開發一個類,在數據庫中一條記錄裏配置上全類名,就可以用其實例來進行校驗了。
import com.taobao.member.domain.prop.TmallPropRuleConfineDO;
import com.taobao.member.prop.ao.check.ConditionValue;
import com.taobao.member.prop.ao.check.ObjectCheck;
import com.taobao.member.prop.ao.check.ObjectCheckCodeConstant;
import com.taobao.member.prop.ao.check.QueryRuleConfine;
import com.taobao.member.prop.ao.ruleConfine.Branch;
import com.taobao.member.prop.ao.ruleConfine.Node;
import com.taobao.member.prop.ao.ruleConfine.RuleOperate;
import com.taobao.member.service.prop.PropConstants;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
*
* @author zirou
*
*/
@Component
public class CheckForUseTime implements ObjectCheck<QueryRuleConfine>{
Map<String,ConditionValue> conditionValueMap= new HashMap<String,ConditionValue>();
public Map<String, ConditionValue> getConditionValueMap() {
return conditionValueMap;
}
public void setConditionValueMap(Map<String, ConditionValue> conditionValueMap) {
this.conditionValueMap = conditionValueMap;
}
@Override
public String check(QueryRuleConfine queryRuleConfine) {
String result = ObjectCheckCodeConstant.OBJECT_CHECK_TRUE_CODE+":"+this.getCheckName();
TmallPropRuleConfineDO memberPropRuleConfineDO = this.buildMemberCorrespondRule(queryRuleConfine);
List<TmallPropRuleConfineDO> memberRuleTypeList = new ArrayList<TmallPropRuleConfineDO>();
List<TmallPropRuleConfineDO> thisRuleTypeList = new ArrayList<TmallPropRuleConfineDO>();
for(TmallPropRuleConfineDO tmallPropRuleConfineDO:queryRuleConfine.getUsePropRuleConfineList()){
if(tmallPropRuleConfineDO.getRuleType()==PropConstants.PROP_RULE_CONFINE_RULE_TYPE_USE_TIME){
if(tmallPropRuleConfineDO.getMemberLevel()==Integer.MIN_VALUE){//同一個propItemId的同一個rule_type下面,不可能同時存在有會員等級的和無等級的
tmallPropRuleConfineDO.setMemberLevel(queryRuleConfine.getMemberLevel());
}
thisRuleTypeList.add(tmallPropRuleConfineDO);
}
}
if(thisRuleTypeList.size()>0){
Branch root = RuleOperate.createRuleTree(thisRuleTypeList);
Node matchNode = RuleOperate.findContainsNode(root,memberPropRuleConfineDO);
if(matchNode.getPosition()==2){
ArrayList<Node> leafNodes = ((Branch)matchNode).getChildren();
Map existPart = (Map) leafNodes.get(0).getValue();
if(existPart.containsKey(PropConstants.PROP_RULE_CONFINE_CONDITION_KEY_TIME)){
if(memberPropRuleConfineDO.getConditionValue()!=null && !"".equals(memberPropRuleConfineDO.getConditionValue())){
ConditionValue conditionValue = conditionValueMap.get(memberPropRuleConfineDO.getConditionValue());
boolean isSatisfy = conditionValue.isSatisfyTimeConfine(queryRuleConfine);
if(isSatisfy){
memberPropRuleConfineDO.setConditionKey(PropConstants.PROP_RULE_CONFINE_CONDITION_KEY_TIME);
memberPropRuleConfineDO.setConditionValue(memberPropRuleConfineDO.getConditionValue());
memberRuleTypeList.add(memberPropRuleConfineDO);
}else{
return "不滿足使用的時間條件限制:"+this.getCheckName();
}
}
}
}else{
return ObjectCheckCodeConstant.OBJECT_CHECK_FALSE_CODE+":"+this.getCheckName();
}
Branch rootDeleted = RuleOperate.deleteTree(root, memberRuleTypeList);
boolean boo = RuleOperate.isAllEmptyLeaves(rootDeleted);
if(!boo) {
return ObjectCheckCodeConstant.OBJECT_CHECK_FALSE_CODE+":"+this.getCheckName();
}
}
return result;
}
protected TmallPropRuleConfineDO buildMemberCorrespondRule(QueryRuleConfine queryRuleConfine) {
TmallPropRuleConfineDO tmallPropRuleConfineDO = new TmallPropRuleConfineDO();
tmallPropRuleConfineDO.setPropId(queryRuleConfine.getPropId());
tmallPropRuleConfineDO.setPropItemId(queryRuleConfine.getPropItemId());
tmallPropRuleConfineDO.setMemberLevel(queryRuleConfine.getMemberLevel());
tmallPropRuleConfineDO.setRuleType(PropConstants.PROP_RULE_CONFINE_RULE_TYPE_USE_TIME);
tmallPropRuleConfineDO.setConditionValue(queryRuleConfine.getUseTimeProcessorClassName());
return tmallPropRuleConfineDO;
}
@Override
public int getBizType() {
return PropConstants.PROP_RULE_CONFINE_RULE_TYPE_USE_TIME;
}
@Override
public String getCheckName() {
return CheckForUseTime.class.getName();
}
}
到此時,我們已經將所有校驗的規則加載起來了,在使用時通過調用propManager的isSatisfyRuleConfine(queryRuleConfine, PropConstants.BIZ_TYPE_RECEIVE);方法進行校驗。propManager調用objectCheckService的check(queryRuleConfine, bizType);方法。
import com.alibaba.common.logging.Logger;
import com.alibaba.common.logging.LoggerFactory;
import com.taobao.member.exception.MemberException;
import com.taobao.member.prop.ao.check.ObjectCheck;
import com.taobao.member.prop.ao.check.ObjectCheckCodeConstant;
import com.taobao.member.prop.ao.check.ObjectCheckManager;
import com.taobao.member.prop.ao.check.ObjectCheckService;
import com.taobao.member.service.prop.PropConstants;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
*
* @author zirou
*
*/
@Component("objectCheckServiceImpl")
public class ObjectCheckServiceImpl implements ObjectCheckService,InitializingBean {
private Logger logger = LoggerFactory.getLogger(ObjectCheckServiceImpl.class);
private ObjectCheckManager objectCheckManager;
public void setObjectCheckManager(ObjectCheckManager objectCheckManager) {
this.objectCheckManager = objectCheckManager;
}
private ExecutorService executorService;
public void afterPropertiesSet() throws Exception {
init();
}
public void init() {
executorService = Executors.newCachedThreadPool();
}
@Override
public List<String> check(Object obj, int bizType) {
List<String> featureResult = Collections.synchronizedList(new ArrayList<String>());
List<ObjectCheck> objCheckList = objectCheckManager.getObjectCheckListByObject(obj);
// 組裝需要工作的對象檢查器
List<ObjectCheck> objCheckWorkList = new ArrayList<ObjectCheck>();
if (objCheckList != null && objCheckList.size()>0) {
if(PropConstants.ALL_BIZ_TYPE == bizType){
objCheckWorkList = objCheckList;
}else if(PropConstants.BIZ_TYPE_RECEIVE == bizType){
for (ObjectCheck objectCheck : objCheckList) {
if (PropConstants.ALL_BIZ_TYPE<=objectCheck.getBizType() && objectCheck.getBizType()<=PropConstants.BIZ_TYPE_RECEIVE) {
objCheckWorkList.add(objectCheck);
}
}
}else if(PropConstants.BIZ_TYPE_USE == bizType){
for (ObjectCheck objectCheck : objCheckList) {
if (PropConstants.ALL_BIZ_TYPE>=objectCheck.getBizType() && objectCheck.getBizType()>=PropConstants.BIZ_TYPE_USE) {
objCheckWorkList.add(objectCheck);
}
}
}else{
for (ObjectCheck objectCheck : objCheckList) {
if (bizType == objectCheck.getBizType()
|| PropConstants.ALL_BIZ_TYPE == bizType
|| PropConstants.ALL_BIZ_TYPE == objectCheck.getBizType()) {
objCheckWorkList.add(objectCheck);
}
}
}
}
if (objCheckWorkList.size() > 0) {
CountDownLatch doneSignal = new CountDownLatch(objCheckWorkList.size());
for (ObjectCheck objCheck : objCheckWorkList){
executorService.execute(new WorkerRunnable(doneSignal, objCheck, featureResult, obj));// create and start threads
}
try {
doneSignal.await();
} catch (InterruptedException e) {
logger.error("object_check_time_out_error,the obj className is {"+ obj.getClass().getName() + "}");
featureResult.add(ObjectCheckCodeConstant.OBJECT_CHECK_TIME_OUT_ERROR_CODE);
throw new MemberException(e);
}
}
return featureResult;
}
class WorkerRunnable implements Runnable {
private final CountDownLatch doneSignal;
private final ObjectCheck objectCheck;
private final List<String> featureResult;
private final Object obj;
WorkerRunnable(CountDownLatch doneSignal, ObjectCheck objectCheck,List<String> featureResult, Object obj) {
this.doneSignal = doneSignal;
this.objectCheck = objectCheck;
this.featureResult = featureResult;
this.obj = obj;
}
public void run() {
String result = doWork(objectCheck);
featureResult.add(result);
doneSignal.countDown();
}
String doWork(ObjectCheck objectCheck) {
String result = ObjectCheckCodeConstant.NONE_DEFINED_OBJECT_CHECK_ERROR_CODE;
try {
result = objectCheck.check(obj);
} catch (Exception e) {
logger.error("objCheck throw Exception ,the obj's className is {"
+ obj.getClass().getName() + "} and "
+ "the objectCheck class is {"
+ objectCheck.getClass().getName() + "}", e);
}
return result;
}
}
}
check方法首先取已經初始化好的objectCheckManagerImpl的objectCheckListMap,根據是領取還是使用,從這個objectCheckListMap過濾出校驗的規則限制列表,對其中的每條規則校驗通過從線程池中取到的某線程進行校驗。