动态代理_JAVA_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > JAVA > 动态代理

动态代理

 2016/7/14 5:32:35  noble510520  程序员俱乐部  我要评论(0)
  • 摘要:代理就像个中介,最外层操作代理对象,代理对象再调用委托对象当需要在调用前后做一些处理,但是这些处理与业务逻辑无关的时候,如果把无关代码写在业务逻辑里面,代码就会变得很乱,这时候用代理就再好不过了。就像spring的aop编程,也是用了代理,在调用前后做一些校验、日志记录等无关业务流程的事因为要通过代理对象去调用委托对象,所以代理对象需要持有委托对象的引用,而且代理类中需要实现委托对象的各种方法代理有两种一种是静态代理、一种是动态代理静态代理是由自己编写代理类,但是代理类都相差无几
  • 标签:代理

代理就像个中介,最外层操作代理对象,代理对象再调用委托对象

当需要在调用前后做一些处理,但是这些处理与业务逻辑无关的时候,如果把无关代码写在业务逻辑里面,代码就会变得很乱,这时候用代理就再好不过了。

就像spring的aop编程,也是用了代理,在调用前后做一些校验、日志记录等无关业务流程的事

因为要通过代理对象去调用委托对象,所以代理对象需要持有委托对象的引用,而且代理类中需要实现委托对象的各种方法

代理有两种一种是静态代理、一种是动态代理

静态代理是由自己编写代理类,但是代理类都相差无几,而且要每一个类都编写一个代理类的话,就会有太多的类了

动态代理是由反射技术,自动生成代理类,运行期才生成class文件

动态代理有两种实现方法,一种是java.lang.reflect、一种是cglib

jdk自带的实现方法,委托类只能实现接口,不能继承类,所有具有一定的局限性

cglib,委托类既可以实现接口也可以继承类

下面通过一个例子来说明代码

代理 - 钟绍威 - 1

一个Book接口,接口有read方法,有一个EBook类实现Book接口

//Book接口
public interface Book {
 public void read();
}
?
//委托类
class EBook implements Book {
 @Override
 public void read() {
  System.out.println("读电子书");
 }
}

静态代理

代理 - 钟绍威 - 2

比原本的代码多了一个BookProxy

//代理类
public class BookProxy implements Book{
 //持有Book委托实例
 private Book book;
 //绑定Book委托实例并返回代理对象
 public Book bind(Book book){
 this.book=book;
 return this;
 }
 //委托book调用read
 public void read(){
 try{
 //前置代码
 book.read();
 //后置代码
 }catch(Exception e){
 //异常代码
 }finally{
 //finall代码
 }
 }
}

可以看到,代理的本质就是,代理类持有委托对象,通过代理对象去调用委托对象,在调用的时候就可以添加一些额外代码

jdk实现动态代理

代理 - 钟绍威 - 3

这里的BookProxy,是使用反射,在运行期自动生成的

重要的是InvocationHandler,调用反射对象的时候,实际上是调用了InvocationHandler.invoke()

所以需要实现InvocationHandler接口,让实现类持有委托类引用,并且重写invoke方法

//代理类
public class BookInvocationHandler implements InvocationHandler {
 //委托类
 private Object target;
?
 //绑定委托类 并 返回一个代理对象
 public Object bind(Object target){
 this.target=target;
 return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
 }
 //调用委托对象
 //proxy是代理对象,method是要调用的方法,arg是方法的参数
 @Override
 public Object invoke(Object proxy, Method method, Object[] arg) throws Throwable {
 Object result = null;
 try{
 //前置代码
 result=method.invoke(proxy,arg);
 //后置代码
 }catch(Exception e){
 //异常代码
 }finally{
 //finally代码
 }
 return result;
 }
}

这里需要注意两个地方

  • Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)通过newProxyInstance拿到代理对象,主要参数,loader:委托类的类加载器,interfaces实现的接口,h调用处理程序
  • InvocationHandler.invoke(Object proxy, Method method, Object[] arg)
    这里的参数proxy是代理对象!所以调用委托对象的时候不能是method.invoke(proxy,arg),不然会循环调用invoke的,要invoke绑定的委托类对象

jdk不能代理继承的类,要代理继承的类,要用cglib去实现

cglib实现动态代理

代理 - 钟绍威 - 4

这里和jdk实现方法差不多,就是InvocationHandler换成了MethodInterceptor

proxy还是用反射在运行期生成,只是他用Enhancer.create()

public class BookInterceptor implements MethodInterceptor {
?
 private Object target;
 public Object bind(Object target) { 
 this.target = target; 
 Enhancer enhancer = new Enhancer(); 
 //设置父类
 enhancer.setSuperclass(this.target.getClass()); 
 // 回调方法 
 enhancer.setCallback(this); 
 // 创建代理对象 
 return enhancer.create(); 
 } 
?
 //obj委托对象 mehtod要拦截的方法 args参数 proxy也是要拦截的方法(更快)
 @Override
 public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
 method.invoke(target, args);
 return null;
 }
?
}
发表评论
用户名: 匿名