美文网首页
如何给动态创建的feignClient添加configurati

如何给动态创建的feignClient添加configurati

作者: 牧羊人刘俏 | 来源:发表于2019-11-30 17:32 被阅读0次

    继续的深入到FeignClientFactoryBean

        @Override
        public Object getObject() throws Exception {
            return getTarget();
        }
    

    继续的跟下去

    FeignContext context = applicationContext.getBean(FeignContext.class);
            Feign.Builder builder = feign(context);
    

    可以看到,我们根据FeignContext创建了一个feign
    继续的跟代码

        protected Feign.Builder feign(FeignContext context) {
            FeignLoggerFactory loggerFactory = get(context, FeignLoggerFactory.class);
            Logger logger = loggerFactory.create(this.type);
    
            // @formatter:off
            Feign.Builder builder = get(context, Feign.Builder.class)
                    // required values
                    .logger(logger)
                    .encoder(get(context, Encoder.class))
                    .decoder(get(context, Decoder.class))
                    .contract(get(context, Contract.class));
            // @formatter:on
    
            configureFeign(context, builder);
    
            return builder;
        }
    

    可以看到,里面有个方法

    configureFeign(context, builder);
    

    继续的跟进去

        protected void configureFeign(FeignContext context, Feign.Builder builder) {
            FeignClientProperties properties = applicationContext.getBean(FeignClientProperties.class);
            if (properties != null) {
                if (properties.isDefaultToProperties()) {
                    configureUsingConfiguration(context, builder);
                    configureUsingProperties(properties.getConfig().get(properties.getDefaultConfig()), builder);
                    configureUsingProperties(properties.getConfig().get(this.name), builder);
                } else {
                    configureUsingProperties(properties.getConfig().get(properties.getDefaultConfig()), builder);
                    configureUsingProperties(properties.getConfig().get(this.name), builder);
                    configureUsingConfiguration(context, builder);
                }
            } else {
                configureUsingConfiguration(context, builder);
            }
        }
    

    然后可以看到

        protected void configureUsingConfiguration(FeignContext context, Feign.Builder builder) {
            Logger.Level level = getOptional(context, Logger.Level.class);
            if (level != null) {
                builder.logLevel(level);
            }
            Retryer retryer = getOptional(context, Retryer.class);
            if (retryer != null) {
                builder.retryer(retryer);
            }
            ErrorDecoder errorDecoder = getOptional(context, ErrorDecoder.class);
            if (errorDecoder != null) {
                builder.errorDecoder(errorDecoder);
            }
            Request.Options options = getOptional(context, Request.Options.class);
            if (options != null) {
                builder.options(options);
            }
            Map<String, RequestInterceptor> requestInterceptors = context.getInstances(
                    this.name, RequestInterceptor.class);
            if (requestInterceptors != null) {
                builder.requestInterceptors(requestInterceptors.values());
            }
    
            if (decode404) {
                builder.decode404();
            }
        }
    
    Map<String, RequestInterceptor> requestInterceptors = context.getInstances(
                    this.name, RequestInterceptor.class);
    

    可以在这里面看到FeignContext的getInstances方法,会返回针对特定feignclient的拦截器

    public <T> Map<String, T> getInstances(String name, Class<T> type) {
        AnnotationConfigApplicationContext context = getContext(name);
        if (BeanFactoryUtils.beanNamesForTypeIncludingAncestors(context,
                type).length > 0) {
            return BeanFactoryUtils.beansOfTypeIncludingAncestors(context, type);
        }
        return null;
    }
    
    继续的跟进去
    
    protected AnnotationConfigApplicationContext getContext(String name) {
        if (!this.contexts.containsKey(name)) {
            synchronized (this.contexts) {
                if (!this.contexts.containsKey(name)) {
                    this.contexts.put(name, createContext(name));
                }
            }
        }
        return this.contexts.get(name);
    }
    
    这里面用到了缓存,其中name就是feignClient的名字
    然后继续的的跟进去
    
    protected AnnotationConfigApplicationContext createContext(String name) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        if (this.configurations.containsKey(name)) {
            for (Class<?> configuration : this.configurations.get(name)
                    .getConfiguration()) {
                context.register(configuration);
            }
        }
        for (Map.Entry<String, C> entry : this.configurations.entrySet()) {
            if (entry.getKey().startsWith("default.")) {
                for (Class<?> configuration : entry.getValue().getConfiguration()) {
                    context.register(configuration);
                }
            }
        }
        context.register(PropertyPlaceholderAutoConfiguration.class,
                this.defaultConfigType);
        context.getEnvironment().getPropertySources().addFirst(new MapPropertySource(
                this.propertySourceName,
                Collections.<String, Object> singletonMap(this.propertyName, name)));
        if (this.parent != null) {
            // Uses Environment from parent as well as beans
            context.setParent(this.parent);
        }
        context.setDisplayName(generateDisplayName(name));
        context.refresh();
        return context;
    }
    
    所有的操作都是基于属性
    private Map<String, C> configurations = new ConcurrentHashMap<>();
    所以我们可以在这个configurations上面进行hack的操作。
    比如我们需要对xxx这个feignClient添加configuration,只需要在configurations这个属性添加 一条信息就可以了。
    代码如下
    

    @Component
    public class FeignContextPostProcessor implements BeanPostProcessor {

    @Autowired
    private XmlProcessLabelContextHolder xmlProcessLabelContextHolder;
    
    
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE)
    @Documented
    public @interface FeignClientConfiguration {
    
        String value() default "";
    
        Class<?>[] configuration() default {};
    
    
    }
    
    
    class FeignConfiguration implements RequestInterceptor {
    
        @Override
        public void apply(RequestTemplate template) {
            // in sync case
            if(xmlProcessLabelContextHolder.getXmlProcessLabelInfo().getHeaderInfo() == null){
    
                HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
                template.header(AuthInfo.HEADER_X_ID_TOKEN_PLAIN_K, AuthInfo.HEADER_X_ID_TOKEN_PLAIN_V);
                template.header(HttpHeaders.HOST, HttpRequestUtils.getClientHost(request));
                template.header(AuthInfo.HEADER_X_ID_TOKEN_K,request.getHeader(AuthInfo.HEADER_X_ID_TOKEN_K));
    
             // async case
            }else{
    
                template.header(AuthInfo.HEADER_X_ID_TOKEN_PLAIN_K, xmlProcessLabelContextHolder.getXmlProcessLabelInfo().getHeaderInfo().get(AuthInfo.HEADER_X_ID_TOKEN_PLAIN_K));
                template.header(HttpHeaders.HOST, xmlProcessLabelContextHolder.getXmlProcessLabelInfo().getHeaderInfo().get(HttpHeaders.HOST));
                template.header(AuthInfo.HEADER_X_ID_TOKEN_K,xmlProcessLabelContextHolder.getXmlProcessLabelInfo().getHeaderInfo().get(AuthInfo.HEADER_X_ID_TOKEN_K));
    
            }
    
    
        }
    }
    
    
    
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    
        if(bean instanceof FeignContext){
    
            FeignContext  feignContextBean =  (FeignContext)bean;
    
            FeignClientConfiguration con  = AnnotationUtils.findAnnotation(FeignClientDelegate.class, FeignClientConfiguration.class);
    
    
            List bffSpecificationInnerLists = Lists.newArrayList();
            bffSpecificationInnerLists.add(new SpecificationInner(con.value(),con.configuration()));
            feignContextBean.setConfigurations(bffSpecificationInnerLists);
    
            return feignContextBean;
    
        }
        return bean;
    }
    
    
    @Data
    public class SpecificationInner implements NamedContextFactory.Specification {
    
        private String name;
        private  Class<?>[] configuration;
    
        public SpecificationInner(String name,Class<?>[] configuration){
    
            this.configuration = configuration;
            this.name = name;
    
    
        }
    
    
        @Override
        public String getName() {
            return name;
        }
    
        @Override
        public Class<?>[] getConfiguration() {
            return configuration;
        }
    }
    

    }

    主要的思想就是在get FeignContext这个bean之后,动态的注册一些信息。
    ok完!!!!
    

    相关文章

      网友评论

          本文标题:如何给动态创建的feignClient添加configurati

          本文链接:https://www.haomeiwen.com/subject/ycnowctx.html