代理
代理主要可以分为:
- 静态代理
- JDK自带的动态代理
- Cglib
静态代理
静态代理比较简单,简单来说就是不想直接调用被代理类,通过代理类来实现功能。如下就是使用了静态代理
定义接口
public interface BookFace {public void addBook();public void addapple();
}
public class BookFaceImp implements BookFace {@Overridepublic void addBook(){System.out.println("增加图书方法");}@Overridepublic void addapple(){System.out.println("增加苹果");}}
public class BookFaceStatic implements BookFace{private BookFace target;public BookFaceStatic(BookFace target){this.target=target;}@Overridepublic void addBook() {System.out.println("美术图书");target.addBook();}@Overridepublic void addapple() {System.out.println("红苹果");target.addapple();}
}
编写单测:
@Testpublic void test3(){BookFaceStatic faceStatic=new BookFaceStatic(new BookFaceImp());faceStatic.addBook();faceStatic.addapple();}
输出结果:
上述就是一个简单的静态代理,就是讲需要的被代理类作为参数传入待代理类中。
JDK自带的动态代理
java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。
JDK动态代理只能对实现了接口的类生成代理,而不能针对类。
延续使用上述的接口和接口实现类,核心代码如下:
public class BookFaceProcyJDK implements InvocationHandler {private Object target;public Object getProcy(Object target){//获取到是哪个类需要代理this.target=target;//getInterfaces()获取代理类的接口return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);}//重写invoke方法,InvocationHandler中自动会执行@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("批量执行1");Object result=method.invoke(target,args);System.out.println("批量执行2");return result;}
}
编写单测:
@Testpublic void test1(){BookFaceImp bookFaceImp=new BookFaceImp();BookFaceProcyJDK bookFaceProcy=new BookFaceProcyJDK();BookFace bookFace= (BookFace)bookFaceProcy.getProcy(bookFaceImp);bookFace.addBook();bookFace.addapple();}
输出结果:
采坑:
为什么BookFace bookFace= (BookFaceImp)bookFaceProcy.getProcy(bookFaceImp);
不能这样写???
解释:因为代理时相当于新建了一个BookFaceImp1,要么写成(BookFaceImp1)bookFaceProcy.bind(bookFaceImp)或者使用它的父类BookFace,因为不知道到底生成了一个什么名字的BookFaceImp,所以得使用它的父类BookFace。
(代理生成的BookFaceImp1和BookFaceImp是统一层级的)
Cglib
cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法。
延续使用上述的接口和接口实现类,核心代码如下:
public class BookFaceProcyCglib implements MethodInterceptor {private Object target;@Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {System.out.println("监听开始");Object result=method.invoke(target,args);System.out.println("监听结束");return result;}public Object getProcy(Object target){this.target=target;Enhancer enhancer=new Enhancer();//设置父类,因为cglib是设置子类enhancer.setSuperclass(target.getClass());//设置回调enhancer.setCallback(this);return enhancer.create();}
}
单测:
@Testpublic void test2(){BookFaceImp bookFaceImp=new BookFaceImp();BookFaceProcyCglib bookFaceProcy=new BookFaceProcyCglib();BookFace bookFace= (BookFace)bookFaceProcy.getProcy(bookFaceImp);bookFace.addBook();bookFace.addapple();}
运行结果:
Cglib与jdk自带的动态代理不同是生成的bookFaceImp1的父类是bookFaceImp
所以 BookFace bookFace= (BookFace)bookFaceProcy.getProcy(bookFaceImp)也可以改成 BookFace bookFace= (BookFaceImp)bookFaceProcy.getProcy(bookFaceImp),效果一致