前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >使用动态代理只代理接口(非实现类)

使用动态代理只代理接口(非实现类)

作者头像
算法之名
发布2019-11-29 00:41:27
5530
发布2019-11-29 00:41:27
举报
文章被收录于专栏:算法之名算法之名

面试了阿里、美团与滴滴后,我有了几个重大发现…>>>

假设现在我们有一个已知的算法,我们需要写任意一个接口打上我们特有的标签,那么这个接口的方法都可以执行这个算法,好比Mybatis的Dao,或者Feign的接口。现在假设我们这个特有的标签如下:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ProxyVersion {
}

已知的算法为打印方法的所有参数。

@Override
public Object invoke(Object[] argv) throws Throwable {
    Stream.of(argv).sequential().forEach(System.out::println);
    return null;
}

现在需求清楚了,我们来随意写个接口,并打上该标签。

@ProxyVersion
public interface ProxyTest {
    String find(String a, Integer b);
}

先写一个动态代理类

@AllArgsConstructor
public class ProxyInvocationHandler implements InvocationHandler {
    private Map<Method,MethodHandler> dispatch;

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        return dispatch.get(method).invoke(args);
    }
}

其中MethodHandler为方法处理器接口,定义如下

public interface MethodHandler {
    Object invoke(Object[] argv) throws Throwable;
}

然后写一个方法处理器接口的实现类,它包含了我们固定要实现的算法。

public class DefaultMethodHandler implements MethodHandler {

    @Override
    public Object invoke(Object[] argv) throws Throwable {
        Stream.of(argv).sequential().forEach(System.out::println);
        return null;
    }
}

我们首先写一个目标类,因为我们不知道我们要代理的是啥接口,所以使用泛型,并且包含一个该泛型的Class属性type。

@Data
@AllArgsConstructor
public class Target<T> {
    private Class<T> type;
}

然后为来创建该目标类,写一个目标工厂类,从该目标工厂类去搜索包下的所有类,并获取带有@ProxyVersion标签的接口放入我们的目标对象属性中。这里我们做了简化处理,只取第一个接口。

public class TargetFactory {
    public static Target createTarget() {
        Set<Class<?>> classes = ClassUtil.getClassSet("com.guanjian.demo.proxytest");
        List<Class<?>> collect = classes.stream()
                .filter(Class::isInterface)
                .filter(clazz -> clazz.isAnnotationPresent(ProxyVersion.class))
                .collect(Collectors.toList());
        return new Target(collect.get(0));
    }
}

ClassUtil代码请参考@Compenent,@Autowired,@PostConstruct自实现

现在我们要调用动态代理类,这里我们也做了简化处理,只取第一个方法。最终返回我们代理的接口实例

public class ProxyBean {
    public Object proxyTest() {
        Map<Method,MethodHandler> methodToHandler = new HashMap<>();
        //获取目标对象
        Target target = TargetFactory.createTarget();
        //将目标对象的方法以及方法处理器(方法处理器包含我们需要的固定算法)放入映射中
        methodToHandler.put(target.getType().getMethods()[0],new DefaultMethodHandler());
        //构建动态代理对象
        InvocationHandler handler = new ProxyInvocationHandler(methodToHandler);
        //返回动态代理代理的接口实例
        return Proxy.newProxyInstance(target.getType().getClassLoader(), new Class[]{target.getType()}, handler);
    }
}

再加一个ProxyBean的工厂

public class ProxyBeanFactory {
    public static ProxyBean createProxyBean() {
        return new ProxyBean();
    }
}

最后写测试

public class ProxyMain {

    public static void main(String[] args) {
        ProxyTest test = (ProxyTest)ProxyBeanFactory.createProxyBean().proxyTest();
        test.find("aaa",233);
    }
}

运行结果

aaa

233

如果我们换一个接口替换ProxyTest也是一样,随意定义接口,都可以获取执行的结果。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

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

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

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