Open zpinsg opened 3 months ago
1.这种模式下默认全程都需要使用反射,你使用反射的姿势可能不对,你应该先获取ServiceInstance.class,然后获取合适的构造器,最后调用该构造器; 2.还有一种方案如果类不多的话,在module中引入spring cloud相关的依赖(版本和业务一致),然后强制这些类使用业务类加载器加载类似特殊路由的逻辑,可参考com.alibaba.jvm.sandbox.core.classloader.RoutingURLClassLoader
现在想实现通过agent的增强,对openfeign远程调用做定制化的负载均衡策略。
Spring Cloud 2021.0.0之后的版本使用的是Spring Cloud LoadBalancer进行负载均衡,我找到了一个合适的增强点:
org.springframework.cloud.loadbalancer.core#getInstanceResponse private Response getInstanceResponse(List instances) {
if (instances.isEmpty()) {
if (log.isWarnEnabled()) {
log.warn("No servers available for service: " + serviceId);
}
return new EmptyResponse();
}
其中,最后return的new DefaultResponse(instance) 中的instance为org.springframework.cloud.netflix.eureka.EurekaServiceInstance
我编写的module代码如下: public void loadCompleted() { new EventWatchBuilder(moduleEventWatcher) .onClass(CLASS_NAME) .includeBootstrap() .onBehavior(BEHAVIOR_NAME) .onWatch(new AdviceListener() { @Override protected void before(Advice advice) { defectLogger.info("触发zone-avoidance-rule模块"); try {
// List instances = (List) advice.getParameterArray()[0];
// defectLogger.info("zone-avoidance-rule模块:返回zone2的服务实例"); // Class<?> defaultResponseClass = Class.forName("org.springframework.cloud.client.loadbalancer.DefaultResponse"); // Constructor<?> constructor = defaultResponseClass.getConstructor(EurekaServiceInstance.class); // DefaultResponse defaultResponse = (DefaultResponse) constructor.newInstance(obj); // ProcessController.returnImmediately(defaultResponse);
// ProcessController.returnImmediately(new DefaultResponse((EurekaServiceInstance)obj));
// InstanceInfo instanceInfo = (InstanceInfo)MethodUtils.invokeExactMethod(obj,"getInstanceInfo"); // EurekaServiceInstance eurekaServiceInstance = new EurekaServiceInstance(instanceInfo); // defectLogger.info("zone-avoidance-rule模块:创建eurekaServiceInstance:" + eurekaServiceInstance); // ProcessController.returnImmediately(new DefaultResponse(eurekaServiceInstance)); } } } catch (Exception e) { throw new RuntimeException(e); } } }); } }
现在遇到的问题: 因为classloader不同,所以 List instances = (List) advice.getParameterArray()[0]强转会报错,我使用反射可以获取到想要的信息。
但是最后,我要通过ProcessController.returnImmediately方法返回new DefaultResponse(eurekaServiceInstance)时,怎么也绕不过去类型转换的问题。
我尝试了好多方法,可见注释的内容,核心问题是我要new DefaultResponse的构造函数需要传递ServiceInstance实例,我将obj传递进去后是构造不出来的。
困扰我好久了,望不吝赐教