使用JAVA proxy实现动态代理

动态代理与静态代理不同,动态代理的代理类是在运行时动态生成的。在Java中,通过实现java.lang.reflect.Proxy和java.lang.reflect.InvocationHandler接口,可以创建动态代理对象。

Proxy核心方法

public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)

loader:一个classloader对象,定义了由哪个实例、类、接口的classloader对象对生成的代理类进行加载。一般是被代理对象(类\接口)的classloader
interfaces:一个interface对象数组,表示我们将要给我们的代理对象提供一组什么样的接口,如果我们提供了这样一个接口对象数组,那么也就是声明了代理类实现了这些接口,代理类就可以调用接口中声明的所有方法。如果为代理类提供的接口是真实对象实现的接口数组,这样代理对象就能像真实对象一样调用接口中的所有方法。
h:一个InvocationHandler对象,表示的是当动态代理对象调用方法的时候会关联到哪一个InvocationHandler(调用处理程序)对象上,并最终由其调用。
即当我通过代理对象来调用方法的时候,实际就是委托由其关联到的h对象的invoke方法中来调用,并不是自己来真实调用,而是通过代理的方式来调用的。
通过 Proxy.newProxyInstance 创建的代理对象是在jvm运行时动态生成的一个对象,它并不是我们的InvocationHandler类型,也不是我们定义的那组接口的类型,而是在运行是动态生成的一个对象,并且命名方式都是这样的形式,以$开头,proxy为中,最后一个数字表示对象的标号。

InvocationHandler核心方法

每一个动态代理类的调用处理程序都必须实现InvocationHandler接口,并且每个代理类的实例都关联到了实现该接口的动态代理类调用处理程序中,当我们通过动态代理对象调用一个方法时候,这个方法的调用就会被转发到实现InvocationHandler接口类的invoke方法来调用,看如下invoke方法:

Object    invoke(Object proxy, Method method, Object[] args) 
// 在代理实例上处理方法调用并返回结果。

proxy:代理对象实例,其所属的类为com.sun.proxy.$Proxy0,它的类加载器与被代理类的加载器一致,这也应证了newProxyInstance第一个参数loader的作用,即代理类是由传入的类加载器加载的!
method:要调用某个被代理对象真实的方法的Method对象,当时要使用真实对象方法的时,一般调用Object o=method.invoke(真实对象实例,args);
args:代理对象调用某个方法时所传递的实际参数数组!
返回:从代理实例的方法调用返回的值。即代理对象调用方法时的返回值,对某方法没有进行代理一般返回method.invoke的返回值!

实现步骤

  1. 定义一个接口,该接口存在可以调用的方法。
  2. 创建一个被代理类,实现上面定义的接口。
  3. 创建一个InvocationHandler实现类,该类实现了InvocationHandler接口。
  4. 在InvocationHandler实现类中重写invoke方法,并在方法中调用被代理类的方法。
  5. 使用Proxy类创建被代理类的动态代理对象,将InvocationHandler实现类作为参数传递给Proxy类的静态方法newProxyInstance()。
  6. 使用动态代理对象代替被代理类的实例。

代码实例

接口

public interface IUserDao {  
public void save();  
}

被代理类

public class UserDao implements IUserDao{  
@Override  
public void save() {  
System.out.println("保存数据");  
}  
}

代理实例和测试

public class ProxyFactory {
    private Object target;// 维护一个目标对象
    public ProxyFactory(Object target) {
        this.target = target;
    }
    // 为目标对象生成代理对象
    public Object getProxyInstance() {
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("开启事务");
                        // 执行目标对象方法
                        Object returnValue = method.invoke(target, args);
                        System.out.println("提交事务");
                        return null;
                    }
                });
    }
    public static void main(String[] args) {
        IUserDao target = new UserDao();
        System.out.println(target.getClass());  //输出目标对象信息
        IUserDao proxy = (IUserDao) new ProxyFactory(target).getProxyInstance();
        System.out.println(proxy.getClass());  //输出代理对象信息
        proxy.save();  //执行代理方法
    }
}

执行结果

class DynamicProxy.UserDao
class com.sun.proxy.$Proxy0
开启事务
保存数据
提交事务