- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
代理模式在Java中有很多应用场景,而代理又分静态代码和动态代理。静态代理是编写、编译或加载时织入代码实现,而动态代理则在运行时实现。简单而言,静态代理是在运行前就已经存在,而动态代理则在运行时才存在的。而常用的动态代理有两种实现:
现在我们来通过代码分别展示一下两种方式.
JDK Proxy是通过实现接口来实现代理的,我们先定义一个接口:
public interface Flyable {
String fly(String route);
}
接着有一个实现类:
public class Bird implements Flyable {
@Override
public String fly(String route) {
System.out.println("Route: " + route);
return route;
}
}
然后我们需要定义一个 InvocationHandler 来改动方法的逻辑,就是目标被代理后有什么不同:
public class FlyableInvocation implements InvocationHandler {
private final Flyable target;
public FlyableInvocation(Flyable target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
long start = System.nanoTime();
System.out.println(target + ": ===JDK proxy===");
Object result = method.invoke(this.target, args);
System.out.println(target + ": ===JDK proxy===");
long end = System.nanoTime();
System.out.println("Executing time: " + (end - start) + " ns");
return result;
}
}
这里我们在方法调用前后加了日志,同时也计算了一下方法的执行时间.
最终在调用的时候如下:
public class JDKDynamicProxy {
public static void main(String[] args) {
ClassLoader classLoader = JDKDynamicProxy.class.getClassLoader();
Class<?>[] interfaces = Bird.class.getInterfaces();
Bird bird = new Bird();
Flyable flyable = (Flyable) Proxy.newProxyInstance(classLoader, interfaces, new FlyableInvocation(bird));
flyable.fly("Go to pkslow.com");
}
}
通过 Proxy.newProxyInstance 方法会生成一个代理的实例,执行这个实例的方法,而原有实例 bird 被代理了.
执行结果如下:
com.pkslow.basic.jdk.Bird@3551a94: ===JDK proxy===
Route: Go to pkslow.com
com.pkslow.basic.jdk.Bird@3551a94: ===JDK proxy===
Executing time: 18195736 ns
我们还可以查看生成的代理类,可以通过添加VM参数:
# JDK 8
-Dsum.misc.ProxyGenerator.saveGeneratedFiles=true
# JDK 11
-Djdk.proxy.ProxyGenerator.saveGeneratedFiles=true
当然,也可以在Java代码中设置系统属性来实现.
设置完成,再执行程序,就会生成代理类的.class文件.
CGLib是通过继承来实现的,我们先来定义一个类:
public class Animal {
public String talk(String str) {
System.out.println("Talking: " + str);
return str;
}
}
然后定义一个Interceptor,这个类的作用就是生成代理实例,且定义如何改变目标方法的执行:
public class CGLibProxy<T> implements MethodInterceptor {
private T target;
public T getInstance(T target) {
this.target = target;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.target.getClass());
enhancer.setCallback(this);
return (T) enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
long start = System.nanoTime();
System.out.println(target + ": ===CGLib proxy===");
Object result = methodProxy.invoke(this.target, args);
System.out.println(target + ": ===CGLib proxy===");
long end = System.nanoTime();
System.out.println("Executing time: " + (end - start) + " ns");
return result;
}
}
这里同样是在方法前后加了日志,同时记录时长.
调用如下:
public class CGLibDynamicProxy {
public static void main(String[] args) {
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "/Users/larry/IdeaProjects/pkslow-samples/java-basic/jdk-cglib-proxy/target/cglib_proxy_classes");
CGLibProxy<Animal> cgLibProxy = new CGLibProxy<>();
Animal animal = cgLibProxy.getInstance(new Animal());
animal.talk("Hi, pkslow");
}
}
这里设置系统属性是为了把生成的代理类输出到 .class 文件中,方便学习查看.
执行结果如下:
com.pkslow.basic.cglib.Animal@57855c9a: ===CGLib proxy===
Talking: Hi, pkslow
com.pkslow.basic.cglib.Animal@57855c9a: ===CGLib proxy===
Executing time: 28396871 ns
JDK Proxy本质上使用的是反射的机制,而CGLib使用的是ASM,CGLib速度会更好。但它们都不支持final的类和方法,因为通过接口和继承都无法改变final方法.
代码请看GitHub: https://github.com/LarryDpk/pkslow-samples 。
最后此篇关于JavaJDKProxy和CGLib动态代理示例讲解的文章就讲到这里了,如果你想了解更多关于JavaJDKProxy和CGLib动态代理示例讲解的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我是一名优秀的程序员,十分优秀!