首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >聊聊DubboOpenFeignAutoConfiguration

聊聊DubboOpenFeignAutoConfiguration

原创
作者头像
code4it
修改2019-08-01 10:31:14
5720
修改2019-08-01 10:31:14
举报
文章被收录于专栏:码匠的流水账码匠的流水账

本文主要研究一下DubboOpenFeignAutoConfiguration

DubboOpenFeignAutoConfiguration

spring-cloud-alibaba-0.9.0.RELEASE/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboOpenFeignAutoConfiguration.java

@ConditionalOnClass(name = {"feign.Feign", TARGETER_CLASS_NAME})
@AutoConfigureAfter(name = {"org.springframework.cloud.openfeign.FeignAutoConfiguration"})
@Configuration
public class DubboOpenFeignAutoConfiguration {
​
    public static final String TARGETER_CLASS_NAME = "org.springframework.cloud.openfeign.Targeter";
​
    @Bean
    public TargeterBeanPostProcessor targeterBeanPostProcessor(Environment environment,
                                                               DubboServiceMetadataRepository dubboServiceMetadataRepository,
                                                               DubboGenericServiceFactory dubboGenericServiceFactory,
                                                               DubboGenericServiceExecutionContextFactory contextFactory) {
        return new TargeterBeanPostProcessor(environment, dubboServiceMetadataRepository,
                dubboGenericServiceFactory, contextFactory);
    }
​
}
  • DubboOpenFeignAutoConfiguration注册了TargeterBeanPostProcessor

TargeterBeanPostProcessor

spring-cloud-alibaba-0.9.0.RELEASE/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/openfeign/TargeterBeanPostProcessor.java

public class TargeterBeanPostProcessor implements BeanPostProcessor, BeanClassLoaderAware {
​
    private final Environment environment;
​
    private final DubboServiceMetadataRepository dubboServiceMetadataRepository;
​
    private final DubboGenericServiceFactory dubboGenericServiceFactory;
​
    private final DubboGenericServiceExecutionContextFactory contextFactory;
​
    private ClassLoader classLoader;
​
    public TargeterBeanPostProcessor(Environment environment,
                                     DubboServiceMetadataRepository dubboServiceMetadataRepository,
                                     DubboGenericServiceFactory dubboGenericServiceFactory,
                                     DubboGenericServiceExecutionContextFactory contextFactory) {
        this.environment = environment;
        this.dubboServiceMetadataRepository = dubboServiceMetadataRepository;
        this.dubboGenericServiceFactory = dubboGenericServiceFactory;
        this.contextFactory = contextFactory;
    }
​
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }
​
    @Override
    public Object postProcessAfterInitialization(final Object bean, String beanName) throws BeansException {
        if (isPresent(TARGETER_CLASS_NAME, classLoader)) {
            Class<?> beanClass = getUserClass(bean.getClass());
            Class<?> targetClass = resolveClassName(TARGETER_CLASS_NAME, classLoader);
            if (targetClass.isAssignableFrom(beanClass)) {
                return newProxyInstance(classLoader, new Class[]{targetClass},
                        new TargeterInvocationHandler(bean, environment, classLoader, dubboServiceMetadataRepository,
                                dubboGenericServiceFactory, contextFactory));
            }
        }
        return bean;
    }
​
    @Override
    public void setBeanClassLoader(ClassLoader classLoader) {
        this.classLoader = classLoader;
    }
}
  • TargeterBeanPostProcessor实现了BeanPostProcessor、BeanClassLoaderAware接口;其postProcessAfterInitialization方法首先判断classLoader是否有org.springframework.cloud.openfeign.Targeter,如果有则判断beanClass的父类是否是targetClass,如果是则使用Proxy.newProxyInstance进行代理,代理的InvocationHandler为TargeterInvocationHandler

TargeterInvocationHandler

spring-cloud-alibaba-0.9.0.RELEASE/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/openfeign/TargeterInvocationHandler.java

