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();}
}