一、功能概述

需要实现的功能是使用指定的 SDK 开发包来访问其他服务的资源,这种场景其实和MapperFeign 类似。所以,希望也通过接口上配置注解的方式实现。

所以在本文使用了三个注解:

  1. @RkproblemMapperScan :自定义的注解,用于指定要扫描的包名;
  2. @RkproblemMapper :自定义的注解,用于标记当前接口需要被代理;
  3. @RequestMappingSpringMvc 的注解,用于标记当前方法需要被代理,以及代理的 url

二、实现流程

2.1 创建注解

创建一个注解,添加在接口上表示当前接口需要被扫描代理。

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Component
@Indexed
public @interface RkproblemMapper {
}

创建一个开启功能的注解,可以指定需要扫描 @RkproblemMapper 注解的包名。

注解中引入了 RkproblemMapperRegister 类,将进行 Bean 的代理和注册。

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import({RkproblemMapperRegister.class})
public @interface RkproblemMapperScan {
    @AliasFor("basePackages")
    String[] value() default {};

    @AliasFor("value")
    String[] basePackages() default {};

    Class<?>[] basePackageClasses() default {};
}

2.2 Bean 注册

RkproblemMapperRegister 类用于注册 Bean,它将解析 @RkproblemMapperScan 注解的配置,然后根据配置扫描 @RkproblemMapper 注解,进行 Bean 的注册。

  • ImportBeanDefinitionRegistrar 的实现类使用 @Import 注解则会调用接口方法,将其中要注册的类注册成 bean

  • ResourceLoaderAware 获取资源加载器,可以获得外部资源文件;

  • ResourceLoaderAware 获取 Bean 的类加载器,用于加载代理类。

public class RkproblemMapperRegister implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, BeanClassLoaderAware {
    private ClassLoader classLoader;
    private ResourceLoader resourceLoader;

    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        AnnotationAttributes attributes = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(RkproblemMapperScan.class.getName(), true));
        Set<String> packages = new HashSet();
        if (attributes != null) {
            this.addPackages(packages, attributes.getStringArray("value"));
            this.addPackages(packages, attributes.getStringArray("basePackages"));
            this.addClasses(packages, attributes.getStringArray("basePackageClasses"));
            if (packages.isEmpty()) {
                packages.add(ClassUtils.getPackageName(importingClassMetadata.getClassName()));
            }
        }

        RkproblemMapperScanner scanner = new RkproblemMapperScanner(registry, this.classLoader);
        if (this.resourceLoader != null) {
            scanner.setResourceLoader(this.resourceLoader);
        }

        scanner.doScan(StringUtils.toStringArray(packages));
    }

    private void addPackages(Set<String> packages, String[] values) {
        if (values != null) {
            Collections.addAll(packages, values);
        }

    }

    private void addClasses(Set<String> packages, String[] values) {
        if (values != null) {
            String[] var3 = values;
            int var4 = values.length;

            for(int var5 = 0; var5 < var4; ++var5) {
                String value = var3[var5];
                packages.add(ClassUtils.getPackageName(value));
            }
        }

    }

    public void setBeanClassLoader(ClassLoader classLoader) {
        this.classLoader = classLoader;
    }

    public void setResourceLoader(ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
    }
}

扫描 @RkproblemMapper 注解,创建 BeanDefinition 信息。

public class RkproblemMapperScanner extends ClassPathBeanDefinitionScanner {
    private ClassLoader classLoader;

    public RkproblemMapperScanner(BeanDefinitionRegistry registry, ClassLoader classLoader) {
        super(registry, false);
        this.classLoader = classLoader;
        this.addIncludeFilter(new AnnotationTypeFilter(RkproblemMapper.class));
    }

    protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
        if (beanDefinition.getMetadata().isInterface()) {
            try {
                Class<?> target = ClassUtils.forName(beanDefinition.getMetadata().getClassName(), this.classLoader);
                return !target.isAnnotation();
            } catch (Exception var3) {
                this.logger.error("load class exception:", var3);
            }
        }

