springboot启动时动态修改feignClient注解的值,实现微服务本地debug

话不多说上代码
注解代码

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Import(FeignAnnotationUpdateRegistrar.class)
public @interface AEnableUpdateFeignRegistrar {
    /**
     * 需要修改 扫描的包,默认会使用当前类上面的EnableFeignClients里头的包
     * @return
     */
    String[] value() default {"net","com"};
}

反射修改类的代码

@Slf4j
public class FeignAnnotationUpdateRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware {

    private ResourceLoader resourceLoader;
    private Environment environment;

    private final Map<String, String> map = MapUtil.builder("scrm-component-server", "scrm-comonent-pro")
            .put("scrm-user", "tcloud-user-pro").put("scrm-crm-customer", "tcloud-customer-pro")
            // todo 这里添加需要替换的微服务名和网关对应的负载均衡名(也可动态修改为url,需要改动点代码,找到使用这个map的地方修改下)
            .put("scrm-paas-common", "http://*******")
            .map();

    @Override
    public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
        ClassPathScanningCandidateComponentProvider scanner = this.getScanner();
        scanner.setResourceLoader(this.resourceLoader);
        scanner.addIncludeFilter(new AnnotationTypeFilter(FeignClient.class));
        Set<String> basePackages = this.getBasePackages(metadata);
        Iterator var8 = basePackages.iterator();
        LinkedHashSet<BeanDefinition> candidateComponents = new LinkedHashSet();
        while (var8.hasNext()) {
            String basePackage = (String) var8.next();
            candidateComponents.addAll(scanner.findCandidateComponents(basePackage));
        }
        for (BeanDefinition definition : candidateComponents) {
            try {
                if (definition instanceof AnnotatedBeanDefinition) {
                    AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition)definition;
                    AnnotationMetadata annotationMetadata = beanDefinition.getMetadata();
                    MergedAnnotations annotations = annotationMetadata.getAnnotations();
                    Class<?> feignClass = Class.forName(beanDefinition.getBeanClassName());
                    FeignClient feignClient = feignClass.getAnnotation(FeignClient.class);
                    Object value = feignClient.value();
                    String url = this.map.get(value);
                    if (url != null) {
                        InvocationHandler h = Proxy.getInvocationHandler(feignClient);
                        // 获取 AnnotationInvocationHandler 的 memberValues 字段
                        Field hField = h.getClass().getDeclaredField("memberValues");
                        // 因为这个字段事 private final 修饰,所以要打开权限
                        hField.setAccessible(true);
                        // 获取 memberValues
                        Map memberValues = (Map) hField.get(h);
                        // 修改 value 属性值
                        memberValues.put("url",url);
                    }
                    for (MergedAnnotation<Annotation> annotation : annotations) {
                        Class<Annotation> aClass = annotation.getType();
                        if (aClass.isAssignableFrom(FeignClient.class)) {
                            Class<? extends MergedAnnotation> annotationClass = annotation.getClass();
                            Field rootAttributes = annotationClass.getDeclaredField("rootAttributes");
                            rootAttributes.setAccessible(true);
                            Object attributes = rootAttributes.get(annotation);
                            if (attributes instanceof Map) {
                                Map<String, String> map = (Map<String, String>) attributes;
                                Object value = map.get("value");
                                String url = this.map.get(value);
                                if (url != null) {
                                // 这里就是替换feignClient注解里头的url,后面的值可以自定义填写
                                    map.put("url", "https://preapiconsole.71360.com/api/app/" + url);
                                }
                            }
                        }
                    }
                }
            } catch (Exception e) {
                log.error("反射修改feign的url失败", e);
            }
        }
    }

    private ClassPathScanningCandidateComponentProvider getScanner() {
        return new ClassPathScanningCandidateComponentProvider(false, this.environment) {
            protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
                boolean isCandidate = false;
                if (beanDefinition.getMetadata().isIndependent() && !beanDefinition.getMetadata().isAnnotation()) {
                    isCandidate = true;
                }

                return isCandidate;
            }
        };
    }

    protected Set<String> getBasePackages(AnnotationMetadata importingClassMetadata) {
        Map<String, Object> attributes = importingClassMetadata.getAnnotationAttributes(EnableFeignClients.class.getCanonicalName());
        Set<String> basePackages = new HashSet();
        String[] var4 = (String[]) ((String[]) attributes.get("value"));
        int var5 = var4.length;

        int var6;
        String pkg;
        for (var6 = 0; var6 < var5; ++var6) {
            pkg = var4[var6];
            if (StringUtils.hasText(pkg)) {
                basePackages.add(pkg);
            }
        }

        var4 = (String[]) ((String[]) attributes.get("basePackages"));
        var5 = var4.length;

        for (var6 = 0; var6 < var5; ++var6) {
            pkg = var4[var6];
            if (StringUtils.hasText(pkg)) {
                basePackages.add(pkg);
            }
        }

        Class[] var8 = (Class[]) ((Class[]) attributes.get("basePackageClasses"));
        var5 = var8.length;

        for (var6 = 0; var6 < var5; ++var6) {
            Class<?> clazz = var8[var6];
            basePackages.add(ClassUtils.getPackageName(clazz));
        }

        if (basePackages.isEmpty()) {
            basePackages.add(ClassUtils.getPackageName(importingClassMetadata.getClassName()));
        }

        return basePackages;
    }

    public void setResourceLoader(ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
    }

    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }
}

