接下来都是源码分析了,在分析之前必须了解一下代理模式。
代理模式是java常用的设计模式,他的特征是代理类与委托类有同样的接口,其他类想访问这个类必须先通过代理类。
在某些情况下,一个客户在访问一个对象之前想再前后做一些固定的操作,那么这个时候就适合用到代理模式。
比较常见的:中介、快递/外卖小哥、黄牛等
我们分别通过代码来演示静态代理和动态代理
//顶层接口 public interface Person { void sayHello(); } //代理工厂类 如果多一个其他的接口 那么也要多一个代理工厂实现类 public class PersonProxy implements Person { private Person person; public PersonProxy(Person person) { this.person = person; } //静态代理 每多一个方法 就要写一遍重复的代码 public void sayHello() { System.out.println("调用前"); person.sayHello(); System.out.println("调用后"); } } //实现类 public class PersonBoyImpl implements Person { public void sayHello() { System.out.println("hello 我是男孩"); } } //main方法调用 public static void main(String[] args) { new PersonProxy(new PersonBoyImpl()).sayHello(); } //执行打印的结果 调用前 hello 我是男孩 调用后
以上就是静态代理的实现,缺点很明显,就是每个接口都需要对应的代理工厂类,每个方法都需要去写一遍重复的代码
在Java中有两种生成代理的方式我们先来看第一种JDK代理
(JDK动态代理必须要有实现接口)
Person
和实现类BoyPerson
不变//动态代理Handler类 public class PersonPoxyHandler implements InvocationHandler { //保留原始类 Object target; //创建代理类 public Object getInstance(Object target){ this.target = target; Class<?> clazz = target.getClass(); //1.生成新的class类 方法名相同 JDK代理对象为接口 //2.通过实现接口创建 //3.回调类传了this ,而此类又实现了InvocationHandler,那么调用代理类的invoke会调到当前类 return Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this); } //代理调用类 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("[JDK]代理调用之前"); //代理方法执行 此处传入原始类 Object result = method.invoke(target, args); System.out.println("[JDK]代理调用之后"); return result; } }
public static void main(String[] args) throws Exception { //传入实现类,实际上返回的对象已经是代理对象了 //如果是其他不同的类,传入不同的接口实现类就可拿到代理对象 Person person = (Person) new PersonPoxyHandler().getInstance(new BoyPerson()); person.sayHello(); } //打印结果,具体原理看后面 [JDK]代理调用之前 hello 我是xxxx [JDK]代理调用之后
因为此时拿到已经是代理类了,每次调用方法都会走到代理handler类的invoke方法
Cglib动态代理是基于字节码生成类,需要引入cglib包。
<dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.2.5</version> </dependency>
//新建一个类 里面就一个方法 public class GirlPerson{ public void sayHello() { System.out.println("hello 我是Girl"); } }
/** * cglib 动态代理 基于字节码生成类 * 需要引入cglib包 */ public class CglibProxyHandler implements MethodInterceptor { //通过字节码创建代理对象 public Object getInstance(Class<?> clazz){ Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(clazz); //回调 enhancer.setCallback(this); return enhancer.create(); } //回调 因为创建时传的也是this public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("[CGLIB]代理调用之前"); //代理方法执行 o = 原始类 methodProxy/代理类方法 调用父类 Object result = methodProxy.invokeSuper(o, objects); System.out.println("[CGLIB]代理调用之后"); return result; } }
public static void main(String[] args) throws Exception { //基于继承的形式创建的代理类,不用接口实现 GirgPerson instance = (GirgPerson)new CglibProxyHandler().getInstance(new GirgPerson().getClass()); instance.sayWorld(); } //打印结果,具体原理看后面 [CGLIB]代理调用之前 hello 我是Girl [CGLIB]代理调用之后
上面不懂的不要紧,我准备了代理类生成的源码!
//直接看 Proxy.newProxyInstance 这个方法 public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException { Objects.requireNonNull(h); //克隆一下接口 final Class<?>[] intfs = interfaces.clone(); final SecurityManager sm = System.getSecurityManager(); if (sm != null) { checkProxyAccess(Reflection.getCallerClass(), loader, intfs); } /* * Look up or generate the designated proxy class. */ //通过实现接口获得一个代理类 Class<?> cl = getProxyClass0(loader, intfs); /* * Invoke its constructor with the designated invocation handler. */ try { if (sm != null) { checkNewProxyPermission(Reflection.getCallerClass(), cl); } //获取代理类的构造方法 final Constructor<?> cons = cl.getConstructor(constructorParams); final InvocationHandler ih = h; if (!Modifier.isPublic(cl.getModifiers())) { AccessController.doPrivileged(new PrivilegedAction<Void>() { public Void run() { cons.setAccessible(true); return null; } }); } //实例化代理类 并通过构造方法传参 传入InvocationHandler return cons.newInstance(new Object[]{h}); } catch (IllegalAccessException|InstantiationException e) { throw new InternalError(e.toString(), e); } catch (InvocationTargetException e) { Throwable t = e.getCause(); if (t instanceof RuntimeException) { throw (RuntimeException) t; } else { throw new InternalError(t.toString(), t); } } catch (NoSuchMethodException e) { throw new InternalError(e.toString(), e); } }
public static void main(String[] args) throws Exception { Person person1 = new BoyPerson(); Class<?>[] interfaces = person1.getClass().getInterfaces(); byte[] bytes = ProxyGenerator.generateProxyClass("$Proxy", interfaces); FileOutputStream stream = new FileOutputStream(new File("D:/$Proxy.class")); stream.write(bytes); stream.flush(); stream.close(); }
//我们实际拿到的是这个代理对象 public final class $Proxy extends Proxy implements Person { private static Method m1; private static Method m3; private static Method m2; private static Method m0; //构造类 通过newInstance(h) 直接将InvocationHandler传参直接到父类 public $Proxy(InvocationHandler var1) throws UndeclaredThrowableException { super(var1); } //重点看这里 public final void sayHello() { try { //调用父类的h 然后调用的invoke对象 super.h.invoke(this, m3, (Object[])null); } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } static { try { m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object")); m3 = Class.forName("com.xxx.demo.动态代理.Person").getMethod("sayHello"); m2 = Class.forName("java.lang.Object").getMethod("toString"); m0 = Class.forName("java.lang.Object").getMethod("hashCode"); } catch (NoSuchMethodException var2) { throw new NoSuchMethodError(var2.getMessage()); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); } } }
从$Proxy.class代理类可以看到,通过构造方法将回调类(handler)传入代理类,然后代理会传入父类super,那么在调用方法时实际执行的是super.h.invoke(),自然就能调用到PersonPoxyHandler类实现的invoke方法了
public static void main(String[] args) throws Exception { //在main方法第一行加上这句代码,就能保存到指定目录 //存储代理类 System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\code"); //基于继承的形式创建的代理类,不用接口实现 GirgPerson instance = (GirgPerson)new CglibProxyHandler().getInstance(new GirgPerson().getClass()); instance.sayWorld(); }
//代理类对象调用方法 public final void sayHello() { MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; if (this.CGLIB$CALLBACK_0 == null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_0; } if (var10000 != null) { //回调类里面的实现方法,多的也不用展开说了 var10000.intercept(this, CGLIB$sayHello$1$Method, CGLIB$emptyArgs, CGLIB$sayHello$1$Proxy); } else { super.sayHello(); } } //set回调方法 就是handler public void setCallbacks(Callback[] var1) { this.CGLIB$CALLBACK_0 = (MethodInterceptor)var1[0]; }
动态代理的两种方式及原理已经分析就到这里,还想研究更深层次的小伙伴自行了解哦!这里提一点,动态代理在以后的代码分析中起到至关重要的作用,务必学好学懂!
以上就是本章的全部内容了。
上一篇:线程池工作线程ForkJoin的使用
下一篇:SpringMvc手写简单实现篇 - IOC容器、DI依赖注入篇
读书破万卷,下笔如有神