本文主要研究一下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); } }
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; } }
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; } }
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); } }