返回首页 / 程序员知识/java动态代理三种方式是什么

java动态代理三种方式是什么

2023-12-04 收藏 92

  1、JDK 动态代理:底层采用的是Java反射技术,获取真正的代理类,代理对象会在jvm 中进行创建,通过指定接口的ClassLoader 来创建一个指定接口的代理对象,代理类会实现InvocationHandler接口,来拦截我们的接口请求,在invoke()中做增强与请求转发处理。

@SuppressWarnings("unchecked")
public  T getProxy(Class interfaces) {
	// 1. jvm 内存中生成一个class 类
	// 2. 根据该class 类反射一个代理对象 $Proxy@
	return (T) Proxy.newProxyInstance(interfaces.getClassLoader(), new Class[] {interfaces}, this);
}

/**
 * invoke() 是 InvocationHandler 接口中代理的拦截方法, 此处覆盖该方法, 让它对目标接口的方法进行拦截
 *
 * @param proxy 这个就是我们的代理类, 就是jdk 生成的那个以 $Proxy. 开头的代理类
 * @param method interface.method() 目标接口中的方法
 * @param args interface.method(args) 目标接口中的参数
 * @return
 * @throws Throwable
 */
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    System.out.println("TargetProxy 前置增强.....");

    // 调用目标接口中的方法
    Object result = method.invoke(target, args);

    System.out.println("TargetProxy 后置增强.....");
    return result;
}

  2、CGLIB 动态代理:使用CGLIB实现动态代理,完全不受代理类必须实现接口的限制,CGLIB底层采用ASM字节码生成框架,使用字节码技术生成代理类,在JDK8之前,CGLIB动态要比JDK的动态代理(JDK使用的是Java反射)效率要高。唯一需要注意的是,如果被代理的类被final修饰,那么它将不可被继承,即不可被代理,同样,如果被代理的类中存在final修饰的方法,那么该方法也不可被代理。因为CGLIB原理是动态生成被代理类的子类。

  3、javassist 动态代理:javassist与JDK代理类似,它是通过代理工厂来创建代理对象的,代理类实现MethodHandler接口,来拦截我们的接口请求,在invoke()中做增强与请求转发处理。

public Object getProxy(Class tClass) throws InstantiationException, IllegalAccessException {
    // 代理工厂
    ProxyFactory proxyFactory = new ProxyFactory();

    // 设置需要创建子类的父类
    proxyFactory.setSuperclass(tClass);

    // 通过字节码技术动态创建子类实例
    proxyFactory.writeDirectory = "D:\software\data\idea\mybatis-3-mybatis-3.5.4";
    Object proxy = proxyFactory.createClass().newInstance();

    // 在调用目标方法之前, Javassist会回调MethodHandler接口方法拦截, 在其中可以实现自己的代理增强方法, 类似JDK中的InvocationHandler
    ((ProxyObject) proxy).setHandler(this);

    // 返回代理对象
    return proxy;
}

@Override
public Object invoke(Object self, Method thisMethod, Method proceed, Object[] args) throws Throwable {
    System.out.println("Javassist 事务开始.....");

    // 调用目标类中的方法
    Object result = proceed.invoke(self, args);

    System.out.println("Javassist 事务结束.....");
    return result;
}

猜你喜欢