class TargeterInvocationHandler implements InvocationHandler {
​
    private final Logger logger = LoggerFactory.getLogger(getClass());
​
    private final Object bean;
​
    private final Environment environment;
​
    private final ClassLoader classLoader;
​
    private final DubboServiceMetadataRepository repository;
​
    private final DubboGenericServiceFactory dubboGenericServiceFactory;
​
    private final DubboGenericServiceExecutionContextFactory contextFactory;
​
    TargeterInvocationHandler(Object bean, Environment environment,
                              ClassLoader classLoader,
                              DubboServiceMetadataRepository repository,
                              DubboGenericServiceFactory dubboGenericServiceFactory,
                              DubboGenericServiceExecutionContextFactory contextFactory) {
        this.bean = bean;
        this.environment = environment;
        this.classLoader = classLoader;
        this.repository = repository;
        this.dubboGenericServiceFactory = dubboGenericServiceFactory;
        this.contextFactory = contextFactory;
    }
​
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        /**
         * args[0]: FeignClientFactoryBean factory
         * args[1]: Feign.Builder feign
         * args[2]: FeignContext context
         * args[3]: Target.HardCodedTarget<T> target
         */
        FeignContext feignContext = cast(args[2]);
        Target.HardCodedTarget<?> target = cast(args[3]);
​
        // Execute Targeter#target method first
        method.setAccessible(true);
        // Get the default proxy object
        Object defaultProxy = method.invoke(bean, args);
        // Create Dubbo Proxy if required
        return createDubboProxyIfRequired(feignContext, target, defaultProxy);
    }
​
    private Object createDubboProxyIfRequired(FeignContext feignContext, Target target, Object defaultProxy) {
​
        DubboInvocationHandler dubboInvocationHandler = createDubboInvocationHandler(feignContext, target, defaultProxy);
​
        if (dubboInvocationHandler == null) {
            return defaultProxy;
        }
​
        return newProxyInstance(target.type().getClassLoader(), new Class<?>[]{target.type()}, dubboInvocationHandler);
    }
​
    private DubboInvocationHandler createDubboInvocationHandler(FeignContext feignContext, Target target,
                                                                Object defaultFeignClientProxy) {
​
        // Service name equals @FeignClient.name()
        String serviceName = target.name();
        Class<?> targetType = target.type();
​
        // Get Contract Bean from FeignContext
        Contract contract = feignContext.getInstance(serviceName, Contract.class);
​
        DubboTransportedMethodMetadataResolver resolver =
                new DubboTransportedMethodMetadataResolver(environment, contract);
​
        Map<DubboTransportedMethodMetadata, RestMethodMetadata> feignRestMethodMetadataMap = resolver.resolve(targetType);
​
        if (feignRestMethodMetadataMap.isEmpty()) { // @DubboTransported method was not found from the Client interface
            if (logger.isDebugEnabled()) {
                logger.debug("@{} method was not found in the Feign target type[{}]",
                        DubboTransported.class.getSimpleName(), targetType.getName());
            }
            return null;
        }
​
        // Update Metadata
        repository.initialize(serviceName);
​
        Map<Method, FeignMethodMetadata> feignMethodMetadataMap = getFeignMethodMetadataMap(serviceName, feignRestMethodMetadataMap);
​
        InvocationHandler defaultFeignClientInvocationHandler = Proxy.getInvocationHandler(defaultFeignClientProxy);
​
        DubboInvocationHandler dubboInvocationHandler = new DubboInvocationHandler(feignMethodMetadataMap,
                defaultFeignClientInvocationHandler, classLoader, contextFactory);
​
        return dubboInvocationHandler;
    }
​
    private Map<Method, FeignMethodMetadata> getFeignMethodMetadataMap(String serviceName,
                                                                       Map<DubboTransportedMethodMetadata, RestMethodMetadata>
                                                                               feignRestMethodMetadataMap) {
        Map<Method, FeignMethodMetadata> feignMethodMetadataMap = new HashMap<>();
​
        for (Map.Entry<DubboTransportedMethodMetadata, RestMethodMetadata> entry : feignRestMethodMetadataMap.entrySet()) {
            RestMethodMetadata feignRestMethodMetadata = entry.getValue();
            RequestMetadata feignRequestMetadata = feignRestMethodMetadata.getRequest();
            DubboRestServiceMetadata metadata = repository.get(serviceName, feignRequestMetadata);
            if (metadata != null) {
                DubboTransportedMethodMetadata dubboTransportedMethodMetadata = entry.getKey();
                Map<String, Object> dubboTranslatedAttributes = dubboTransportedMethodMetadata.getAttributes();
                Method method = dubboTransportedMethodMetadata.getMethod();
                GenericService dubboGenericService = dubboGenericServiceFactory.create(metadata, dubboTranslatedAttributes);
                RestMethodMetadata dubboRestMethodMetadata = metadata.getRestMethodMetadata();
                MethodMetadata methodMetadata = dubboTransportedMethodMetadata.getMethodMetadata();
                FeignMethodMetadata feignMethodMetadata = new FeignMethodMetadata(dubboGenericService,
                        dubboRestMethodMetadata, feignRestMethodMetadata);
                feignMethodMetadataMap.put(method, feignMethodMetadata);
            }
        }
​
        return feignMethodMetadataMap;
    }
