计算机系统应用教程网站

网站首页 > 技术文章 正文

Java面试题:Java代理的几种实现方式?

btikc 2024-12-13 11:56:15 技术文章 22 ℃ 0 评论

在 Java 中,代理有以下几种实现方式:

静态代理


  1. 定义与实现方式

静态代理是由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class 文件就已经存在了。静态代理通常需要实现与目标对象相同的接口,并在代理类中持有目标对象的引用。在代理方法中,可以在调用目标对象的方法前后添加额外的逻辑。例如,有一个接口Subject和一个实现了该接口的目标类RealSubject,可以创建一个代理类StaticProxy实现Subject接口,并在其中持有RealSubject的引用。

  1. 特点

优点:可以在不修改目标对象的情况下,为目标对象添加额外的功能。实现简单,容易理解。

缺点:如果目标对象的接口发生变化,代理类也需要相应地修改。如果有多个目标对象,需要为每个目标对象创建一个代理类,代码冗余度高。

动态代理

  1. Java 动态代理(基于接口)

实现原理:Java 动态代理是在运行时动态生成代理类的字节码,并加载到 JVM 中。它要求目标对象必须实现一个接口,通过java.lang.reflect.Proxy类来创建代理对象。动态代理的核心是利用反射机制,在运行时生成一个实现了目标对象接口的代理类。这个代理类包含了一个InvocationHandler接口的实现,用于处理对目标对象方法的调用。当调用代理对象的方法时,实际上会调用InvocationHandler的invoke方法。在invoke方法中,可以在调用目标对象的方法前后添加额外的逻辑,如日志记录、性能监控等。

实现步骤:

定义一个接口,目标对象和代理对象都要实现这个接口。

创建目标对象的实现类。实现InvocationHandler接口,在invoke方法中添加代理逻辑,并调用目标对象的方法。

使用Proxy.newProxyInstance方法创建代理对象,传入目标对象的类加载器、目标对象实现的接口数组和InvocationHandler实例。

Java 代码实现示例:

interface Subject {
    // 定义一个方法
    void doSomething();
}

class RealSubject implements Subject {
    @Override
    // 目标对象的方法实现
    public void doSomething() {
        System.out.println("RealSubject is doing something.");
    }
}

class DynamicProxyHandler implements InvocationHandler {
    private Object target;

    public DynamicProxyHandler(Object target) {
        // 传入目标对象进行保存
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Before calling method.");
        // 调用目标对象的方法
        Object result = method.invoke(target, args);
        System.out.println("After calling method.");
        return result;
    }
}

public class JavaDynamicProxyExample {
    public static void main(String[] args) {
        Subject realSubject = new RealSubject();
        // 使用动态代理创建代理对象
        Subject proxySubject = (Subject) Proxy.newProxyInstance(
                RealSubject.class.getClassLoader(),
                new Class[]{Subject.class},
                new DynamicProxyHandler(realSubject));
        proxySubject.doSomething();
    }
}
  1. CGLIB 动态代理(基于继承)

实现原理:CGLIB(Code Generation Library)是一个强大的代码生成库,可以在运行时动态生成目标类的子类作为代理类。它不需要目标类实现接口,通过继承目标类来实现代理。CGLIB 使用字节码生成技术,在运行时生成一个继承自目标类的子类,并在子类中重写目标类的方法。在重写的方法中,可以添加额外的逻辑。CGLIB 使用net.sf.cglib.proxy.Enhancer类来创建代理对象。在设置回调对象时,可以定义代理对象的方法调用行为。这个回调对象通常是一个实现了net.sf.cglib.proxy.MethodInterceptor接口的类,在intercept方法中可以处理对目标方法的调用。

实现步骤:

创建目标对象的类。

实现MethodInterceptor接口,在intercept方法中添加代理逻辑,并调用目标对象的方法。

使用Enhancer类创建代理对象,设置目标对象的类、回调对象等参数。

Java 代码实现示例:

class TargetClass {
    public void doSomething() {
        System.out.println("TargetClass is doing something.");
    }
}

class CglibProxyInterceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("Before calling method.");
        // 调用目标对象的方法
        Object result = proxy.invokeSuper(obj, args);
        System.out.println("After calling method.");
        return result;
    }
}

public class CglibDynamicProxyExample {
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(TargetClass.class);
        // 设置回调对象
        enhancer.setCallback(new CglibProxyInterceptor());
        // 创建代理对象
        TargetClass proxyObject = (TargetClass) enhancer.create();
        proxyObject.doSomething();
    }
}
  1. 特点

优点:可以在运行时动态地创建代理对象,灵活性高。对于实现了相同接口的多个目标对象,可以使用相同的代理逻辑,减少代码冗余。

缺点:动态生成代理类的字节码会带来一定的性能开销。对于一些复杂的代理逻辑,实现起来可能比较复杂。

Java 中的代理有静态代理和动态代理两种主要实现方式。静态代理实现简单,但代码冗余度高;动态代理灵活性高,但有一定的性能开销。在实际应用中,可以根据具体的需求选择合适的代理方式。

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表