JDK动态代理是通过Java反射机制来实现的,它要求目标对象必须实现一个接口,然后通过Proxy类的newProxyInstance()方法来创建代理对象。生成的代理对象也会实现这个接口,并且将所有方法的调用都转发给InvocationHandler处理器去处理。因为JDK动态代理是基于接口的,所以它只能代理实现了接口的类,无法代理没有实现接口的类。
Cglib代理则是通过继承目标对象来实现的,它不要求目标对象必须实现接口,而是在运行时动态生成一个目标对象的子类,然后通过子类来实现对目标对象的代理访问。生成的代理对象是目标对象的子类,并且重写了目标对象的所有方法,在重写的方法中加入了增强代码。因为Cglib代理是基于继承的,所以它可以代理没有实现接口的类。
JDK动态代理是Java提供的一种基于接口的代理方式,它的原理可以简单概括为以下几个步骤:
-
定义接口:首先定义一个接口,该接口中包含了目标对象的所有方法。
-
创建InvocationHandler对象:创建一个实现了InvocationHandler接口的代理处理器对象,该对象用于处理代理对象的方法调用。
-
创建代理对象:通过Proxy类的newProxyInstance()方法创建代理对象。该方法需要传入三个参数:ClassLoader对象、Class[]对象和InvocationHandler对象。其中,ClassLoader对象用于指定代理对象的类加载器,Class[]对象用于指定代理对象需要实现的接口,InvocationHandler对象用于指定代理对象的方法调用处理器。
-
调用代理对象方法:通过代理对象调用目标对象的方法时,代理对象会将方法调用转发给InvocationHandler对象处理。在InvocationHandler对象的invoke()方法中,可以对方法调用进行增强处理,然后再将处理后的方法调用结果返回给代理对象。
当我们通过JDK动态代理调用目标对象的方法时,代理对象会首先检查目标对象是否实现了至少一个接口。如果目标对象没有实现接口,那么JDK动态代理就无法生成代理对象。否则,JDK动态代理会使用Java反射机制在运行时动态生成一个代理类,该代理类实现了目标对象实现的所有接口,并继承了Proxy类。然后,JDK动态代理会创建一个InvocationHandler对象,并将其与代理类关联起来。当我们调用代理对象的任意方法时,代理对象会将方法调用转发给InvocationHandler对象处理。在InvocationHandler对象的invoke()方法中,可以对方法调用进行增强处理,例如记录日志、事务管理等。最后,InvocationHandler对象将处理后的方法调用结果返回给代理对象。
Cglib代理是通过继承目标对象来实现代理的,它的原理可以简单概括为以下几个步骤:
-
创建Enhancer对象:首先创建一个Enhancer对象,它是Cglib的核心类,用于生成代理对象。
-
设置父类和回调函数:通过
setSuperclass()
方法设置目标对象的父类,然后通过setCallback()
方法设置回调函数,即MethodInterceptor对象。 -
创建代理对象:调用Enhancer对象的
create()
方法,生成代理对象。在生成代理对象的过程中,Cglib会动态创建目标对象的子类,并重写目标对象的所有非final方法,在重写的方法中加入了增强代码,以实现对目标对象的代理访问。 -
调用代理对象方法:通过代理对象来调用目标对象的方法时,Cglib会先判断是否是代理对象自己实现的方法,如果是,则直接调用代理对象自己的方法;如果不是,则调用父类(即目标对象)的方法。在调用父类方法之前和之后,Cglib会自动调用回调函数中的
intercept()
方法,以实现增强逻辑的执行。
Cglib代理只能代理非final类的非final方法,因为final方法不能被重写。此外,Cglib代理相对于JDK动态代理而言,由于采用继承的方式实现代理,会生成目标对象的子类,因此在性能上相对较低。
假设我们有一个接口 UserService
,它有一个方法 getUserById(int id)
用来根据用户ID获取用户信息。现在我们想要对这个方法进行代理,记录每次调用的时间。可以通过如下代码实现:
public interface UserService {
User getUserById(int id);
}
public class UserServiceImpl implements UserService {
public User getUserById(int id) {
// 根据id从数据库中获取用户信息
return user;
}
}
public class UserServiceProxy implements InvocationHandler {
private Object target;
public UserServiceProxy(Object target) {
this.target = target;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before method " + method.getName());
long startTime = System.currentTimeMillis();
Object result = method.invoke(target, args);
long endTime = System.currentTimeMillis();
System.out.println("after method " + method.getName() + ", elapsed time: " + (endTime - startTime) + "ms");
return result;
}
}
public class Main {
public static void main(String[] args) {
UserService userService = new UserServiceImpl();
UserService proxy = (UserService) Proxy.newProxyInstance(UserService.class.getClassLoader(),
new Class[] { UserService.class }, new UserServiceProxy(userService));
User user = proxy.getUserById(1);
}
}
在上面的代码中,我们创建了一个 UserServiceProxy
类,它实现了 InvocationHandler
接口,用来处理代理对象的方法调用。在 invoke()
方法中,我们先记录了方法调用前的时间,然后调用了目标对象的方法,最后记录了方法调用后的时间,并输出了方法调用的耗时。在 Main
类中,我们使用 Proxy.newProxyInstance()
方法来创建代理对象,然后通过代理对象来调用 getUserById()
方法。
假设我们有一个类 UserServiceImpl
,它有一个方法 getUserById(int id)
用来根据用户ID获取用户信息。现在我们想要对这个方法进行代理,记录每次调用的时间。可以通过如下代码实现:
public class UserServiceImpl {
public User getUserById(int id) {
// 根据id从数据库中获取用户信息
return user;
}
}
public class UserServiceInterceptor implements MethodInterceptor {
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("before method " + method.getName());
long startTime = System.currentTimeMillis();
Object result = proxy.invokeSuper(obj, args);
long endTime = System.currentTimeMillis();
System.out.println("after method " + method.getName() + ", elapsed time: " + (endTime - startTime) + "ms");
return result;
}
}
public class Main {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(UserServiceImpl.class);
enhancer.setCallback(new UserServiceInterceptor());
UserServiceImpl userService = (UserServiceImpl) enhancer.create();
User user = userService.getUserById(1);
}
}
在上面的代码中,我们创建了一个 UserServiceInterceptor
类,它实现了 MethodInterceptor
接口,用来处理代理对象的方法调用。在 intercept()
方法中,我们先记录了方法调用前的时间,然后调用了目标对象的方法,最后记录了方法调用后的时间,并输出了方法调用的耗时。在 Main
类中,我们使用 Enhancer
类来创建代理对象,然后通过代理对象来调用 getUserById()
方法。需要注意的是,Cglib代理要求目标类不能是final类,否则会抛出异常。