SpringAOP底层原理
目录
两种实现方式
JDK动态代理
编写接口
接口的实现类
创建代理对象
测试
CGLIB动态代理
需要增强的方法
创建代理对象
测试
关于两种代理需要知道的点
两种实现方式
SpringAOP底层根据接口的使用情况,有两种的实现方式
- 有接口的时候:使用jdk动态代理
- 没有接口的情况:使用cglib动态代理
JDK动态代理
编写接口
package com.heaboy.aopdemo.jdkproxy;
public interface TargetInteface {
void method1();
void method2();
int method3(Integer i);
}
接口的实现类
package com.heaboy.aopdemo.jdkproxy;
public class Target implements TargetInteface {
@Override
public void method1() {
System.out.println("method1 running ...");
}
@Override
public void method2() {
System.out.println("method2 running ...");
}
@Override
public int method3(Integer i) {
System.out.println("method3 running ...");
return i;
}
}
创建代理对象
对于代码的解析已写在注释中方便理解,这里在invoke调用前后都添加通知 => 环绕通知
package com.heaboy.aopdemo.jdkproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class TargetProxy {
public static <T> Object getTarget(T t) {
//Proxy.newProxyInstance中的三个参数,分别对应下面的三个传入数据
//ClassLoader loader:用来知名生成代理对象所使用的类加载器
//Class<?> interfaces 用来知名目标类实现的所有接口
//InvocationHandler h 里面的方法就是这个代理对象要做的事情
return Proxy.newProxyInstance(t.getClass().getClassLoader(), t.getClass().getInterfaces(), new InvocationHandler() {
//实现InvocationHandler接口后,需要重写invoke方法,invoke方法用于调用被代理对象的方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// proxy就是目标对象t,method就是调用目标对象中方法,args就是调用目标对象中方法的参数。
//比如说:代理对象.method1(),这时proxy就是目标类,method1就是method,args就是method1方法参数。
System.out.println("执行方法前...");
Object invoke = method.invoke(t, args);
System.out.println("执行方法后...");
return invoke;
}
});
}
}
测试
package com.heaboy.aopdemo.jdkproxy;
public class TargetUser {
public static void main(String[] args) {
TargetInteface target = (TargetInteface) TargetProxy.getTarget(new Target());
target.method1();
System.out.println("-----------------------------");
target.method2();
System.out.println("-----------------------------");
System.out.println(target.method3(3));
}
}
CGLIB动态代理
需要增强的方法
package com.heaboy.aopdemo.cglibproxy;
public class Target {
public void method1() {
System.out.println("method1 running ...");
}
public void method2() {
System.out.println("method2 running ...");
}
public int method3(Integer i) {
System.out.println("method3 running ...");
return i;
}
}
创建代理对象
package com.heaboy.aopdemo.cglibproxy;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class TargetProxy {
public static <T> Object getProxy(T t) {
Enhancer en = new Enhancer(); //使用Enchancer为无接口类创建代理对象
en.setSuperclass(t.getClass());//设置要代理的目标类
en.setCallback(new MethodInterceptor() {//代理类需要完成的工作
//重写intercept方法
@Override
public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("执行方法前。。。");
//调用原有方法
Object invoke = methodProxy.invokeSuper(object, args);
// Object invoke = method.invoke(t, args);// 作用等同与上面。
System.out.println("执行方法后。。。");
return invoke;
}
});
//返回创建好的代理类对象
return en.create();
}
}
测试
package com.heaboy.aopdemo.cglibproxy;
import java.util.ArrayList;
import java.util.List;
public class TargetUser {
public static void main(String[] args) {
//创建代理类
Target target = (Target) TargetProxy.getProxy(new Target());
//打印生成的代理类全限定类名
System.out.println(target.getClass().getName());
//调用代理类方法
target.method1();
}
}
关于两种代理需要知道的点
- SpringAOP生成动态代理对象
- 实现了接口:JDK动态代理
- 无接口类:CGLIB动态代理
- SpringAOP生成动态代理对象不需要特殊编译器
- SpringAOP可以根据目标对象是否实现接口,自动选择代理模式
- 优先对接口创建代理,方便程序的解耦与维护
- 被final标记的方法 -> 方法不能重写 -> 无法被代理