一、JDK动态代理
核心接口:InvocationHandler(调用处理器),它只有一个方法 invoke 。
无论何时调用代理对象的方法,调用处理器的 invoke 方法都会被调用,并向其传递 Method 对象和原始的调用参数。
定义:
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
核心类:Proxy(代理类)
创建一个代理对象,需要使用 Proxy 类的 newProxyInstance 方法。 该方法有三个参数:一个类加载器(class loader) ,使用 null 表示使用默认的类加载器;一个 Class 对象数组,每个元素都是需要实现的接口;一个调用处理器。
定义:
public class Proxy implements java.io.Serializable
API:
static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
返回指定接口的代理类的实例,该接口将方法调用分派到指定的调用处理器。
static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces)
返回给定类加载器和接口数组的代理类的 java.lang.Class 对象。
static boolean isProxyClass(Class<?> cl)
当且仅当使用 getProxyClass 方法或 newProxyInstance 方法将指定的类动态生成为代理类时,才返回 true。
static InvocationHandler getInvocationHandler(Object proxy)
返回指定代理实例的调用处理器。
二、JDK动态代理 与 CGLIB动态代理
1、区别
- JDK动态代理是Java标准库提供的一种代理实现方式,它主要利用Java反射机制实现。JDK动态代理要求被代理的类必须实现一个或多个接口,通过接口来定义代理对象的行为。在运行时,JDK动态代理会为被代理类生成一个实现了相同接口的代理类实例,并通过 InvocationHandler(调用处理器)来定义代理方法的具体实现。
- CGLIB是一个强大的高性能的代码生成库,它可以在运行时扩展Java类。CGLIB动态代理通过继承被代理类来创建代理对象,因此被代理类不需要实现任何接口。CGLIB利用ASM(开源的Java字节码编辑库)修改被代理类字节码生成子类,从而实现对被代理类方法的拦截和增强。
2、代码示例
UserService接口
package site.itool;
/**
* UserService接口
*/
public interface UserService {
// 通过用户id打印用户姓名
void printUserName(Long id);
}
UserService接口实现类
package site.itool;
/**
* UserService接口实现类
*/
public class UserServiceImpl implements UserService {
/**
* 实现接口方法
* @param id
*/
@Override
public void printUserName(Long id) {
System.out.println("(代理对象)姓名是" + id);
}
}
JDK动态代理
package site.itool;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* JDK代理类 调用处理器
*/
public class JdkProxy implements InvocationHandler {
private Object target ; // 需要代理的目标对象
public JdkProxy(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("JDK动态代理,开始!");
Object result = method.invoke(target, args);
System.out.println("JDK动态代理,结束!");
return result;
}
/**
* 获取代理对象方法
* @return
*/
private Object getJDKProxy(){
// JDK动态代理只能针对实现了接口的类进行代理,newProxyInstance 函数所需参数就可看出
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
public static void main(String[] args) {
JdkProxy jdkProxy = new JdkProxy(new UserServiceImpl());
// 获取代理对象
UserService user = (UserService)jdkProxy.getJDKProxy();
user.printUserName(1L); //执行方法
}
}
输出:
CGLIB动态代理
package site.itool;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* CGLIB代理类 调用处理器
*/
public class CglibProxy implements MethodInterceptor {
private Object target ; // 需要代理的目标对象
public CglibProxy(Object target) {
this.target = target;
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("CGLIB动态代理,开始!");
Object invoke = method.invoke(target, objects); // 方法执行,参数:target 目标对象 objects 参数数组
System.out.println("CGLIB动态代理,结束!");
return invoke;
}
/**
* 获取代理对象方法
* @return
*/
public Object getCglibProxy(){
Enhancer enhancer = new Enhancer();
// 设置父类,因为 CGLIB 是针对指定的类生成一个子类,所以需要指定父类
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(this); // 设置回调
Object result = enhancer.create(); // 创建并返回代理对象
return result;
}
public static void main(String[] args) {
CglibProxy cglib = new CglibProxy(new UserServiceImpl());
// 获取代理对象
UserService user = (UserService)cglib.getCglibProxy();
user.printUserName(1L); //执行方法
}
}
输出: