JDK动态代理简解

例子

  • IBusiness.java
public interface IBusiness {  
    public void processBusiness();
}
  • UserBusiness.java
public class UserBusiness implements IBusiness {  
    public void processBusiness() {
        System.out.println("User processBusiness...");
    }   
}
  • DynamicInvocationHandler.java
import java.lang.reflect.InvocationHandler;  
import java.lang.reflect.Method;

public class DynamicInvocationHandler implements InvocationHandler {  
    private Object target;

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


    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("before: " + method.getName());

        /*  
         * 1,关于Class类: 
         * + Java类运行时在JVM中都表现为一个Class对象,因此一个Class对象表示一个运行时的类或接口
         * + 可以通过 类型.class 或 对象.getClass() 或者 Class.forName() 来获取类所对应的Class对象
         *
         * 2,关于类型转换:
         * + 向上类型转换:将子类对象转换成父类对象,向上类型转换是自动的
         * + 向下类型转换:将父类对象转换成子类对象,需要进行强制转换
         *
         * 3,关于反射:
         * + 可以通过java.lang.reflect.Method对象的getDeclaringClass方法,
         * + + 获取声明该方法的类。
         *
         * + <Method对象>.invoke方法的第一个参数必须是 
         * + + 声明了该方法的类或子类的对象
         *
         * 在这里(method.invoke(target, args);):
         * + 因为声明method方法的类是传递给Proxy类的接口,
         * + + 而target是实现了该接口(IBusiness)的类(UserBusiness)的对象,
         * + + 所以可以直接使用target来调用method.invoke,因为向上类型转换是自动的。
         * + + method.getDeclaringClass().isInstance(target)会返回true
         */
        Object result = method.invoke(target, args);
        System.out.println(method.getDeclaringClass().isInstance(target)); //true
        System.out.println("after: " + method.getName());
        return result;
    }
}
  • Main.java
import java.lang.reflect.Proxy;

public class Main {  
    public static void main(String[] args) {
        UserBusiness userBusiness = new UserBusiness();
        DynamicInvocationHandler handler = new DynamicInvocationHandler(userBusiness);

        /*  
         * Proxy类的静态方法newProxyInstance,主要做以下几件事情
         * + 1,根据传递给它的接口数组(第二个参数),生成一个类的字节码,
         * + + 新生成的类继承自Proxy,并实现了所有的接口
         *
         * + 2,根据传递给它的类加载器(第一个参数),把该类加载进JVM
         *
         * + 3,使用传递给它的InvocationHandler对象(第三个参数),调用该类的构造器,
         * + + 创建该类的对象;并且遍历所有的接口中的所有的方法,生成Method对象,
         * + + 最后用这些Method对象初始化该对象的几个Method成员
         *
         * + 4,返回对象给调用方
         */
        // Proxy新创建的类实现了所有传递它的接口,
        // + 所以可以转换成IBusiness
        IBusiness business = (IBusiness)Proxy.newProxyInstance(
            userBusiness.getClass().getClassLoader(), //类加载器
            userBusiness.getClass().getInterfaces(), //接口数组
            handler //InvocationHandler对象
        );

        //实际上调用的是Proxy创建的类的对象的processBusiness方法,
        // + 而该对象的processBusiness方法的实现就是去调用 InvocationHandler
        // + + 的invoke方法
        business.processBusiness();
    }
}

编译、运行:

javac IBusiness.java UserBusiness.java DynamicInvocationHandler.java Main.java  
java Main  


输出:

before: processBusiness  
User processBusiness...  
true  
after: processBusiness  

查看Proxy类创建的类

  • 修改Main.java
import java.lang.reflect.Proxy;  
import java.lang.reflect.Method;  
import java.lang.reflect.Field;

public class Main {  
    public static void printClassDefination(Class<?> cls) {
        System.out.print(cls.getName() + " implements ");
        for (Class<?> _interface : cls.getInterfaces())
            System.out.print(_interface.getName() + " ");
        System.out.println(" {\nDeclared Methods:");
        for (Method method : cls.getDeclaredMethods())
            System.out.println("\t" + method.getName());
        System.out.println("\nDeclared Fields:");
        for (Field field : cls.getDeclaredFields())
            System.out.println("\t" + field.getType().getName() + " - " + field.getName());
        System.out.println("}");
    } 
    public static void main(String[] args) {
        UserBusiness userBusiness = new UserBusiness();
        DynamicInvocationHandler handler = new DynamicInvocationHandler(userBusiness);

        IBusiness business = (IBusiness)Proxy.newProxyInstance(
            userBusiness.getClass().getClassLoader(), //类加载器
            userBusiness.getClass().getInterfaces(), //接口数组
            handler //InvocationHandler对象
        );
        printClassDefination(business.getClass());
    }
}

编译、运行:

javac IBusiness.java UserBusiness.java DynamicInvocationHandler.java Main.java  
java Main  


输出:

com.sun.proxy.$Proxy0 implements IBusiness  {  
Declared Methods:  
    processBusiness
    equals
    toString
    hashCode

Declared Fields:  
    java.lang.reflect.Method - m1
    java.lang.reflect.Method - m3
    java.lang.reflect.Method - m0
    java.lang.reflect.Method - m2
}

可以看到:新创建的类的名称是$Proxy0,它实现了IBusiness接口,并且里面有4个Method类型的成员变量。

感谢浏览tim chow的作品!

如果您喜欢,可以分享到: 更多

如果您有任何疑问或想要与tim chow进行交流

可点此给tim chow发信

如有问题,也可在下面留言: