java高级特性代理

引言:和反射一样,java中的代理也是困扰自己的一大问题之一;所以今天又 将java核心思想里面的反射再看了一遍:下面简单总结一下自己对代理用法的理解:
所谓的代理其实就是A可以做的事不想做,交给B去做;我们都知道代理呢其实是分动态代理和静态代理的;静态代理呢比较容易实现也比较好理解,难点就是在动态代理上:

一:静态代理:

  • 1:什么是静态代理?
    静态代理其实就是:代理类和委托类之前就已经准备好了;再java中就是程序运行前代理类和委托类的字节码就已经准备好了;
    如:小明在学校是一个学霸,它不喜欢做简单的题,一碰到简单的题呢就交给它的朋友小红去做;
//代理接口(即要做的事情)
interface Exercise{
    public void test();
}
public class Xiaoming implements Exercise{

    @Override
    public void test() {
        System.out.println("我是小明,不想做简单的题让小红帮我做吧");
    }

}
class ProxyXiaoHong implements Exercise{
    //小红拿着小明给它的题目(代理类持有一个委托类对象的引用)
    Exercise ming ;
    public ProxyXiaoHong(Exercise ming){
        this.ming = ming;
    }
    @Override
    public void test() {
        //将请求分派给委托类处理
        ming.test();
        System.out.println("我是小红,我帮小明做道题吧!");
    }
}

测试类

public class testProxy {
    public static void main(String[] args) {
        Exercise e = ProxyFactory.getInstance();
        e.test();
    }
}
//为了不让老师认出来是别人写的,他们两要将作业一起交到课代表那里(java称之为代理工厂:然客户不知道到底是代理做的还是委托类做的)
class ProxyFactory{
    public static Exercise getInstance(){
        return new ProxyXiaoHong(new Xiaoming());
    }
}
  • 静态代理的优缺点:
    优点:用户不需要知道具体的实现类是什么;只需要关注自己业务逻辑的本身;
    缺点:
    <1>:代理对象一个接口只服务于一种类型的对象,如果有很多种方法,我们就需要为每一种方法进行代理;所以当业务逻辑方法很多 静态代理变不再适用了;
    <2>:如果接口中增加了方法,除了实现类要增加方法之外,所有代理类也要增加相应的方法;增加了代码的维护量

二:动态代理:

JDK的动态代理

由于静态代理的一个接口只能为一个代理类服务;程序的开发过程中必然会产生大量的代理类,为此我们提出了动态代理的概念:还是使用前面的小明

动态代理就是在运行时生成一个类,这个类会实现你指定的一组接口,而这个类没有.java文件,是在运行时生成的,你也不用去关心它是什么类型的,你只需要知道它实现了哪些接口即可。
例子:

public class Xiaoming implements Exercise{

    @Override
    public void test() {
        // TODO Auto-generated method stub
        System.out.println("我是小明,不想做简单的题让其他人帮我做吧");
    }

}
interface Exercise{
    public void test();
}
/**
*调用处理器关键
*我们每一个调用委托类的方法都会经过这个调用处理器中的invoke方法;
*/
class DynamicProxyHandler implements InvocationHandler{
    //委托类  
    public Object target; 
    public DynamicProxyHandler(Object obj){
        this.target = obj;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // TODO Auto-generated method stub
        return method.invoke(target, args);
    }
} 

测试类:

public class testD {
    public static void main(String[] args) {
        Xiaoming ming = new Xiaoming();
        /**
         * 创建代理对象
         * Proxy是java中的代理类
         * newProxyInstance()方法是根据指定参数创建一个代理类;
         * 参数1:ClassLoader loader,是一个类加载器;作为java安全模型的一部分,
         * 对于系统类和从因特网上下载下来的类,我们可以使用不同的类加载器;使用null表示默认的类加载器
         * 参数2:Class<?>[] interfaces,一个Class数组,其中的每一个元素代表了委托类所实现的接口
         * 参数3: InvocationHandler h:一个调用处理器
         */
        Exercise pE = (Exercise) Proxy.newProxyInstance(Exercise.class.getClassLoader(), new Class[]{Exercise.class}, new DynamicProxyHandler(ming));
        pE.test();
    }
}

CJLIB的动态代理

CJLIB动态代理:使用CGLIb的动态代理可以实现对没有实现接口的类的代理,
关键类有:

  • MethodInterceptor ,代理需要实现该类,并重写里面的intercept方法.
  • Enhancer,加强,通过该类我们可以设置需要代理的目标类,并创建代理类。

