这篇文章主要讲解了“Java反射与动态代理的介绍”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java反射与动态代理的介绍”吧!
一、反射
二、动态代理
1、JDK代理
2、CGLIB代理
3、JDK代理与CGLIB代理对比
概念:在运行状态中,对于任意的一个类,都能够知道这个类的所有字段和方法,对任意一个对象都能够通过反射机制调用一个类的任意方法
实现方法:JVM在第一次加载某个类时会生成一个Class对象,里面记录了这个类的信息
链接:类加载机制(留坑)
动态代理的作用:在不改变原代码的基础上增加新的功能,如日志、权限检验等
反射在动态代理中的应用:由于知道原类的字段、方法等信息,才可以通过代理类执行被代理类的方法
动态代理的实现有两种
实现方法:通过创建一个代理类,这个代理类继承于一个Proxy类,Proxy类中有一个InvocationHandler接口,这个接口持有被代理对象和一个invoke()方法。创建好代理类对象后,对该对象调用的方法都会交由invoke方法处理。invoke方法接受3个参数:代理对象、方法、参数列表。重写invoke方法便可以在原方法的基础上添加其他逻辑
一个JDK代理的简单实现:
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; // 定义一个接口 interface MyInterface { void fun(); } // 用一个类去实现这个接口 class Person implements MyInterface { @Override public void fun() { System.out.println("Person实现接口方法"); } } // 用一个类实现InvocationHandler接口 class MyInvocationHandler<T> implements InvocationHandler { //InvocationHandler持有的被代理对象 T target; public MyInvocationHandler(T target) { this.target = target; } /** * proxy:代表动态代理对象 * method:代表正在执行的方法 * args:代表调用目标方法时传入的实参 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("代理执行" + method.getName() + "方法"); // 在原方法的基础上添加其他逻辑 Object result = method.invoke(target, args); // 通过invoke方法调用原方法 return result; } } public class Main { public static void main(String[] args) { Person person = new Person(); InvocationHandler invocationHandler = new MyInvocationHandler<>(person); MyInterface proxy = (MyInterface) Proxy.newProxyInstance(Person.class.getClassLoader(), Person.class.getInterfaces(), invocationHandler); proxy.fun(); } }
输出结果:
代理执行fun方法
Person实现接口方法
缺陷:只能代理接口方法,因为JDK代理需要继承一个Proxy类,又由于Java的单继承机制,导致代理类无法继承父类的函数,只能实现接口
原理与JDK代理类似,区别在于CGLIB代理创建的代理类直接继承于被代理类,所以可以实现被代理类的方法而非仅仅接口方法
一个简单的CGLIB代理实现:
public class Main { public static void main(String[] args) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(Car.class); enhancer.setCallback(new MethodInterceptor() { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { System.out.println("before"); Object res = methodProxy.invokeSuper(obj, args); System.out.println("after"); return res; } }); Car car = (Car) enhancer.create(); car.print(); } } class Car { void print() { System.out.println("执行原方法"); } }
由于CGLIB并非JDK自带,所以需要通过Maven引入一个依赖
<dependency> <groupId>org.sonatype.sisu.inject</groupId> <artifactId>cglib</artifactId> <version>3.1.1</version> </dependency>
输出结果:
before
执行原方法
after
1、JDK代理只能实现接口方法,而CGLIB代理既可以实现接口方法也可以实现类中自带的方法
2、性能上,在JDK1.8,CGLIB3.1.1的环境上,每次创建一个代理类并执行同样的方法
当执行10000次,JDK代理用时85ms,而CGLIB代理用时190ms,明显JDK代理性能更佳;
当执行1000000(一百万)次时,两种代理耗时几乎相等;
当执行10000000次时,CGLIB代理已经优于JDK代理。
所以在执行次数少时,JDK代理性能更好;反之CGLIB代理性能更好(但是重复执行多于1000000次的任务几乎没有吧
感谢各位的阅读,以上就是“Java反射与动态代理的介绍”的内容了,经过本文的学习后,相信大家对Java反射与动态代理的介绍这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是亿速云,小编将为大家推送更多相关知识点的文章,欢迎关注!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。