15_Java反射机制——5.反射的应用:动态代理

问题一: 动态代理的概念

    动态代理是指客户通过代理类来调用其它对象的方法,并且是在程序运行时,
    根据实际需要,动态地创建目标类的代理对象。

问题二: 动态代理和静态代理相比,动态代理的优势

    抽象角色中(接口)声明的所有方法都被转移到调用处理器一个集中的方法中处理,
    这样,就可以更加灵活和统一的处理众多的方法。

问题三: 动态代理的使用场景

    调试和远程方法调用

1. Java 动态代理相关API

    1) Proxy : 专门完成代理的操作类,是所有动态代理类的父类。
                通过此类可以为一个或多个接口动态地生成实现类。
    2) Proxy : 提供了用于创建动态代理类和动态代理对象的静态方法

    // 创建一个动态代理类所对应的Class对象
    static Class<?> getProxyClass(ClassLoader loader, Class<?>... Interfaces)

    // 创建一个动态代理对象, loader: 类加载器;interfaces: 被代理类(原始类)实现的全部接口; h: 得到 InvocationHandler 接口的实现类实例。
    static Object newProxyInstance(ClassLoader loder, Class<?>[] interfaces, InvocationHandler h)    

2. 动态代理的实现

实现动态代理要解决的问题
    1) 问题:如何通过 加载到 内存中的类(被代理类 —— 原始类),动态创建代理类及其对象    
    
    // 创建一个动态代理类所对应的Class对象
    static Class<?> getProxyClass(ClassLoader loader, Class<?>... Interfaces)
    
    // 创建一个动态代理对象, loader: 类加载器;interfaces: 被代理类(原始类)实现的全部接口; h: 得到 InvocationHandler 接口的实现类实例。
    static Object newProxyInstance(ClassLoader loder, Class<?>[] interfaces, InvocationHandler h)   
    
    2) 问题:如何通过 代理类对象的同名方法的调用,去实现 被代理类(原始类)的同名方法的调用

    在 InvocationHandler 接口中,有 invoke 方法, 可以通过实现该接口,来重写 invoke 方法 从而实现 被代理类对象的同名方法的调用。
    public Object invoke(Object proxy, Method method, Object[] args)throws Throwable;
    
    @Override
          public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
          
                  // 调用 被代理类对象的同名方法,得到其方法调用的返回值
                  Object realReturnValue = method.invoke(target, args);
                  return realReturnValue;
           }
实现动态代理举例

【1. 创建一个 Plant 接口】

public interface Plant {

    public void photosynthesis();

    public void breath();
}

【2. 创建一个 被代理类(原始类) BigTree】

package com.atzwx.java;

// 被代理类 (原始类)
public class BigTree implements Plant {

    @Override
    public void photosynthesis() {
        System.out.println("被代理的类 —— BigTree.photosynthesis");
    }

    @Override
    public void breath() {
        System.out.println("被代理的类 —— BigTree.breath");
    }
}

【3. 创建一个 实现 InvocationHandler 接口的 MyInvocationHandler类,重写 invoke方法,实现动态代理的具体操作】

package com.atzwx.java;

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

public class MyInvocationHandler implements InvocationHandler {

    private Object target;

    // 设置 指定的 被代理类(原始类)
    public void setTarget(Object target) {
        this.target = target;
    }

    /**
     * 通过代理类对象 调用同名方法, 来实现 被代理类(原始类)对象 调用同名方法
     * @param proxy 调用方法的代理对象
     * @param method 代理类对象调用的同名方法
     * @param args 同名方法的形式参数
     * @return 被代理类对象的同名方法的真实返回值
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        PlantUtil plantUtil = new PlantUtil();

        // 调用 通用方法1
//        plantUtil.universalMethod1();

        // 调用 被代理类对象的同名方法,得到其方法调用的返回值
        Object realReturnValue = method.invoke(target, args);

        // 调用 通用方法2
//        plantUtil.universalMethod2();

        return realReturnValue;
    }
}

【4. 创建一个 代理类 ProxyObjectFactory】

package com.atzwx.java;

import java.lang.reflect.Proxy;

// 代理类
public class ProxyObjectFactory {

    /**
     * 创建一个动态代理类对象
     * @param target 为被代理类(原始类) 的 对象
     * @return
     */
    public static Object getProxyInstance(Object target) {

        ClassLoader classLoader = target.getClass().getClassLoader();
        Class<?>[] interfaces = target.getClass().getInterfaces();

        // 用于实现 处理代理类 与 被代理类 的同名方法调用
        MyInvocationHandler invocationHandler = new MyInvocationHandler();
        invocationHandler.setTarget(target);

        // 返回一个代理类对象
        return Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
    }
}

【5. 调用 代理类对象的同名方法】

package com.atzwx.test;

import com.atzwx.java.BigTree;
import com.atzwx.java.Employee;
import com.atzwx.java.Plant;
import com.atzwx.java.ProxyObjectFactory;
import org.junit.Test;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class ReflectTest {
    /**
     * 反射的应用:动态代理
     *
     */
    @Test
    public void dynamicProxy() {

        // 1. 创建一个 被代理类 对象
        BigTree bigTree = new BigTree();

        // 2. 创建一个 代理类对象
        Plant plant = (Plant) ProxyObjectFactory.getProxyInstance(bigTree);

        // 3. 代理类对象的同名方法的调用,去实现 被代理类对象的同名方法的调用
        plant.photosynthesis();

        System.out.println();

        plant.breath();
    }
}

【output】

被代理的类 —— BigTree.photosynthesis

被代理的类 —— BigTree.breath

3. 动态代理 与 AOP (Aspect Orient Programming) 简单举例

【新建一个 PlantUtil 类,在该类中编写通用方法】

package com.atzwx.java;

public class PlantUtil {

    public void universalMethod1() {
        System.out.println("==============PlantUtil.universalMethod1==============");
    }

    public void universalMethod2() {
        System.out.println("==============PlantUtil.universalMethod2==============");
    }

}

【在 MyInvocationHandler 类中的 invoke 方法里,添加通用方法】

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

        PlantUtil plantUtil = new PlantUtil();

        // 调用 通用方法1
        plantUtil.universalMethod1();

        // 调用 被代理类对象的同名方法,得到其方法调用的返回值
        Object realReturnValue = method.invoke(target, args);

        // 调用 通用方法2
        plantUtil.universalMethod2();

        return realReturnValue;
    }

【调用 动态代理类 Plant 对象的同名方法】

    plant.photosynthesis();
    
    System.out.println();
    
    plant.breath();

【output】

==============PlantUtil.universalMethod1==============
被代理的类 —— BigTree.photosynthesis
==============PlantUtil.universalMethod2==============

==============PlantUtil.universalMethod1==============
被代理的类 —— BigTree.breath
==============PlantUtil.universalMethod2==============
posted @ 2022-03-21 23:35  hellozwx  阅读(58)  评论(0编辑  收藏  举报