动态代理原理
- JDK动态代理:
- JDK动态代理是基于接口实现的。它利用了Java反射机制,在运行时动态生成代理类。通过Proxy类的静态方法
newProxyInstance
,传入类加载器、被代理类实现的接口数组以及实现了InvocationHandler接口的处理器对象。当代理对象的方法被调用时,实际上是由InvocationHandler的invoke
方法来处理,在invoke
方法中可以实现对目标方法的增强逻辑。
- CGLIB动态代理:
- CGLIB动态代理是基于继承实现的。它通过字节码生成技术,在运行时动态生成被代理类的子类作为代理类。CGLIB通过Enhancer类来创建代理对象,设置父类为被代理类,然后通过回调机制,当代理对象方法被调用时,会回调MethodInterceptor的
intercept
方法,在这个方法中实现对目标方法的增强。
应用场景
- 日志记录:在方法调用前后记录日志信息,如记录用户登录时间、操作等。
- 事务管理:在方法调用前后开启和提交事务,保证数据的一致性。
- 权限控制:在方法调用前检查用户权限,决定是否允许执行该方法。
区别
- 代理实现方式:
- JDK动态代理基于接口,被代理类必须实现至少一个接口。
- CGLIB动态代理基于继承,被代理类可以不实现接口,但不能是final类(因为无法继承)。
- 性能:
- JDK动态代理因为基于反射,在调用次数较少时性能较好。
- CGLIB动态代理生成字节码,在调用次数较多时性能更好,因为减少了反射带来的开销。
电商系统用户登录模块使用代理模式实现日志记录功能
- JDK动态代理实现:
public interface UserLoginService {
void login(String username, String password);
}
public class UserLoginServiceImpl implements UserLoginService {
@Override
public void login(String username, String password) {
System.out.println("用户 " + username + " 登录成功");
}
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class LoginInvocationHandler implements InvocationHandler {
private Object target;
public LoginInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("记录登录日志,开始时间:" + System.currentTimeMillis());
Object result = method.invoke(target, args);
System.out.println("记录登录日志,结束时间:" + System.currentTimeMillis());
return result;
}
}
import java.lang.reflect.Proxy;
public class JDKProxyFactory {
public static Object getProxy(Object target) {
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new LoginInvocationHandler(target));
}
}
public class Main {
public static void main(String[] args) {
UserLoginService target = new UserLoginServiceImpl();
UserLoginService proxy = (UserLoginService) JDKProxyFactory.getProxy(target);
proxy.login("testUser", "123456");
}
}
- CGLIB动态代理实现:
public class UserLoginService {
public void login(String username, String password) {
System.out.println("用户 " + username + " 登录成功");
}
}
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class LoginMethodInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("记录登录日志,开始时间:" + System.currentTimeMillis());
Object result = methodProxy.invokeSuper(o, objects);
System.out.println("记录登录日志,结束时间:" + System.currentTimeMillis());
return result;
}
}
import net.sf.cglib.proxy.Enhancer;
public class CGLIBProxyFactory {
public static Object getProxy(Class<?> clazz) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(clazz);
enhancer.setCallback(new LoginMethodInterceptor());
return enhancer.create();
}
}
public class Main {
public static void main(String[] args) {
UserLoginService proxy = (UserLoginService) CGLIBProxyFactory.getProxy(UserLoginService.class);
proxy.login("testUser", "123456");
}
}