JAVA学习之动态代理

JDK1.6中的动态代理

在Java中Java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,通过使用这个类和接口可以生成一个动态代理对象。JDK提供的代理只能针对接口做代理

java.lang.reflect.Proxy 提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类。

// 方法 1: 该方法用于获取指定代理对象所关联的调用处理器
public static InvocationHandler getInvocationHandler(Object proxy) 

// 方法 2:该方法用于获取关联于指定类装载器和一组接口的动态代理类的类对象
public static Class<?> getProxyClass(ClassLoader loader, 
Class<?>... interfaces)

// 方法 3:该方法用于判断指定类对象是否是一个动态代理类
public static boolean isProxyClass(Class<?> cl) 

// 方法 4:该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例
public static Object newProxyInstance(ClassLoader loader,
 Class<?>[] interfaces,InvocationHandler h)

java.lang.reflect.InvocationHandler:调用处理器接口,自定义invokle方法,用于实现对于真正委托类的代理访问。

/**
 该方法负责集中处理动态代理类上的所有方法调用。
 第一个参数既是代理类实例,
 第二个参数是被调用的方法对象(反射中Method对象)
 第三个参数是调用方法的参数列表。
 调用处理器根据这三个参数进行预处理或分派到委托类实例上发射执行
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;

 使用Proxy类中的newProxyInstance方法创建代理对象

参数:
        loader - 定义代理类的类加载器
        interfaces - 代理类要实现的接口列表
        h - 指派方法调用的调用处理程序 
        返回: 一个带有代理类的指定调用处理程序的代理实例,它由指定的类加载器定义,并实现指定的接口 
        public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)throws IllegalArgumentException

实例

接口:

package com.jalja.org.base.poxy;
public interface ArithmeticCalculator {
    int add(int i, int j);
    int sub(int i, int j);
    int mul(int i, int j);
    int div(int i, int j);
}

实现类:

package com.jalja.org.base.poxy;
public class ArithmeticCalculatorImpl implements ArithmeticCalculator {
    @Override
    public int add(int i, int j) {
        int result = i + j;
        System.out.println("add:"+result);
        return result;
    }
    @Override
    public int sub(int i, int j) {
        int result = i - j;
        System.out.println("sub:"+result);
        return result;
    }
    @Override
    public int mul(int i, int j) {
        int result = i * j;
        System.out.println("mul:"+result);
        return result;
    }
    @Override
    public int div(int i, int j) {
        int result = i / j;
        System.out.println("div:"+result);
        return result;
    }
}

代理类及使用:

package com.jalja.org.base.poxy.test;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import com.jalja.org.base.poxy.ArithmeticCalculator;
import com.jalja.org.base.poxy.ArithmeticCalculatorImpl;
public class MyInvocationHandler implements InvocationHandler{
    private Object target;//目标对象(对哪个对象做动态代理)
    public MyInvocationHandler(Object target) {
        this.target=target;
    }
    @Override
    /**
     * proxy - 在其上调用方法的代理实例
     * method - 对应于在代理实例上调用的接口方法的 Method 实例。Method 对象的声明类将是在其中声明方法的接口,该接口可以是代理类赖以继承方法的代理接口的超接口。
     * args - 包含传入代理实例上方法调用的参数值的对象数组,如果接口方法不使用参数,则为 null。基本类型的参数被包装在适当基本包装器类(如 java.lang.Integer 或 java.lang.Boolean)的实例中。 
     * return - 返回代理对象
     */
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //obj - 从中调用底层方法的对象
        //args - 用于方法调用的参数 
        //public Object invoke(Object obj, Object... args)throws IllegalAccessException, IllegalArgumentException,InvocationTargetException
        System.out.println(method.getName()+"方法前置。。。。。。。。。。。。。。。。");
        Object result=method.invoke(target, args);
        System.out.println("method:"+method);
        System.out.println(method.getName()+"方法后置。。。。。。。。。。。。。。。。");
        return result;
    }
    public static void main(String[] args) {
        /*参数:
        loader - 定义代理类的类加载器
        interfaces - 代理类要实现的接口列表
        h - 指派方法调用的调用处理程序 
        返回: 一个带有代理类的指定调用处理程序的代理实例,它由指定的类加载器定义,并实现指定的接口 
        public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)throws IllegalArgumentException*/
        ArithmeticCalculator ac=new ArithmeticCalculatorImpl();
        //Object proxy=Proxy.newProxyInstance(ac.getClass().getClassLoader(), ac.getClass().getInterfaces(), new MyInvocationHandler(ac));
        ArithmeticCalculator proxy=(ArithmeticCalculator)Proxy.newProxyInstance(
                ac.getClass().getClassLoader(), ac.getClass().getInterfaces(), new MyInvocationHandler(ac));
        proxy.add(10, 100);
        proxy.sub(20, 10);
    }

}

Cglib动态代理 
JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。

 Demo:

package com.jalja.org.base.poxy.Cglib;

import java.lang.reflect.Method;

import com.jalja.org.base.poxy.ArithmeticCalculatorImpl;

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

public class CglibProxy implements MethodInterceptor{
    private Object target;  
    /** 
     * 创建代理对象 
     * @param target 
     * @return 
     */  
    public Object getInstance(Object target) {  
        this.target = target;  
        Enhancer enhancer = new Enhancer();  
        enhancer.setSuperclass(this.target.getClass());  
        // 回调方法  
        enhancer.setCallback(this);  
        // 创建代理对象  
        return enhancer.create();  
    }  
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("前置代理");  
        //通过代理类调用父类中的方法  
        Object result = proxy.invokeSuper(obj, args);  
        System.out.println("后置代理");  
        return result;  
    }
    public static void main(String[] args) {
       CglibProxy cglib=new CglibProxy();  
       ArithmeticCalculatorImpl bookCglib=(ArithmeticCalculatorImpl)cglib.getInstance(new ArithmeticCalculatorImpl());  
       bookCglib.add(10, 30);
    }
}

CGLib创建的动态代理对象性能比JDK创建的动态代理对象的性能高不少,但是CGLib在创建代理对象时所花费的时间却比JDK多得多,所以对于单例的对象,因为无需频繁创建对象,用CGLib合适,反之,使用JDK方式要更为合适一些。