动态代理

即,动态代理是利用java反射技术,在运行时创建一个实现某些给定接口的新类。

栗子

先定义接口

public interface people {
    public String work();
}

实现该接口

public class Teacher implements people{

    @Override
    public String work() {
        System.out.println("教书育人");
        return "教书";
    }
}

编写代理类

import com.sun.xml.internal.ws.api.pipe.FiberContextSwitchInterceptor;

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

public class WorkHandler implements InvocationHandler {
    // 代理类的对象
    private Object obj;

    public WorkHandler(){

    }

    // 在调用这个方法的时候,会被调度到invoke方法,并将参数传入
    public WorkHandler(Object obj){
        this.obj = obj;
    }
    // 在调用给类的方法的时候,会被调度到invoke方法
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 真实对象执行之前添加操作
        // 调用obj类的method方法,并且参数为args
        Object invoke = method.invoke(obj, args);
        // 真实对象执行后添加操作
        return invoke;// 返回执行的结果
    }
}

最后运行

import java.io.FileInputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class Main {
    public static void main(String[] args){
        // 要代理的对象
        people people = new Teacher();  // 创建要代理的真实对象
        // 进行注册
        InvocationHandler handler = new WorkHandler(people);
        // 进行创建代理对象
        // 定义一个代理对象
        people proxy;
        // 调用Proxy.newProxyInstance方法
        // 需要传入真实对象实现的接口,为下一步调用该方法做准备
        // 将handler关联到invocationHandler对象,用于调度到invoke方法
        // 由于返回的对象为object类型,需要进行强制类型转换,保留people接口定义的方法
        // 最后一个参数要对对象进行关联,最后批量生产出对象
        proxy = (people) Proxy.newProxyInstance(handler.getClass().getClassLoader(), people.getClass().getInterfaces(), handler);
        System.out.println(proxy.work());
    }
}

第一个参数

第一个参数是运行时,创建的代理对象。

反射+IO操作读取class文件

import java.io.FileInputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Main {
    // 需要使用static让其加载进入内存
    static class myClassLoader extends ClassLoader{
        private String classPath;  // 获取当前类的在磁盘中保存的地址
        // 通过构造函数将地址注入
        public myClassLoader(String classPath){
            this.classPath = classPath;
        }
        // 将文件内容加载进入内存
        private byte[] loadByte(String name) throws Exception{
            // 获取一个输入流,
            FileInputStream fis = new FileInputStream(classPath + "/" + name + ".class");
            // 获取长度
            int len = fis.available();
            // 定义byte数组
            byte[] data = new byte[len];
            // 加载进入内存
            fis.read(data);
            // 关闭流
            fis.close();
            return data;
        }
        // 重写findClass方法,让加载的时候调用findClass方法
        protected Class<?> findClass(String name) throws ClassNotFoundException{
            try{
                // 读取文件到数组中
                byte[] data = loadByte(name);
                // 将字节码加载进入内存当中
                return defineClass(name, data, 0, data.length);
            }catch(Exception e){
                e.printStackTrace();
            }
            return null;
        }
    }
    public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, ClassNotFoundException {
        // 先初始化该类
        myClassLoader classLoader = new myClassLoader("/home/ming");
        // 此时会调用findClass加载Test.class加载进入内存当中
        Class clazz = classLoader.loadClass("com.ming.Test");
        // 实例化该类对象
        Object obj = clazz.newInstance();
        // 获取clazz该类方法中名称为hello,参数为空的方法。
        Method helloMethod = clazz.getDeclaredMethod("helloWorld", null);
       // 调用该方法
        // 调用obj类中的helloMethod,参数为空的方法。
       helloMethod.invoke(obj, null);
    }
}