Java代理模式(2)一动态代理

目录

Java代理模式(1)一静态代理
Java代理模式(2)一动态代理
Java代理模式(3)一CGLib代理


前言

之前Java代理模式(1)已经介绍了Java的静态模式,其缺点也已经说明。为此引出了Java的动态代理。


一、Java动态代理与静态代理的对比

静态代理:

  • 是通过开发人员手动去实现接口并调用的;
  • 只能一个代理类实现一个接口,如果接口中的还有未实现的方法时,代理类也要必须实现。同时会产生大量重复的代码。

动态代理:

  • 通过反射机制实现动态代理(利用java.lang.reflect.InvocationHandlerjava.lang.reflect.Proxy
  • 可以实现多个代理对象,不再受限制与一个代理只能实现一个接口。

既然动态代理提到了反射,那么就不得不说与动态代理有关的这两个Java API

java.lang.reflect.InvocationHandler

  • 对委托实例进行调用代理时,将委托对象的方法指派到其代理对象实现的调用处理器InvocationHandlerinvoke方法中
  • 然后代理类就可以调用invoke方法完成代理,在代理过程中invoke会根据传入的代理对象、方法名称以及参数决定调用代理的哪个方法。

public interface InvocationHandler {
    //Object proxy:需要被代理的对象  
    //Method method:被代理对象委托的方法
    //Object[] args:方法调用时所需要参数  
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;

}

java.lang.reflect.Proxy

代理类是通过Proxy.newProxyInstance()来生成的,

  • ClassLoader loader: 定义代理类的类加载器
  • Class[] interfaces :代理类要实现的接口列表
  • InvocationHandler h : 指派方法调用的调用处理程序,即实现InvocationHandler接口的调用处理程序
public static Object newProxyInstance(ClassLoader loader, Class[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {

二、完整举例实现代码:

利用之前(1)中所举例的例子完成一个完成的动态代理例子:

(1)目标对象实现的接口:ProblemInterface:

public interface ProblemInterface {
    void resolve();//解决问题
}

(2)目标对象:RealSubject

public class RealSubject implements ProblemInterface{

    @Override
    public void resolve() {
        System.out.println("There is an fatal bug in xxx project, It mainly includes...");
    }
}

(3)DynamicProxyHandler:实现InvocationHandler接口的调用处理类,用来生成代理对象、

public class DynamicProxyHandler implements InvocationHandler{

    //1.目标委托类即RealSubject
    private Object targetObject;

     /**
      * 2.委托类与代理类绑定关系:根据传入的目标对象返回一个代理对象  
      * @param targetObject
      * @return proxyObject
      */
     public Object getProxyInstance(Object targetObject){  
            this.targetObject=targetObject;  
            //targetObject.getClass().getClassLoader():指定产生代理对象的类加载器(需要将其指定为和目标对象同一个类加载器 )
            //targetObject.getClass().getInterfaces():目标对象委托类的所有实现的接口(代理类要实现的接口序列是与目标对象是相同的)
            //this:指派方法调用的调用处理程序,即实现InvocationHandler接口的调用处理程序
            return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),  
                    targetObject.getClass().getInterfaces(),this);  
    }
     /**
      * 3.调用处理器根据这三个参数决定调用代理的哪个方法
      */
    //Object proxy:需要被代理的对象  
    //Method method:被代理对象委托的方法
    //Object[] args:方法调用时所需要参数  
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result=method.invoke(targetObject, args);//通过反射调用真实业务对象的业务方法,并且返回
        return result;
    }
}

(4)客户端测试类:DynamicClient

public class DynamicClient {

    public static void main(String[] args) {
        DynamicProxyHandler dynamicProxyHandler = new DynamicProxyHandler();
        //传入目标对象new RealSubject()之后获得动态代理对象
        ProblemInterface proxy = (ProblemInterface)dynamicProxyHandler.getProxyInstance(new RealSubject());
        //代理目标对象的业务
        proxy.resolve();
    }
}

输出结果为如下,RealSubject目标对象的resolve()方法得到了代理

There is an fatal bug in xxx project, It mainly includes…

之后我们在ProblemInterface中随便增加add()方法来更加深入理解静态代理与动态代理的的区别

public interface ProblemInterface {
    void resolve();//解决问题
    void add();
}

真实对象RealSubject必须实现add()方法:

public class RealSubject implements ProblemInterface{

    @Override
    public void resolve() {
        System.out.println("There is an fatal bug in xxx project, It mainly includes...");
    }
    public void add() {
        System.out.println("This is add() method");
    }
}

Java静态代理:Proxy必须还要实现add()方法,才能代理成功

public class Proxy implements ProblemInterface{
    private ProblemInterface problemInterface = new RealSubject();//小李的问题已经得到反映
    @Override
    public void resolve() {
        System.out.println("I'm preparing for it");//领导A先准备好材料
        problemInterface.resolve();//开始与经理B沟通反映
        System.out.println("In a word, I think the problem...");//结束后领导A做了总结
    }
    @Override
    public void add() {
        problemInterface.add();//增加的方法
    }

}

而在动态代理中,只需要需要委托的目标对象实现add()方法之后,再增加一个方法调用proxy.add()即可

public class DynamicClient {

    public static void main(String[] args) {
        DynamicProxyHandler dynamicProxyHandler = new DynamicProxyHandler();
        //传入目标对象new RealSubject()之后获得动态代理对象
        ProblemInterface proxy = (ProblemInterface)dynamicProxyHandler.getProxyInstance(new RealSubject());
        //代理目标对象的业务
        proxy.resolve();
        //增加方法
        proxy.add();
    }
}

再比如我们再需要代理另外一个目标对象RealSubject2的业务:

public class RealSubject2 implements ProblemInterface{

    @Override
    public void resolve() {
        System.out.println("I am RealSubject2");
    }
    public void add() {
        System.out.println("This is add() method");
    }
}

如果是静态代理还得像Java代理模式(1)一样再创建一个Poxy2代理类代理RealSubject2,这样会很麻烦,代码量自然会增加。而使用动态代理方式后,只需要再创建调用处理类然后再传入需要代理的RealSubject2目标对象即可。

public class DynamicClient {

    public static void main(String[] args) {
        DynamicProxyHandler dynamicProxyHandler = new DynamicProxyHandler();
        DynamicProxyHandler dynamicProxyHandler2 = new DynamicProxyHandler();
        //传入目标对象new RealSubject()之后获得动态代理对象
        ProblemInterface proxy = (ProblemInterface)dynamicProxyHandler.getProxyInstance(new RealSubject());
        //再代理new RealSubject2()
        ProblemInterface proxy2 = (ProblemInterface)dynamicProxyHandler2.getProxyInstance(new RealSubject2());
        //RealSubject的需要代理的业务
        proxy.resolve();
        proxy.add();
        //RealSubject2的需要代理的业务
        proxy2.resolve();
        proxy2.add();
    }
}

最后的代理结果:

There is an fatal bug in xxx project, It mainly includes...
This is add() method
I am RealSubject2
This is add() method

总结

虽然JDK的动态代理已经基本满足代理要求,但只是局限于实现接口的被代理类,而在大多数的业务情况下如果遇到需要代理并没有实现接口类的目标对象时,应该使用CGLib动态代理(Java代理模式(3)一CGLib代理)。典型框架Spring AOP就运用了JDK动态代理与CGLib动态代理两者的结合。

你可能感兴趣的:(设计模式,Java动态代理,静态代理,CGLib动态代理)