SpringAOP原理和代理模式详解
1. SpringAOP和代理模式
SpringAOP是建立在代理模式上的,代理模式是它的底层实现机制,而SpringAOP是对代理模式在“面向切面编程”这个领域的高级封装和应用
1.1 理解两个核心概念
- 代理模式:一种结构设计模式。不想直接操作目标对象,而是创建一个代理对象。客户端调用dialing,代理在调用前后做一些处理(如权限,日志),然后再调用真正的目标,核心是控制访问
- SpringAOP:一种编程范式,用于将分散在各个业务方法中的横切关注点(如日志、事务、缓存)集中管理,核心是分离关注点
1.2 关系核心:SpringAOP如何利用代理模式
SpringAOP在运行时,并不会修改原始的业务代码。它的做法是:为你指定的目标Bean动态地创建一个代理对象,然后让这个代理对象“替身”区执行工作。具体流程如下:
- 定义切面:使用@Aspect或XML定义哪些方法(Pointcut)在什么时候(@Around、@Before、@After......)执行下面额外的逻辑
- 创建代理:当Spring容器启动,扫描到你的Bean和切面配置后,它不会直接返回UserService对象本身,按照配置生成代理类
- 拦截调用:从容器中获取到实际上是这个“代理对象”,调用userService.saveUser()时调用首先到达代理对象
- 执行增强链:代理对象会根据切面配置,依次执行@Before方法 、saveUser()本体、@After方法等
- 委托给目标:最终,代理对象会通过方法调用(反射或直接调用)区执行原始的UserService的svaeUser()方法
结论:SpringAOP中的“切面”、“通知”、“切入点”等高级概念,最终都是通过“代理对象”这个具体的技术手段实现的。没有代理模式,SpringAOP无从谈起
2. 代理模式
2.1 静态代理
代理类在编译期就已经确定了,手动编写,每个主题需要单独编写一个代理类
优点:简单,容易理解
缺点:当接口增加方法时,代理类和真实类都要进行修改
2.2 动态代理
代理类在运行时动态生成,无需为每个类手动编写代理
2.2.1JDK动态代理
要求:目标对象必须实现至少一个接口
实现:
- 定义一个接口及其实现类
- 自定义InvocationHandler并重写invoke方法,在invoke方法中我们会调用目标方法并自定义一些处理逻辑
- 通过Proxy.newProxyInstance(ClassLoder loder,Class<?>[] interfaces,InvocationHandler h)方法擦混关键代理对象
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; interface Service { void execute(); } class RealService implements Service { public void execute() { System.out.println("执行真实业务"); } } class MyInvocationHandler implements InvocationHandler { private Object target; public MyInvocationHandler(Object target) { this.target = target; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("前置增强"); Object result = method.invoke(target, args); System.out.println("后置增强"); return result; } } // 使用 Service real = new RealService(); Service proxy = (Service) Proxy.newProxyInstance( real.getClass().getClassLoader(), real.getClass().getInterfaces(), new MyInvocationHandler(real) ); proxy.execute();1. InvocationHandler
InvocationHandler接口是java动态代理的关键接口之一,它定义了一个单一的方法invoke(),用于处理被代理对象的方法调用
public interface InvocationHandler { /** * 参数说明 * proxy:代理对象 * method:代理对象需要实现的⽅法,即其中需要重写的⽅法 * args:method所对应⽅法的参数 */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable; }通过实现InvocationHandler接口,可以对被代理对象的方法进行功能增强
2. Proxy
Proxy类中使用频率最高的方法:newProxyInstance(),这个方法主要用来生成一个代理对象
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws InvocationHandler h){ // 代码省略...... }这个方法一共有三个参数:
Loader:类加载器,用于加载代理对象
interfaces:被代理类实现的一些接口(这个参数的第一也决定了JDK动态代理只能代理实现了接口的一些类)
h:实现了InvocationHandler接口的对象
2.2.2 CGLIB动态代理
要求:目标类无需实现接口类,但不能是final类,方法也不能是final
实现:
- 定义一个类
- 自定义MethodInterceptor并重写intercept方法,intercept用于增强目标方法,和JDK中的invoke方法类似
- 通过Enhancer类的create()创建代理类
import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; class RealService { public void execute() { System.out.println("真实业务"); } } class MyMethodInterceptor implements MethodInterceptor { public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("前置增强"); Object result = proxy.invokeSuper(obj, args); System.out.println("后置增强"); return result; } } // 使用 Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(RealService.class); enhancer.setCallback(new MyMethodInterceptor()); RealService proxy = (RealService) enhancer.create(); proxy.execute();1.MethodInterceptor
MethodInterceptor和JDK动态代理中的InvocationHandler类似,它只定义了一个方法intercept,用于增强目的方法
2.Enhancer.create()
用来生成一个代理对象
public static Object create(Class type, Callback callback) { //...代码省略 }type:被代理类的类型(类或接口)
callback:自定义方法拦截器MethodInterceptor