原理:通过字节码技术为一个类创建子类并在子类中采用方法拦截技术拦截所有的父类方法的调用。顺势植入横切逻辑。

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class CJLBProxyTest implements MethodInterceptor{
    private Enhancer enhancer =  new Enhancer();
    @Override
    public Object intercept(Object o, Method method, Object[] params, MethodProxy methodProxy) throws Throwable {
        System.out.println("前置代理");
        Object res = methodProxy.invokeSuper(o, params);
        System.out.println("后置代理");
        return res;
    }

    public Object getPersonProxy(Class cla){
        enhancer.setSuperclass(cla);
        enhancer.setCallback(this);
        return enhancer.create();
    }

    public static void main(String[] args) {
        CJLBProxyTest cjlbp = new CJLBProxyTest();
        Coder cxy = (Coder)cjlbp.getPersonProxy(Coder.class);
        cxy.Coding("陈鹏");
    }
}
class Coder{
    public void Coding(String name){
        System.out.println(name+"正在写代码");
    }
}

动态代理优点:
动态代理与静态代理相比较,最大的好处是接口中声明的所有方法都被转移到调用处理器一个集中的方法中处理(InvocationHandler.invoke)。这样,在接口方法数量比较多的时候,我们可以进行灵活处理,而不需要像静态代理那样每一个方法进行中转。而且动态代理的应用使我们的类职责更加单一,复用性更强

三:动态代理的用途:

动态代理的用途与装饰模式很相似,就是为了对某个对象进行增强。所有使用装饰者模式的案例都可以使用动态代理来替换。
下面我们用一个例子来说明动态代理的用途!
我们来写一个Waiter接口,它只有一个serve()方法。MyWaiter是Waiter接口的实现类:

public interface Waiter {
  public  void  serve();
}
public class MyWaiter  implements Waiter {
     public void serve() {
       System.out.println("服务...");
    }
}

现在我们要对MyWaiter对象进行增强,要让它在服务之前以及服务之后添加礼貌用语,即在服务之前说“您好!”,在服务之后说:“很高兴为您服务!”。

public class  MainApp1 {
  public static void main(String[] args) {
      /**
        *1:获取类加载器
        */
       ClassLoader loader = MainApp1.class.getClassLoader();
       /**
        *2:获取该类实现想要实现的接口数组
        */
       Class[] cs = {Waiter.class};
      /**
        *3:创建别代理的对象
        */
       Waiter target = new MyWaiter();
       MyInvocationHandler h = new MyInvocationHandler(target);
      /**
        *4:获取代理对象
        */
      Waiter waiter = (Waiter)Proxy.*newProxyInstance*(loader,cs, h);
      /**
        *5:执行被代理类的相关方法
        */
       waiter.serve();
    }
}
/**
*自己定义的一个处理器:
/
class MyInvocationHandler  implements InvocationHandler {
    //被代理的目标对象
   public Waiter target;
   //
  public  MyInvocationHandler(Waiter target) {
    this.target = target;
  }
/**关键方法 
它是对代理对象所有方法的唯一实现。也就是说,无论你调用代理对象上的哪个方法,其实都是在调用InvocationHandler的invoke()方法。
这里注意:getClass()等一些Native方法除外
*/
 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
       System.*out*.println("您好!");
       Object result = method.invoke(target, args);
       System.*out*.println("很高兴为您服务!");
        return result;
    }
}

总结:
其实所谓代理,就是对象代表对象去做某些事情。在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之前起到中介的作用。

代理对象就是把被代理对象包装一层,在其内部做一些额外的工作,比如用户需要上facebook,而普通网络无法直接访问,网络代理帮助用户先FQ,然后再访问facebook。这就是代理的作用了。那小明举例吧,小红在替他写练习时要求得先听一首歌;我们就可以在invoke方法被调用之前顶一个其他的方法;

纵观静态代理与动态代理,它们都能实现相同的功能,而我们看从静态代理到动态代理的这个过程,我们会发现其实动态代理只是对类做了进一步抽象和封装,使其复用性和易用性得到进一步提升而这不仅仅符合了面向对象的设计理念,其中还有AOP的身影,这也提供给我们对类抽象的一种参考。关于动态代理与AOP的关系,个人觉得AOP是一种思想,而动态代理是一种AOP思想的实现!
参阅资料:http://blog.csdn.net/hejingyuan6/article/details/36203505



作者:cp_insist
链接:https://www.jianshu.com/p/ad21ff936e06
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。
posted @ 2018-07-17 18:58  天涯海角路  阅读(128)  评论(0)    收藏  举报