java动态代理

关键接口描述

Proxy 提供了用于创建动态代理类代理对象静态方法,它也是所有动态代理类的父类

接口描述
static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces)返回代理类的 java.lang.Class 对象,并向其提供类加载器,该代理类将实现interface所指定的接口
static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)返回一个指定接口的代理类实例(即直接创建一个动态代理对象),该代理对象的实现类实现了interfaces中接口,执行代理对象的每个方法都会被换执行InvocationHandler对象的invoke方法

注意:第一种生成了动态代理类之后,如果需要通过该代理类来创建对象,依然需要传入一个InvocationHandler对象。 系统生成的每个代理对象都有一个与之关联的InvocationHandler对象


动态代理类实现都必须要先提供InvocationHandler这个接口的实现类,并且每个代理类的实例都关联到了一个handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的invoke 方法来进行调用。


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

  • loader:一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
  • interfaces:一个Interface对象的数组,表示的是要给需要代理的对象提供一组什么接口,如果提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样就能调用这组接口中的方法了
  • h:一个InvocationHandler对象,表示的是当这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象

案例分析

案例一
package myDynamicProxy;
/**
 * 动态代理通过动态代理直接创建一个代理对象实例
 */

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * 第一步: 被代理的接口
 */
interface Person {

    void walk();
    void speak();
}

/**
 *
 * 第二步:创建一个具体的实现类(真正的被代理的角色--真实对象/角色)
 */

 class  Man  implements Person {

    @Override
    public void walk() {
        System.out.println("a man is  walking!");
    }

    @Override
    public void speak() {
        System.out.println("a man is speaking!");
    }
}


/**
 * 创建Handler,需要重写invoke()方法; 通过代理对象调用一个方法的时候,
 * 这个方法的调用就会被转发为由InvocationHandler这个接口的invoke方法来进行调用
 */

class PersonInvocationHandler implements InvocationHandler {

    //这个就是我们要代理的真实对象
    private Object target;

    public PersonInvocationHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        System.out.println(method.getName() + "执行前");
        //具体的代理对象
        //当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用
        method.invoke(target, args);
        System.out.println(method.getName() + "执行后");
        return null;
    }
}


public class MyDyNamicProxy {

    public static void main(String[] args) {

        // 我们要代理的真实对象
        Person person = new Man();

        //代理哪个真实对象,就将该对象传进去
        InvocationHandler handler = new PersonInvocationHandler(person);

        //使用指定的InvocationHandler来生成一个动态代理对象
        //生成代理对象的API,Proxy.newProxyInstance(...);
        Person p = (Person) Proxy.newProxyInstance(
                Person.class.getClassLoader(),
                new Class[]{Person.class}, handler);

        //推荐使用上面一种,因为Person的字节码在JVM只存在一份。
    /*    Person p = (Person) Proxy.newProxyInstance(
                person.getClass().getClassLoader(),
                new Class[]{person.getClass()}, handler);*/

        p.walk();
       System.out.println(p.getClass().getName());//myDynamicProxy.$Proxy0  (在运行是动态生成的一个对象)
    }

}

可以将 PersonInvocationHandler 看做代理类,通过Proxy.newProxyInstance(...)生成代理对象。


案例二

继续使用上面的真实对象;简化实现过程。

package myDynamicProxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 *  动态代理工厂
 */
public class ProxyFactory {
    //真实对象;需要被代理的对象
    public Object target;
    public ProxyFactory(Object target) {
        this.target = target;
    }
    //获取代理对象
    public Object getInstanceProxy() {

        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(method.getName() + "执行前");
                        Object returnValue =  method.invoke(target,args);
                        System.out.print(method.getName() + "执行后");
                        return returnValue;
                    }
                });

    }
}

class Client {
    public static void main(String[] args) {
        Person person = new Man();
        Person p = (Person)new ProxyFactory(person).getInstanceProxy();
        p.walk();
    }
}

其他案例(测试类,可略过)
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Collection;

public class ProxyTest {

    /**
     * @param args
     */
    public static void main(String[] args) throws Exception{


        Class clazzProxy1 = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);
        System.out.println(clazzProxy1.getName());//com.sun.proxy.$Proxy0

        System.out.println("----------begin constructors list----------");

        Constructor[] constructors = clazzProxy1.getConstructors();
        for(Constructor constructor : constructors){
            String name = constructor.getName();
            StringBuilder sBuilder = new StringBuilder(name);
            sBuilder.append('(');
            Class[] clazzParams = constructor.getParameterTypes();
            for(Class clazzParam : clazzParams){
                sBuilder.append(clazzParam.getName()).append(',');
            }
            if(clazzParams!=null && clazzParams.length != 0)
                sBuilder.deleteCharAt(sBuilder.length()-1);
            sBuilder.append(')');
            System.out.println(sBuilder.toString());            
        }

        System.out.println("----------begin methods list----------");

        Method[] methods = clazzProxy1.getMethods();
        for(Method method : methods){
            String name = method.getName();
            StringBuilder sBuilder = new StringBuilder(name);
            sBuilder.append('(');
            Class[] clazzParams = method.getParameterTypes();
            for(Class clazzParam : clazzParams){
                sBuilder.append(clazzParam.getName()).append(',');
            }
            if(clazzParams!=null && clazzParams.length != 0)
                sBuilder.deleteCharAt(sBuilder.length()-1);
            sBuilder.append(')');
            System.out.println(sBuilder.toString());            
        }

        System.out.println("----------begin create instance object----------");
        Constructor constructor = clazzProxy1.getConstructor(InvocationHandler.class);
        class MyInvocationHander1 implements InvocationHandler{

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

        }
        Collection proxy1 = (Collection)constructor.newInstance(new MyInvocationHander1());

        System.out.println(proxy1);
        proxy1.clear();
        //是因为size()要返回一个整数,而在invoke中返回了一个null,null无法转换成整数。其中clear本身就返回void
        //proxy1.size();

        Collection proxy2 = (Collection)constructor.newInstance(new InvocationHandler(){

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

        });


        final ArrayList target = new ArrayList();           
        Collection proxy3 = (Collection)getProxy(target,new MyAdvice());
        proxy3.add("zxx");
        proxy3.add("lhm");
        proxy3.add("bxd");
        System.out.println(proxy3.size());
        System.out.println(proxy3.getClass().getName());
    }

    private static Object getProxy(final Object target,final Advice advice) {
        Object proxy3 = Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new InvocationHandler(){

                    public Object invoke(Object proxy, Method method, Object[] args)
                            throws Throwable {
                        advice.beforeMethod(method);//切面应用
                        Object retVal = method.invoke(target, args);
                        advice.afterMethod(method);//切面应用
                        return retVal;                      

                    }
                }
                );
        return proxy3;
    }

}

参看

  1. java的动态代理机制详解
  2. JDK动态代理源码解析
  3. 动态代理Proxy源码分析
  4. 高新技术视频—张孝祥
  5. 彻底理解JAVA动态代理
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值