Spring底层原理学习笔记--第十一讲--(aop之proxy增强-jdk及aop之proxy增强-cglib)
AOP实现之proxy
-
1.jdk动态代理实现及要点
-
2.cglib代理实现及要点
invoke与invokeSuper区别
jdk动态代理实现及要点
package com.lucifer.itheima.a12;
import java.lang.reflect.Proxy;
public class JdkProxyDemo {
interface Foo{
void foo();
}
//该类可以设置成final类型
//jdk中的代理跟目标是平级的兄弟关系,他们都实现了共同的接口
static class Target implements Foo{
public void foo(){
System.out.println("target foo");
}
}
//jdk只能对接口代理
//cglib 没有限制,可以对接口代理,如果没有接口的话也可以
public static void main(String[] param) {
// ClassLoader loader = JdkProxyDemo.class.getClassLoader(); // 用来加载在运行期间动态生成的字节码
// //ClassLoader的作用:
// // 代理类跟普通类有一个差别,普通类是先写java源代码,java源代码编译成java字节码,最后经过类加载然后可以使用
// // 而代理类没有源码,它是在运行期间,直接生成代理类的字节码,生成后的字节码也要被加载后才能运行,谁来做这个操作呢,由我们的Classloader来做这个操作
// //所以类加载器主要是用于加载代理类内部生成的字节码
//
// Foo proxy = (Foo)Proxy.newProxyInstance(loader, new Class[] { Foo.class }, (p, method, args) -> {
// System.out.println("before...");
// return null;
// });
//
// //参数二
// // 将来要生成的代理,要实现的是哪个接口
// // 参数三是干什么的,大家想代理类创建出来了,它也实现了我们的接口,它要实现接口中的抽象方法,必须规定这些方法的行为,那谁来把这些行为进行封装呢,就是第三个参数来做的
//
// //总结:参数1: 用来加载在运行期间动态生成的字节码
// //参数2:将来要实现的接口
// //参数3:代理类调用任何代理方法时,要执行的一些行为
//
//
// //输出结果为
before...
// proxy.foo();
//目标对象
Target target = new Target();
ClassLoader loader = JdkProxyDemo.class.getClassLoader(); //用来加载在运行期间动态生成的字节码
Foo proxy = (Foo)Proxy.newProxyInstance(loader,new Class[]{Foo.class},(p,method,args) -> {
System.out.println("before...");
//目标.方法(参数)
//方法.invoke(目标,参数)
Object result = method.invoke(target,args);
System.out.println("after...");
return result; //让代理也返回目标方法执行的结果
});
// //输出结果为
// before...
// target foo
// after...
proxy.foo();
}
}
cglib代理实现及要点
package com.lucifer.itheima.a12;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
public class CglibProxyDemo {
// 该类不能设置成final类型 因为目标加了final 意味着将来不能有子类,但是代理就是想成为目标的子类型,所以会冲突
static class Target{
// 这个方法如果是final类型的也不能增强,因为既然是子夫级的关系,那肯定是通过方法的重写来获得的增强,既然是方法重写,那对于final类型肯定不再适用,因为final的方法是不能被重写不能被继承的
public final void foo() {
//加了final之后的输出结果为
// target foo
// 不会报错,但是不具备before、after的增强功能了
System.out.println("target foo");
}
}
//代理是子类型,目标是父类型
//跟jdk的动态代理不一样,jdk中的代理跟目标是平级的兄弟关系,他们都实现了共同的接口
public static void main(String[] args) {
Target target = new Target();
Target proxy = (Target)Enhancer.create(Target.class, (MethodInterceptor) (p, method, args1, methodProxy) -> {
System.out.println("before...");
// Object result = method.invoke(target, args); //用方法反射调用目标
// methodProxy 它可以避免反射调用
// Object result = methodProxy.invoke(target,args); //内部没有用反射,需要目标(spring) 但是看到的效果是一样的,都是输出//
// before...
// target foo
// after... 但是内部确实没有用反射
Object result = methodProxy.invokeSuper(p,args); //内部没有用反射,需要代理 但是看到的效果是一样的,都是输出// before...
// target foo
// after...
System.out.println("after...");
return result;
});
//第一个参数:代理的父类是什么 第二个参数,决定将来代理类中方法执行的行为
//o指的是代理类自己,method指的是当前代理类中执行的方法,args指的是方法执行时的参数,methodProxy也可以看作是一个方法对象
//输出结果为
// before...
// target foo
// after...
proxy.foo();
}
}