一个最简单的动态代理的例子
其实对于动态代理技术,大家大可不必被它的名字吓到,自己写一个就知道了。我第一次听这个东西的时候去网上看介绍,被网上的例子跟拟人的解释搞的迷迷糊糊的。像班长代理学生们向班主任交班费的例子,真的是一脸懵逼。
当然虽然我吐槽了,但是我自知自己也讲不好,所以大家不理解的回去写个最简单demo就知道了,然后慢慢扩展,想想在项目中有什么地方可以用到,不用跟逻辑太切合,能应用起来就好了,万万不要被网上的例子搞的迷糊了就觉着这个好难就放弃了,其实就那么回事儿。
其实我理解的动态代理,就是我有一个接口扔给你,你给我返回一个这个接口的实例,就这么简单。
但是实际上我们不能扔一个接口,像下面的例子中我写了一个class 实现了interface,然后把这个类的实例给create,然后create了一个代理对象出来。那我们可能会想,我既然已经有了一个类的对象为什么还要让你给我代理一个出来呢?这不是脱裤子放屁-多此一举吗。是的,下面的例子只是一个探索,实际上还是需要看使用场景的,我们先看例子。
动态代理首先得有两个最重要的东西
- 有一个接口
- 重写Proxy.newProxyInstance中的InvocationHandler
public class SimpleDynamicProxy {
public void test() {
SimpleInterface simpleInterface = createSimple(new SimpleClass());
simpleInterface.doThing1();
simpleInterface.doThing2();
}
interface SimpleInterface {
void doThing1();
void doThing2();
}
public class SimpleClass implements SimpleInterface {
@Override
public void doThing1() {
LogUtil.Companion.d("doThing1");
}
@Override
public void doThing2() {
LogUtil.Companion.d("doThing2");
}
}
private SimpleInterface createSimple(SimpleInterface object) {
/*最简单的例子,传进来一个继承了SimpleInterface的class的实例,我们拿到*/
return (SimpleInterface) Proxy.newProxyInstance(
//这里其实可以用谁的classLoader都行,只要是AppClassLoader就可以,可以用new SimpleClass().getClass().getClassLoader()代替
object.getClass().getClassLoader(),
//获取到需要代理的接口,这里可以看出来必须要有接口,没有实现接口的class是不可以动态代理的,因为没有实现接口
object.getClass().getInterfaces(),
//重写InvocationHandler,这是动态代理最重要的点,我们使用动态代理其实就是为了在下面做事情
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
LogUtil.Companion.d("simple dynamic proxy");
// 千万不可以用method.invoke(proxy, args),自己调用自己会造成递归调用,无法退出 !!!!!!!
method.invoke(object, args);
return null;
}
});
}
}
上面是最简单的动态代理的例子。我给一个集成了接口的类的对象,会返回给我一个有全部功能的代理类。
最重要的是重写InvocationHandler,我们能做的大部分事情都在重写的invoke里面,我们能拿到调用的所有的信息,包括调用的对象、方法、参数,那其实我们想在这里做什么都可以了。最简单的加统计,加曝光,或者调用某几个通用的方法,还可以判断调用的方法不同调用某个方法。
下面这个例子是加了多态的更通用的,实现了接口的多个子类调用的时候返回不同的类。
public class SimpleDynamicProxy {
public void test() {
SimpleInterface simpleInterface = createSimple(new SimpleClass1());
simpleInterface.doThing1();
SimpleInterface generalInterface1 = createT(new SimpleClass1());
generalInterface1.doThing1();
SimpleInterface generalInterface2 = createT(new SimpleClass2());
generalInterface2.doThing1();
LogUtil.Companion.d("doStringThing->" + generalInterface2.doStringThing());
LogUtil.Companion.d("doIntThing->" + generalInterface2.doIntThing());
}
interface SimpleInterface {
void doThing1();
String doStringThing();
int doIntThing();
}
public class SimpleClass1 implements SimpleInterface {
@Override
public void doThing1() {
LogUtil.Companion.d("SimpleClass1 doThing1");
}
@Override
public String doStringThing() {
return "SimpleClass1 doThing2";
}
@Override
public int doIntThing() {
return 1001;
}
}
public class SimpleClass2 implements SimpleInterface {
@Override
public void doThing1() {
LogUtil.Companion.d("SimpleClass2 doThing1");
}
@Override
public String doStringThing() {
return "SimpleClass1 doThing2";
}
@Override
public int doIntThing() {
return 1221;
}
}
private SimpleInterface createSimple(SimpleInterface object) {
/*最简单的例子,传进来一个继承了SimpleInterface的class的实例,我们拿到*/
return (SimpleInterface) Proxy.newProxyInstance(
//这里其实可以用谁的classLoader都行,只要是AppClassLoader就可以,可以用new SimpleClass().getClass().getClassLoader()代替
object.getClass().getClassLoader(),
//获取到需要代理的接口,这里可以看出来必须要有接口,没有实现接口的class是不可以动态代理的,因为没有实现接口
object.getClass().getInterfaces(),
//重写InvocationHandler,这是动态代理最重要的点,我们使用动态代理其实就是为了在下面做事情
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
LogUtil.Companion.d("simple dynamic proxy");
// 千万不可以用method.invoke(proxy, args),自己调用自己会造成递归调用,无法退出 !!!!!!!
method.invoke(object, args);
return null;
}
});
}
private <T> T createT(SimpleInterface object) {
/*更加通用的实现方式,假如我有多个实现了SimpleInterface的class,那可以实现传过来什么代理成什么的实现,可以看上面的调用。
* SimpleClass1和SimpleClass2传过来什么代理出来什么。*/
Object o = Proxy.newProxyInstance(
object.getClass().getClassLoader(),
object.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
LogUtil.Companion.d("dynamic dynamic proxy");
//返回值表示方法的返回值,String或者int或者对象或者其他...
return method.invoke(object, args);
}
});
return (T) o;
}
}
上面就是最简单的一个动态代理的例子,demo先领会,可以先往项目中小功能加一加,或者搞个ABTest加一下,领会功能。差不多了之后设计功能的时候就可以扔进去用了~~
网友评论