假设现在我们有一个已知的算法,我们需要写任意一个接口打上我们特有的标签,那么这个接口的方法都可以执行这个算法,好比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也是一样,随意定义接口,都可以获取执行的结果。
来源:oschina
链接:https://my.oschina.net/u/3768341/blog/3134058