AOP(面向切面编程)的实现方式有多种,
- ajc编译器:可以通过aspectj-maven-plugin插件在编译期对原java文件的字节码进行修改。
- agent类加载:在类加载时完成方法增强,通过设置JVM参数
-javaagent:C:/Users/manyh/.m2/repository/org/aspectj/aspectjweaver/1.9.7/aspectjweaver-1.9.7.jar
完成,其中C:/Users/manyh/.m2/repository是本地maven仓库的地址 - JDK动态代理,JDK支持的动态代理方式
- cglib动态代理,spring提供的动态代理方式
主要介绍一下JDK动态代理
和CGlib动态代理
,这两种方式也是Spring框架中使用的方式
JDK动态代理
特点:
- 1、目标对象和代理对象间是兄弟关系,都实现同一个接口
- 2、目标类可以修饰final关键字,不影响代理类的增强
public class JdkProxyDemo {
interface Foo {
void foo();
}
static class Target implements Foo {
@Override
public void foo() {
System.out.println("target foo");
}
}
// jdk 只能针对接口代理
// cglib
public static void main(String[] args) {
// 目标对象
Target target = new Target();
// 用来加载在运行期间动态生成的字节码
ClassLoader classLoader = JdkProxyDemo.class.getClassLoader();
// 代理对象
Foo proxy = (Foo) Proxy.newProxyInstance(classLoader, new Class[]{Foo.class}, (p, method, args1) -> {
System.out.println("before...");
// 通过反射调用method:方法.invoke(目标, 参数);
Object result = method.invoke(target, args1);
System.out.println("after...");
// 让代理也返回目标方法执行的结果
return result;
});
proxy.foo();
}
}
cglib动态代理
特点:
- 目标对象和代理对象间是父子关系,代理类继承目标类
- 目标类加final关键字时会报错;目标类中的方法加了final关键字虽然不会报错,但不会被代理增强
- 代理对象是通过方法重写完成的增强(静态方法不能被重写,同样也不能被增强)
public class CglibProxyDemo {
static class Target {
public void foo() {
System.out.println("target foo");
}
}
// cglib:代理是字类型,目标是父类型
public static void main(String[] args) {
Target target = new Target();
Target proxy = (Target) Enhancer.create(Target.class, new MethodInterceptor() {
/**
*
* @param o 代理类自己
* @param method 当前执行的方法
* @param args1 方法的执行参数
* @param methodProxy 方法。。。。
* @return
* @throws Throwable
*/
@Override
public Object intercept(Object o, Method method, Object[] args1, MethodProxy methodProxy) throws Throwable {
System.out.println("before...");
// 通过反射调用method:方法.invoke(目标, 参数);
// Object result = method.invoke(target, args1);
// methodProxy 它可以避免反射调用
Object result = methodProxy.invoke(target, args1);// 内部没有用反射,Spring 使用的是这种
// invokeSuper方法的参数第一个参数只需要传入代理对象,不需要目标对象
// Object result = methodProxy.invokeSuper(o, args1);// 内部没有用反射
System.out.println("after...");
return result;
}
});
proxy.foo();
}
}