首页 > 图灵资讯 > java面试题>正文
金三银四精选java面试题-怎么实现动态代理?
2023-11-28 10:28:40
怎么实现动态代理?
代理模式是一种设计模式,提供了对目标对象额外的访问方式,即通过代理对象访问目标对象,这样可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对象的功能。
举个例子:
在租房的时候,有的人会通过房东直租,有的人会通过中介租房。中介一般是不是会提供一些额外的服务,这里的中介就相当于代理。
动态代理实现方式:
第三方类实现:CGLIB基于ASM(一个 Java 字节码操作框架)
如何实现动态代理:
- 基于接口的JDK动态代理
-
- 定义目标类,即被代理的类。
- 通过实现InvocationHandler接口来自定义自己的InvocationHandler;重写invoke方法,在此方法中定义增强逻辑。
- 通过Proxy.newProxyInstance方法获得代理对象。
- 通过代理对象调用目标方法;
/**
* @author 百里
*/
public interface UserService {
void readBook();
}
/**
* @author 百里
*/
public class UserServiceImpl implements UserService {
@Override
public void readBook() {
System.out.println("阅读三国演义!!!");
}
}
/**
* @author 百里
*/
public class UserProxy implements InvocationHandler {
private final Object object;
public UserProxy(Object object){
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("前置处理");
Object invoke = method.invoke(object, args);
System.out.println("后置处理");
return invoke;
}
}
/**
* JDK Proxy
*/
@Test
public void proxyDemo(){
UserService userService = (UserService) Proxy.newProxyInstance( //创建代理对象
UserServiceImpl.class.getClassLoader(), // 加载接口的类加载器
UserServiceImpl.class.getInterfaces(), // 接口
new UserProxy(new UserServiceImpl())); // 代理类,传入需要被代理类的实现类
userService.rentingHouse();
}
- 基于类的CGLIB动态代理
-
- 引入CGLIB的相关依赖。
- 定义目标类,即被代理的类。
- 创建代理类实现CGLIB的MethodInterceptor接口,并重写intercept方法,在此方法中定义增强逻辑。
- 使用Enhancer类创建代理对象,设置目标类、回调对象等参数。
- 调用代理对象的方法,实现代理行为。
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm</artifactId>
<version>9.1</version>
</dependency>
/**
* @author 百里
*/
public class UserCgLibProxy implements MethodInterceptor {
private final Objec object;
public UserCgLibProxy(Object object){
this.object = object;
}
public Object createProxy() {
// 通过CGLIB动态代理获取代理对象的过程
Enhancer enhancer = new Enhancer();
// 设置enhancer对象的父类
enhancer.setSuperclass(object.getClass());
// 设置enhancer的回调对象
enhancer.setCallback(new UserCgLibProxy(object.getClass()));
// 返回代理对象
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("前置处理");
Object invoke = methodProxy.invokeSuper(o, objects);
System.out.println("后置处理");
return invoke;
}
}
/**
* CGLIB
*/
@Test
public void cglibProxyDemo(){
UserCgLibProxy userCgLibProxy = new UserCgLibProxy(new UserServiceImpl());
UserServiceImpl proxy = (UserServiceImpl)userCgLibProxy.createProxy();
proxy.rentingHouse();
}
JDK Proxy与CGLIB的区别:
- 基于接口 vs. 基于类:
-
- JDK Proxy 只能代理接口类型,它通过实现指定接口并生成代理对象来实现代理功能。
- CGLIB 可以代理普通的类,它通过继承目标类,并在子类中重写方法来实现代理。
- 实现方式:
-
- JDK Proxy 是基于反射机制实现的,它利用 Java 的反射 API 动态生成代理对象。
- CGLIB 使用了字节码生成库,直接操作字节码生成代理类。相比于 JDK 代理的反射调用,CGLIB 的方法调用更快速。
- 性能:
-
- 由于 CGLIB 是直接对字节码进行操作,所以在创建和执行代理对象时通常比 JDK 代理更快速。
- JDK Proxy 的性能略低,因为它涉及到反射调用的开销。JDK8 版本已经优化,性能与 CGLIB 差不多。
- 库依赖:
-
- JDK Proxy 是 Java 标准库的一部分,无需额外的依赖。
- CGLIB 需要引入相关的第三方库。