Spring 代理与Aop
静态代理与动态代理:
静态代理的作用:为其他对象提供一种代理以控制对这个对象的访问。另一种情况是,有时一个客户不想或者不能直接引用另外一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
静态代理举例:
package com.zhangsan.spring.proxy; public interface Target { public void myRequest(); }
package com.zhangsan.spring.proxy; public class RealTarget implements Target { @Override public void myRequest() { System.out.println("from my real Target"); } }
package com.zhangsan.spring.proxy; public class ProxyTarget implements Target{ private RealTarget realTarget; @Override public void myRequest() { this.beforeRequest(); if(realTarget == null){ realTarget = new RealTarget(); } realTarget.myRequest(); this.afterRequest(); } private void beforeRequest(){ System.out.println("before request"); } private void afterRequest(){ System.out.println("after request"); } }
package com.zhangsan.spring.proxy; public class ProxyClient { public static void main(String[] args) { Target target = new ProxyTarget(); target.myRequest(); } }
测试结果:
before request
from my real Target
after request
针对于上述的静态代理在实际使用中,容易存在一些不足,这里归纳如下。
- 如果让一个代理类代理多个被代理类,那么会导致代理类变得过大;(一代多,代理类太大)
- 如果每个被代理类都对应一个代理类,那么会导致代理类变得过多;(一代一,代理类太多)
- 由于被代理类和代理类都需要实现相同的接口,当接口定义的方法增加或减少时,被代理类和代理类需要一起修改,不易于代码维护。
上述静态代理存在的问题,可以由动态代理来解决,即在程序运行期间,才决定代理类的生成。
动态代理是这样一种class: 在运行时生成class,在生成它时我们必须提供一组interface给它,然后该class就会声明它实现了这些interface。因此我们可以将该class的实例当作这些interface中的任何一个来用。当然,这个动态代理其实就是一个proxy,它不会替我们做实质性的工作,在生成它的实例时我们必须提供一个handler,由它接管实际的工作。
JDK动态代理:Java动态代理类位于java.lang.reflect包下,一般主要涉及到以下两个类(接口):
(1)Interface InvocationHandler:该接口定义了一个方法public object invoke(Object obj, Method method, Object[] args) 在实际使用时第一个object一般是指代理类,method是被代理的方法,args为该方法的参数数组,这个抽象方法在代理类中动态实现。
(2)Proxy:该类即为动态代理类,其中主要包括以下内容:
static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) , 通过该方法返回代理类的一个实例,返回后的代理实例可以当作代理类来使用。
JDK动态代理创建步骤:
-
创建一个接口Invocation Handler的类,它必须实现invoke方法
-
创建被代理的类及接口
-
通过Proxy的静态方法newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)创建一个代理
-
通过代理调用方法
动态代理实现样例:
package com.zhangsan.spring.dynamicProxy; public interface Subject { void myNewRequest(); }
package com.zhangsan.spring.dynamicProxy; public class RealSubject implements Subject{ @Override public void myNewRequest() { System.out.println("new request from realSubject"); } }
package com.zhangsan.spring.dynamicProxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class DynamicSubjectInvocationHandler implements InvocationHandler { private Object sub; public DynamicSubjectInvocationHandler(Object sub){ this.sub = sub; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//功能增强 System.out.println("proxy: "+ proxy.getClass()); System.out.println("before:"+method); method.invoke(sub,args); System.out.println("after:"+method); return null; } }
package com.zhangsan.spring.dynamicProxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; public class DynamicProxyClient { public static void main(String[] args) { RealSubject realSubject = new RealSubject(); InvocationHandler invocationHandler = new DynamicSubjectInvocationHandler(realSubject); Class<?> classType = invocationHandler.getClass(); Subject subject = (Subject) Proxy.newProxyInstance(classType.getClassLoader(), realSubject.getClass().getInterfaces(),invocationHandler); subject.myNewRequest(); } }
@Test
public void callMyNewRequestByReflect() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Method myNewRequest = Class.forName(Subject.class.getName()).getMethod("myNewRequest");
RealSubject realSubject = new RealSubject();
myNewRequest.invoke(realSubject);
}
main函数运行的测试结果:
proxy: class com.sun.proxy.$Proxy0
before:public abstract void com.gzz.spring.dynamicProxy.Subject.myNewRequest()
new request from realSubject
after:public abstract void com.gzz.spring.dynamicProxy.Subject.myNewRequest()
callMyNewRequestByReflect()函数运行的测试结果:
new request from realSubject
将进行反编译生成的代理类对象拷贝出来如下:
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // package com.sun.proxy; import com.gzz.spring.dynamicProxy.Subject; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.lang.reflect.UndeclaredThrowableException; public final class $Proxy0 extends Proxy implements Subject { private static Method m1; private static Method m2; private static Method m3; private static Method m0; public $Proxy0(InvocationHandler var1) throws { super(var1); } public final boolean equals(Object var1) throws { try { return (Boolean)super.h.invoke(this, m1, new Object[]{var1}); } catch (RuntimeException | Error var3) { throw var3; } catch (Throwable var4) { throw new UndeclaredThrowableException(var4); } } public final String toString() throws { try { return (String)super.h.invoke(this, m2, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final void myNewRequest() throws { try { super.h.invoke(this, m3, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final int hashCode() throws { try { return (Integer)super.h.invoke(this, m0, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } static { try { m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object")); m2 = Class.forName("java.lang.Object").getMethod("toString"); m3 = Class.forName("com.gzz.spring.dynamicProxy.Subject").getMethod("myNewRequest"); m0 = Class.forName("java.lang.Object").getMethod("hashCode"); } catch (NoSuchMethodException var2) { throw new NoSuchMethodError(var2.getMessage()); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); } } }
通过callMyNewRequestByReflect()函数,利用ava反射机制能在运行时获得类的属性和方法的特性,我们可以模拟invocationHandler的method方法的调用。
而通过反编译生成的代理类对象$Proxy0,我们可以看出代理类在调用其代理方法时,实际是调用的invocationHandler的invoke方法, 且传入的参数是代理对象$Proxy0 和通过反射获得的method m2, 而invocationHandler的invoke方法在执行时,通过反射机制实际执行的是真实对象中m2对应的接口。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!