java:动态代理的使用
对于java的使用,真的已经有好几年了。可以说,java的方方面面差不多都有涉猎。但是,也有几个知识点,一直没有怎么涉及。比如:动态代理注解GUI可能是当时学习这些的时候,带给我太多的恐惧,导致我一直不敢再碰这些东西。不过现在回过头来,再次拾起当时让我恐惧的这些内容,没有当时那么恐惧了;相反,有一种很愉悦的感觉。顺便说一句:java中应该没有所谓的”静态代理”。因为我看到网上的各种
·
对于java
的使用,真的已经有好几年了。可以说,java
的方方面面差不多都有涉猎。但是,也有几个知识点,一直没有怎么涉及。比如:
- 动态代理
- 注解
- GUI
可能是当时学习这些的时候,带给我太多的恐惧,导致我一直不敢再碰这些东西。
不过现在回过头来,再次拾起当时让我恐惧的这些内容,没有当时那么恐惧了;相反,有一种很愉悦的感觉。
顺便说一句:
java
中应该没有所谓的”静态代理”。因为我看到网上的各种博客/教程/问答,对于静态代理的讲解,其实完全是对装饰者模式的讲解与使用而已。或者是是对聚合模式的使用而已。
闲话不多说,下面我也简单讲解一下我对动态代理的理解与使用。
DynamicProxy
Java 动态代理| jdk & cglib 两种方式实现
所谓动态代理,首先要确立一个目标就是要生成一个目标类的代理对象。
明确了这一目标,后续的实现就有了一个明确的目的性了。
- 无论是
jdk
的原生支持,还是第三方库,比如cglib
,目的都是一样的,就是生成一个目标类的代理对象。 - 拿到代理对象只后,就可以像使用目标对象一样去使用里面的方法。
- 不过既然是使用代理,就必然希望通过代理,去对目标对象对方法做一些改变,比如增强实现。(加入日志插入等)。这时候,就可以在代理实现等回调方法里面去做一些增强了。
大体上的套路就是这些。至于怎么去使用,往往要看实际应用场景了。
jdk
对动态代理的支持程度是:被代理方法,必须是接口中的方法。cglib
对动态代理对支持程度是:被代理对方法,不能是被final
修饰对方法。
好吧:下面分别给出两种实现的简单示例:
- 基于
jdk
的实现:
模拟场景:有一个
Car
类,实现类Moveable
接口。然后,通过动态代理去调用Car#move()
方法,并在方法执行的前后打印日志。
// interface movaable
interface Moveable {
boolean move(String road);
}
// class car
class Car implements Moveable {
@Override
public boolean move(String road) {
System.out.println("I am running in road: " + road);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return new Random().nextInt() % 2 == 0;
}
}
// test main
public class TestClient {
public static void main(String[] args) {
Moveable m = new Car();
Class<? extends Moveable> clazz = m.getClass();
Moveable proxyInstance = (Moveable) Proxy.newProxyInstance(clazz.getClassLoader(),
clazz.getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("do before >>>>");
long st = System.currentTimeMillis();
Object invoke = method.invoke(m, args);
long et = System.currentTimeMillis();
System.err.println("invoke = " + invoke + " , " + method + " , " + Arrays.toString(args));
System.out.println("do after <<<<<");
System.out.println(method.getName() + " 耗时: " + (et - st));
return invoke;
}
});
proxyInstance.move("Tokyo");
}
}
jdk输出如下:
do before >>>>
I am running in road: Tokyo
invoke = false , public abstract boolean com.cat.proxy.dynamic.Moveable.move(java.lang.String) , [Tokyo]
do after <<<<<
move 耗时: 1001
- 基于
cglib
的实现:
模拟场景:有一个Train
类,也有一个move
方法,通过动态代理,在move
方法执行前后,打印日志。
// class train
class Train {
public boolean move(String road) {
System.out.println("I am running in road: " + road);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return new Random().nextInt() % 2 == 0;
}
}
// test main
public class TestMain {
public static void main(String[] args) throws InterruptedException {
Train train = new Train();
proxy3(train);
}
private static void proxy3(Train train) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(train.getClass());
enhancer.setCallback((MethodInterceptor) (target, method, objects, methodProxy) -> {
System.out.println("** do before >>> .");
// Object invokeSuper = methodProxy.invokeSuper(target, objects);
Object invokeSuper = method.invoke(train, objects); // 使用 method 和 methodProxy 都可以。
System.err.println((target instanceof Train) + " , " + method + " , " + Arrays.toString(objects) + " , " + methodProxy);
System.out.println("** do after <<<< $ ");
return invokeSuper;
});
Train trainProxy = (Train) enhancer.create();
trainProxy.move("Paris");
}
}
cglib输出如下
** do before >>> .
I am running in road: Paris
** do after <<<< $
true , public boolean com.cat.proxy.dynamic.cglib.Train.move(java.lang.String) , [Paris] , net.sf.cglib.proxy.MethodProxy@78e03bb5
最后,给出完整示例代码。
更多推荐
已为社区贡献4条内容
所有评论(0)