Java动态代理的理解

代理可分为两类: 静态代理和动态代理

1.静态代理:

/*定义一个业务接口*/
public interface Count {  
    // 查看账户方法  
    public void queryCount();  
    // 修改账户方法  
    public void updateCount();    
}

/*定义一个委托类,实现该业务接口*/
public class CountImpl implements Count {  
    @Override  
    public void queryCount() {  
        System.out.println("查看账户方法...");  
    }  
    @Override  
    public void updateCount() {  
        System.out.println("修改账户方法...");   
    }  
}  

首先定义一个业务接口,然后定义一个委托类,我们要做的就是静态代理委托类:

/*定义一个静态代理类,对委托类countIml进行代理*/
public class CountProxy implements Count {  
    private CountImpl countImpl;    
    /** 
     * 覆盖默认构造器 
     *  
     * @param countImpl 
     */  
    public CountProxy(CountImpl countImpl) {  
        this.countImpl = countImpl;  
    }   
    @Override  
    public void queryCount() {  
        System.out.println("事务处理之前");  
        // 调用委托类的方法;  
        countImpl.queryCount();  
        System.out.println("事务处理之后");  
    }  
    @Override  
    public void updateCount() {  
        System.out.println("事务处理之前");  
        // 调用委托类的方法;  
        countImpl.updateCount();  
        System.out.println("事务处理之后");  
    }  
}  

如上图代码所示:定义一个代理类,处理委托类的事务

public class TestCount {  
    public static void main(String[] args) {  
        CountImpl countImpl = new CountImpl();  
        CountProxy countProxy = new CountProxy(countImpl);  
        countProxy.updateCount();  
        countProxy.queryCount();  
  
    }  
} 

不过我们也发现,如果代理处理逻辑不同的话,又要重新定义一个代理类,这样是不合理的,所以动态代理应运而生

2.动态代理:

 动态代理与普通的代理相比较,最大的好处是接口中声明的所有方法都被转移到一个集中的方法中处理(invoke),这样,在接口方法数量比较多的时候,我们可以进行灵活处理,而不需要像静态代理那样每一个方法进行中转。
 动态代理类只能代理接口,代理类都需要实现InvocationHandler类,实现invoke方法。该invoke方法就是调用被代理接口的所有方法时需要调用的,该invoke方法返回的值是被代理接口的一个实现类

 动态代理类都会实现同一个接口InvocationHandler

public interface InvocationHandler { 
    public Object invoke(Object proxy,Method method,Object[] args) throws Throwable; 
} 

参数说明:Object proxy,是指被代理的对象;Method method是指被代理对象的方法;Object[] args是指方法参数

Proxy类:

专门完成代理的操作类,可以通过此类为一个或多个接口动态地生成实现类,此类提供了如下的操作方法:

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)throws IllegalArgumentException 
//参数说明: 
//ClassLoader loader:类加载器 
//Class<?>[] interfaces:得到全部的接口 
//InvocationHandler h:得到InvocationHandler接口的子类实例 

下面是动态代理非常经典实例:

第一步,定义一个业务接口:

    public interface TargetInterface {  
        public int targetMethodA(int number);  
        public int targetMethodB(int number);  
    }  

第二步,定义一个业务类,实现该业务接口--即对应的委托类:

    public class ConcreteClass implements TargetInterface{  
      
        public int targetMethodA(int number) {  
            System.out.println("开始调用目标类的方法targetMethodA...");  
            System.out.println("操作-打印数字:"+number);  
            System.out.println("结束调用目标类的方法targetMethodA...");  
            return number;  
        }  
          
        public int targetMethodB(int number){  
            System.out.println("开始调用目标类的方法targetMethodB...");  
            System.out.println("操作-打印数字:"+number);  
            System.out.println("结束调用目标类的方法targetMethodB...");  
            return number;  
        }  
      
    }  

第三步,定义代理类:

    public class ProxyHandler implements InvocationHandler{  
        private Object concreteClass;  
          
        public ProxyHandler(Object concreteClass){  
            this.concreteClass=concreteClass;  
        }  
      
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {  
            System.out.println("proxy:"+proxy.getClass().getName());  
            System.out.println("method:"+method.getName());  
            System.out.println("args:"+args[0].getClass().getName());  
              
            System.out.println("Before invoke method...");  
            Object object=method.invoke(concreteClass, args);//普通的Java反射代码,通过反射执行某个类的某方法  
            System.out.println("After invoke method...");  
            return object;  
        }  
      
    }  

该代理类实现了Java反射包中的InvocationHandler接口,代理实例调用方法时候,将对方法调用指派到它的代理处理器程序的invoke方法中。invoke方法内部实现预处理,对委托类方法调用,事后处理等逻辑。

第四步,测试程序

    public class DynamicProxyExample {  
        public static void main(String[] args){  
             ConcreteClass c=new ConcreteClass();//元对象(被代理对象)  
             InvocationHandler ih=new ProxyHandler(c);//代理实例的调用处理程序。  
             //创建一个实现业务接口的代理类,用于访问业务类(见代理模式)。  
             //返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序,如ProxyHandler。  
             TargetInterface targetInterface=(TargetInterface)Proxy.newProxyInstance(c.getClass().getClassLoader(),c.getClass().getInterfaces(),ih);  
             //调用代理类方法,Java执行InvocationHandler接口的方法.  
             int i=targetInterface.targetMethodA(5);  
             System.out.println(i);  
             System.out.println();  
             int j=targetInterface.targetMethodB(15);  
             System.out.println(j);  
        }  
    }  

用Java反射机制中的Proxy.newProxyInstance方式创建一个代理类实例,创建该实例需要指定该实例的类加载器,需要实现的接口(即目标接口),以及处理代理实例接口调用的处理器。

使用java动态代理的好处:

1、减少编程的工作量:假如需要实现多种代理处理逻辑,只要写多个代理处理器就可以了,无需每种方式都写一个代理类。

2、系统扩展性和维护性增强,程序修改起来也方便多了(一般只要改代理处理器类就行了)。

原文地址:https://www.cnblogs.com/shilin000/p/4789580.html