序
本文主要研究一下 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
- DubboOpenFeignAutoConfiguration