        return false;
    }

    protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
        Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);
        if (beanDefinitions.isEmpty()) {
            this.logger.warn("No @RkproblemMapper was found in '" + Arrays.toString(basePackages) + "' package. Please check your configuration.");
        } else {
            this.processBeanDefinitions(beanDefinitions);
        }

        return beanDefinitions;
    }

    private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
        Iterator var3 = beanDefinitions.iterator();

        while(var3.hasNext()) {
            BeanDefinitionHolder holder = (BeanDefinitionHolder)var3.next();
            GenericBeanDefinition definition = (GenericBeanDefinition)holder.getBeanDefinition();
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("Creating RkproblemBean with name '" + holder.getBeanName() + "' and '" + definition.getBeanClassName() + "' Interface");
            }

       
       definition.getConstructorArgumentValues().addGenericArgumentValue(Objects.requireNonNull(definition.getBeanClassName()));
            definition.setBeanClass(RkproblemRequestFactoryBean.class);
        }

    }
}

2.3 生成代理对象

用于存储接口方法中一些简要信息的实体类。

public class MethodInformation {
    private String url;
    private Type resultType;

    public MethodInformation() {
    }

    public MethodInformation(String url, Type resultType) {
        this.url = url;
        this.resultType = resultType;
    }

    public static MethodInformation build(String url, Type resultType) {
        return new MethodInformation(url, resultType);
    }

    public String getUrl() {
        return this.url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public Type getResultType() {
        return this.resultType;
    }

    public void setResultType(Type resultType) {
        this.resultType = resultType;
    }
}

解析接口方法的信息,创建代理对象。

public class RkproblemRequestFactoryBean<T> implements SmartFactoryBean<T>, ApplicationContextAware {
    private Class<T> rkproblemMapperInterface;
    private ApplicationContext applicationContext;
    private RkproblemHelperProvider provider;
    private static final Map<String, Map<String, MethodInformation>> interfaceProcessorMap = new ConcurrentHashMap(4);

    public RkproblemRequestFactoryBean(Class<T> rkproblemMapperInterface) {
        this.rkproblemMapperInterface = rkproblemMapperInterface;
    }

    public T getObject() {
        this.checkBeanIsInterface();
        return Proxy.newProxyInstance(this.rkproblemMapperInterface.getClassLoader(), new Class[]{this.rkproblemMapperInterface}, new RkproblemRequestHandler(this.provider, this.getInterfaceInformationMap()));
    }

    private Map<String, MethodInformation> getInterfaceInformationMap() {
        if (!interfaceProcessorMap.containsKey(this.rkproblemMapperInterface.getCanonicalName())) {
            Map<String, MethodInformation> methodMap = new LinkedHashMap();
            Method[] var2 = this.rkproblemMapperInterface.getMethods();
            int var3 = var2.length;

            for(int var4 = 0; var4 < var3; ++var4) {
                Method method = var2[var4];
                RequestMapping mapping = (RequestMapping)method.getAnnotation(RequestMapping.class);
                if (mapping != null) {
                    methodMap.put(method.toString(), MethodInformation.build(mapping.value()[0], method.getGenericReturnType()));
                }
            }

            interfaceProcessorMap.put(this.rkproblemMapperInterface.getCanonicalName(), methodMap);
        }

        return (Map)interfaceProcessorMap.get(this.rkproblemMapperInterface.getCanonicalName());
    }

    private void checkBeanIsInterface() {
        Assert.isTrue(this.rkproblemMapperInterface.isInterface(), "@RkproblemMapper 只能作用在接口类型上!");
    }

    public boolean isSingleton() {
        return false;
    }

    public boolean isPrototype() {
        return true;
    }

    public Class<T> getObjectType() {
        return this.rkproblemMapperInterface;
    }

    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
        if (Objects.isNull(this.provider)) {
            this.provider = (RkproblemHelperProvider)this.applicationContext.getBean(RkproblemHelperProvider.class);
        }

    }
}

代理类的处理逻辑,每个被代理的方法都会在 invoke 方法中被执行。

public class RkproblemRequestHandler implements InvocationHandler {
    private final Map<String, MethodInformation> methodInformationInvokes;
    private RkproblemHelperProvider provider;

    public RkproblemRequestHandler(RkproblemHelperProvider provider, Map<String, MethodInformation> methodInformationInvokes) {
        this.provider = provider;
        this.methodInformationInvokes = methodInformationInvokes;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Exception {
        if ("toString".equals(method.getName())) {
            return "proxy$" + method.getDeclaringClass();
        } else {
            Object body = args.length == 1 ? args[0] : (args.length > 1 ? Arrays.asList(args) : null);
            MethodInformation methodInformation = (MethodInformation)this.methodInformationInvokes.get(method.toString());
            return this.provider.apiHeader(methodInformation, body);
        }
    }
}