序
本文主要研究一下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 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 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 feignMethodMetadataMap = getFeignMethodMetadataMap(serviceName, feignRestMethodMetadataMap);
InvocationHandler defaultFeignClientInvocationHandler = Proxy.getInvocationHandler(defaultFeignClientProxy);
DubboInvocationHandler dubboInvocationHandler = new DubboInvocationHandler(feignMethodMetadataMap,
defaultFeignClientInvocationHandler, classLoader, contextFactory);
return dubboInvocationHandler;
}
private Map getFeignMethodMetadataMap(String serviceName,
Map
feignRestMethodMetadataMap) {
Map feignMethodMetadataMap = new HashMap<>();
for (Map.Entry 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 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 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 feignMethodMetadataMap;
private final InvocationHandler defaultInvocationHandler;
private final DubboGenericServiceExecutionContextFactory contextFactory;
private final ClassLoader classLoader;
public DubboInvocationHandler(Map 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