​
    private static <T> T cast(Object object) {
        return (T) object;
    }
}
  • TargeterInvocationHandler实现了InvocationHandler接口,其invoke方法执行createDubboProxyIfRequired;该方法主要是创建dubboInvocationHandler,然后进行proxy

DubboInvocationHandler

spring-cloud-alibaba-0.9.0.RELEASE/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/openfeign/DubboInvocationHandler.java

public class DubboInvocationHandler implements InvocationHandler {
​
    private final Map<Method, FeignMethodMetadata> feignMethodMetadataMap;
​
    private final InvocationHandler defaultInvocationHandler;
​
    private final DubboGenericServiceExecutionContextFactory contextFactory;
​
    private final ClassLoader classLoader;
​
    public DubboInvocationHandler(Map<Method, FeignMethodMetadata> feignMethodMetadataMap,
                                  InvocationHandler defaultInvocationHandler,
                                  ClassLoader classLoader,
                                  DubboGenericServiceExecutionContextFactory contextFactory) {
        this.feignMethodMetadataMap = feignMethodMetadataMap;
        this.defaultInvocationHandler = defaultInvocationHandler;
        this.classLoader = classLoader;
        this.contextFactory = contextFactory;
    }
​
    @Override
    public Object invoke(Object proxy, Method feignMethod, Object[] args) throws Throwable {
​
        FeignMethodMetadata feignMethodMetadata = feignMethodMetadataMap.get(feignMethod);
​
        if (feignMethodMetadata == null) {
            return defaultInvocationHandler.invoke(proxy, feignMethod, args);
        }
​
        GenericService dubboGenericService = feignMethodMetadata.getDubboGenericService();
        RestMethodMetadata dubboRestMethodMetadata = feignMethodMetadata.getDubboRestMethodMetadata();
        RestMethodMetadata feignRestMethodMetadata = feignMethodMetadata.getFeignMethodMetadata();
​
        DubboGenericServiceExecutionContext context = contextFactory.create(dubboRestMethodMetadata, feignRestMethodMetadata, args);
​
        String methodName = context.getMethodName();
        String[] parameterTypes = context.getParameterTypes();
        Object[] parameters = context.getParameters();
​
        Object result = dubboGenericService.$invoke(methodName, parameterTypes, parameters);
​
        Class<?> returnType = getReturnType(dubboRestMethodMetadata);
​
        return realize(result, returnType);
    }
​
    private Class<?> getReturnType(RestMethodMetadata dubboRestMethodMetadata) {
        String returnType = dubboRestMethodMetadata.getReturnType();
        return ClassUtils.resolveClassName(returnType, classLoader);
    }
}
  • DubboInvocationHandler主要是使用dubboGenericService.$invoke方法来执行调用

小结

  • DubboOpenFeignAutoConfiguration注册了TargeterBeanPostProcessor
  • TargeterBeanPostProcessor实现了BeanPostProcessor、BeanClassLoaderAware接口;其postProcessAfterInitialization方法首先判断classLoader是否有org.springframework.cloud.openfeign.Targeter,如果有则判断beanClass的父类是否是targetClass,如果是则使用Proxy.newProxyInstance进行代理,代理的InvocationHandler为TargeterInvocationHandler
  • TargeterInvocationHandler实现了InvocationHandler接口,其invoke方法执行createDubboProxyIfRequired;该方法主要是创建dubboInvocationHandler,然后进行proxy;DubboInvocationHandler主要是使用dubboGenericService.$invoke方法来执行调用

doc

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • DubboOpenFeignAutoConfiguration
  • TargeterBeanPostProcessor
  • TargeterInvocationHandler
  • DubboInvocationHandler
  • 小结
  • doc
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档