特别需要注意的事项:
EnableUpdateFeignRegistrar 这个注解必须要放到EnableFeignClients前头
如下
在这里插入图片描述

6月29 更新,可能会有从其它地方引入的feign导致修改不到 比如在其它的配置类中加EnableFeignClients,或者用Import
所以在注解中加了value,value中的包都会被扫描然后反射修改注解的值,从根源上解决问题

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
可以通过实现 `FeignClientBuilderCustomizer` 接口,重写 `customize` 方法,在该方法中修改 `FeignClient` 的属性。 具体实现如下: ```java @Component public class FeignClientNameCustomizer implements FeignClientBuilderCustomizer { @Override public void customize(FeignClientBuilder builder) { Map<String, Object> feignClientProperties = builder.getFeignClientProperties(); String name = (String) feignClientProperties.get("name"); if ("oldName".equals(name)) { feignClientProperties.put("name", "newName"); } } } ``` 在 `customize` 方法中,通过 `FeignClientBuilder` 获取 `FeignClient` 的属性,判断是否需要修改,如果需要修改,就修改 `name` 属性为新的。 最后,在 `FeignClient` 接口上添加 `@EnableFeignClients(defaultConfiguration = FeignClientsConfiguration.class)` 注解,指定 `FeignClientBuilderCustomizer` 的实现类。 ```java @FeignClient(name = "oldName") public interface DemoFeignClient { @GetMapping("/demo") String demo(); } @Configuration public class FeignClientsConfiguration { @Autowired private FeignClientBuilder builder; @Autowired private FeignClientNameCustomizer feignClientNameCustomizer; @Bean public DemoFeignClient demoFeignClient() { builder.feignClientCustomizers(Collections.singletonList(feignClientNameCustomizer)); return builder.target(DemoFeignClient.class, "http://localhost:8080"); } } ``` 在 `FeignClientsConfiguration` 配置类中,注入 `FeignClientBuilder` 和 `FeignClientNameCustomizer`,并将 `FeignClientNameCustomizer` 添加到 `feignClientCustomizers` 中。最后通过 `builder.target` 方法创建 `FeignClient` 的代理对象。 这样,在启动 Spring Boot 应用时,就会自动调用 `FeignClientNameCustomizer` 的 `customize` 方法,修改 `FeignClient` 的属性

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值