注册过程
1、注册定时任务,每隔60秒执行一次
@Component
@EnableScheduling
public class CacheTaskVersionMapScan implements SchedulingConfigurer {
@Resource
private CacheversionTask cacheVersionTask;
@Resource
private LogicCalcBeanLoadingTask logicCalcBeanLoadingTask;
@Resource
private LogicTaskTrigger logicTaskTrigger;
@Resource
private TaskTrigger taskTrigger;
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar){
taskRegistrar.addTriggerTask(cacheVersionTask,taskTrigger);
taskRegistrar.addTriggerTask(logicCalcBeanLoadingTask,logicTaskTrigger);
}
}
public static String getLogicLoadingTaskCron(){
String cronText "0 * * * * ?";
//通过MCC修改cronText实现动态定时更新
return cronText;
}
2、扫描DB中的配置信息
QOverride
public void run(){
//是否更新开关
if(!MccConfigutil.LoadLogicCalcThriftInterface()){
return;
}
//从缓存中加载需要处理的Bean而非查询缓存,此步骤可以换成直接查缓存
List<DynLogicBean>allUsingLogicBeans loadLogicService.getUsingBeans();
//没有配置任何信息直接跳过
if(CollectionUtils.isEmpty(allUsingLogicBeans)){
return;
}
//得到ApplicationContext中的DefaultListableBeanFactory
GenericApplicationContext context = (GenericApplicationContext)ApplicationContextServiceUtil.getContext();
DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory)context.getBeanFactory();
//admin端保证beanname在新建之后不能修改,否则会有很多垃圾bean清理不掉
for(DynLogicBean dynLogicBean allUsingLogicBeans){
//如果spring中注册过,并且版本spring==db,直接跳过
//没有跳过的这些配置要么是新增加的要么是更新过的,直接重新注册即可
defaultListableBeanFactory.registerBeanDefinition(dynLogicBean.getBeanName(), beanDefinitionBuilder.getRawBeanDefinition());
//原来的做法是卸载:defaultListableBeanFactory.removeBeanDefinition(dynLogicBean.getBeanName());
}
}
3、如何解析BD
// 通过BeanDefinitionBuilder创建bean定义
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(ThriftClientProxy.class);
beanDefinitionBuilder.setDestroyMethodName("destroy");
// 添加属性
// 添加必须属性
beanDefinitionBuilder.addPropertyValue("serviceInterface", CMigSupplyCalcThriftService.class);
beanDefinitionBuilder.addPropertyValue("timeout", dynLogicBean.getTimeout());
beanDefinitionBuilder.addPropertyValue("serverDynamicWeight", dynLogicBean.getServerDynamicWeight());
beanDefinitionBuilder.addPropertyValue("appKey", dynLogicBean.getAppkey());
beanDefinitionBuilder.addPropertyValue("remoteAppkey", dynLogicBean.getRemoteAppkey());
beanDefinitionBuilder.addPropertyValue("remoteServerPort", dynLogicBean.getRemoteServerPort());
// 链接属性设置,默认米格的thrift链接数设置
String configBeanName = "wmFilterThriftPoolConfig";
if(dynLogicBean.getUseConnConfig()) {//使用自定义的ThriftPoolConfig,并且如果启用了,admin端保证maxActive,maxIdle等不能为空
configBeanName = dynLogicBean.getBeanName() + configBeanSuffix;
if(context.containsBean(configBeanName)) {//有config,清理掉,重新加载,能走到这个逻辑里来,说明供给计算bean本身版本已经变化了
defaultListableBeanFactory.removeBeanDefinition(configBeanName);
}
BeanDefinitionBuilder configBuilder = BeanDefinitionBuilder.genericBeanDefinition(MTThriftPoolConfig.class);
configBuilder.addPropertyValue("maxActive", dynLogicBean.getMaxActive());
configBuilder.addPropertyValue("maxIdle", dynLogicBean.getMaxIdle());
configBuilder.addPropertyValue("minIdle", dynLogicBean.getMinIdle());
configBuilder.addPropertyValue("maxWait", dynLogicBean.getMaxWait());
configBuilder.addPropertyValue("testOnBorrow", dynLogicBean.getTestOnBorrow());
configBuilder.addPropertyValue("testOnReturn", dynLogicBean.getTestOnReturn());
configBuilder.addPropertyValue("testWhileIdle", dynLogicBean.getTestWhileIdle());
//加载ThriftPoolConfig bean
defaultListableBeanFactory.registerBeanDefinition(configBeanName, configBuilder.getRawBeanDefinition());
}
// 如果没开启,使用默认的名字是 wmFilterThriftPoolConfig 如果开启了,使用的名字是 dynLogicBean.getBeanName() + configBeanSuffix;
beanDefinitionBuilder.addPropertyReference("mtThriftPoolConfig", configBeanName);
//!!!预留了支持异步的参数,但建议暂时不启用,因为对方完全可能随时吧async属性从true改为false,在供给计算中先取配置,再判断是否是异步调用,很浪费时间,没必要
if (dynLogicBean.getSupportAsync()) {
beanDefinitionBuilder.addPropertyValue("async", dynLogicBean.getAsync());
beanDefinitionBuilder.addPropertyValue("nettyIO", dynLogicBean.getNettyIo());
}
//注册
defaultListableBeanFactory.registerBeanDefinition(dynLogicBean.getBeanName(), beanDefinitionBuilder.getRawBeanDefinition());
如何在BD上绑定Hystrix的信息?
/更改Hystrix链接属性
//ConfigurationManager.getConfigInstance().setProperty方法中有synchronized,绝对不能在运行时线程中调用该方法
//HystrixServiceProxy(的构造器)中的commandkey就是以beanname命名的
if(HystrixCommandProperties.ExecutionIsolationStrategy.SEMAPHORE.equals(dynLogicBean.getExecutionIsolationStrategy()))
ConfigurationManager.getConfigInstance().setProperty("hystrix.command."dynLogicBean.getBeanName()+".execution.isolation.strategy",Hystr
ConfigurationManager.getConfigInstance().setProperty("hystrix.command."+dynLogicBean.getBeanName()+".execution.isolation.semaphore.maxCon
ConfigurationManager.getConfigInstance().setProperty("hystrix.command."+dynLogicBean.getBeanName()+".execution.isolation.thread.timeoutIn
ConfigurationManager.getConfigInstance().setProperty("hystrix.command."+dynLogicBean.getBeanName()+".circuitBreaker.errorThresholdPercent
}eLse{//线程池方式为默认方式
ConfigurationManager.getConfigInstance().setProperty("hystrix.command."dynLogicBean.getBeanName()+".execution.isolation.strategy",Hystr
ConfigurationManager.getConfigInstance().setProperty("hystrix.command."dynLogicBean.getBeanName()+".execution.isolation.thread.timeoutIn
ConfigurationManager.getConfigInstance().setProperty("hystrix.command."+dynLogicBean.getBeanName()+".circuitBreaker.errorThresholdPercent
}
调用关系
DynamicIOCCalculationEngine
1、获取动态bean的定义
@Override
public SupplyResult calculateSupply(RawData rawData){
// 1、上下文中会包含逻辑类型
ThirdPartyCalcConfig tpcc rawData.getTpcc();
int logicTypeCode tpcc.getLogicTypeCode();
DynLogicBean LogicBean = getCalcBeanByLogicCode(LogicTypeCode);
if(logicBean!=nuLL){
WmCMigSupplyCalcRequest request new WmCMigSupplyCalcRequest();
request.setclient(tpcc.getclient());
request.setVersion(tpcc.getVersionstr());
request.setCityId(tpcc.getcityId());
request.setDistrictId(tpcc.getDistrictId());
request.setLat(tpcc.getLat());
request.setLng(tpcc.getLng());
request.setUserId(tpcc.getUserId());
request.setUvid(tpcc.getUuid());
reqvest.setPoiIdList(tpcc.getPoiIdList());
//2、使用hystrix进行包装,供给计算
HystrixServiceProxy hystrixServiceProxy = new HystrixServiceProxy(logicBean.getBeanName(),request);
WmCMigSupplyCalcResponse response hystrixServiceProxy.execute();
}
}
2、与Hystrix组合
class HystrixServiceProxy extends HystrixCommand<WmCMigSupplyCalcResponse>{
public HystrixServiceProxy(String name,WmCMigSupplyCalcRequest request){
super(
Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(name:name "Group"))
.andCommandKey(HystrixCommandKey.Factory.asKey(name))
);
this.request request;
}
}
@Override
protected WmCMigSupplyCalcResponse getFallback(){
WmCMigSupplyCalcResponse fallbackResponse = new WmCMigSupplyCalcResponse();
fallbackResponse.setHasSupply(false);
return fallbackResponse;
}
@Override
protected WmCMigSupplyCalcResponse run()throws Exception{
WmCMigSuppLyCalcResponse response nuLL;
try{
//**通过beanName得到动态注册的bean**
CMigSupplyCalcThriftService.Ifaceiface = ApplicationContextServiceutil.getSupplyCalcServiceByBeanName(this.name);
if(iface !null){
//供给计算
response iface.calcSupply(this.request);
} catch (Exception e){
Logger.error(format:"HystrixServiceProxy run error",e);
return response;
}
}
调用梳理
1、api会传入聚类,聚类上会绑定logicType的值
ThirdPartyCalcConfig tpcc rawData.getTpcc();
int logicTypeCode tpcc.getLogicTypeCode();
DynLogicBean LogicBean = getCalcBeanByLogicCode(LogicTypeCode);
2、用logicType在缓存中查找DB中的配置信息
private LoadingCache<string,Pair<List<DynLogicBean>,List<LogicType>>>calcUsingBeansCache = CacheBuilder.newBuilder()
expireAfterWrite(duration:10,TimeUnit.MINUTES)
refreshAfterWrite(MccConfigUtil.LogicLoadingCacheRefreshTime(TimeUnit.SECONDS)
.maximumSize(10000)
build(new CacheLoader<String,Pair<List<DynLogicBean>,List<LogicType>>>(){
aOverride
public Pair<List<DynLogicBean>,List<LogicType>>Load(String key)throws Exception
return Pair.of(LoadLogicDao.getUsingBeans(),LoadLogicDao.getALlLogicType());
3、创建HystrixServiceProxy,每次请求都会创建一个新的该对象是否影响性能,影响不大,因为Hystrix的底层就是https://www.cnblogs.com/frankcui/p/15249295.html 执行HystrixServiceProxy对象 HystrixCommand 的创建时机
HystrixServiceProxy hystrixServiceProxy = new HystrixServiceProxy(logicBean.getBeanName(),request);
WmCMigSupplyCalcResponse response = hystrixServiceProxy.execute();
4、在HystrixServiceProxy的run方法中通过beanName找到动态注册的服务对象
CMigSupplyCalcThriftService.Iface iface = ApplicationContextServiceutil.getSupplyCalcServiceByBeanName(this.name);
if(iface !null){
response iface.calcSupply(this.request);
}
5、注解原理解析
@HystrixCommand(groupKey = "CbaseFilterService",commandKey = "calcPolicySupply",fallbackMethod = "calcPolicySupplyFallback",
commandProperties = {
@HystrixProperty(name = HystrixPropertiesManager.EXECUTION_ISOLATION_STRATEGY, value = "THREAD"),
@HystrixProperty(name = HystrixPropertiesManager.EXECUTION_ISOLATION_THREAD_TIMEOUT_IN_MILLISECONDS, value = "60"),
@HystrixProperty(name=HystrixPropertiesManager.CIRCUIT_BREAKER_ERROR_THRESHOLD_PERCENTAGE,value = "10")
},
threadPoolProperties = {
@HystrixProperty(name = HystrixPropertiesManager.CORE_SIZE, value = HystrixCons.CBaseFilterHystrixConfig.THREAD_POOL_CORE_SIZE)
}
)