阿里十年资深程序员吐血总结之Java代理模式

阿里十年资深程序员吐血总结之Java代理模式


Java代理模式是怎么实现的

​ Java 代理模式是一种常见的设计模式,它可以在不改变原有代码的情况下,通过代理对象来控制访问原有对象。代理模式常用于添加额外的功能或者限制对原有对象的访问。

​ 在 Java 中,代理模式可以通过接口代理和类代理两种方式实现。

1.接口代理

​ 接口代理也称为动态代理,它是基于 Java 反射机制实现的。通过代理工厂类创建一个实现了原有接口的代理类,当调用代理类的方法时,会被重定向到实际对象的方法中。

示例代码如下:

public interface ISubject {
    void request();
}

public class RealSubject implements ISubject {
    @Override
    public void request() {
        System.out.println("RealSubject request.");
    }
}

public class ProxyFactory {
    private Object target;

    public ProxyFactory(Object target) {
        this.target = target;
    }

    public Object getProxyInstance() {
        return Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                (proxy, method, args) -> {
                    System.out.println("before...");
                    Object returnValue = method.invoke(target, args);
                    System.out.println("after...");
                    return returnValue;
                }
        );
    }
}

public class Main {
    public static void main(String[] args) {
        ISubject realSubject = new RealSubject();
        ISubject proxy = (ISubject) new ProxyFactory(realSubject).getProxyInstance();
        proxy.request();
    }
}

在上面的示例代码中,RealSubject 类实现了 ISubject 接口,它是代理的实际对象。ProxyFactory 类是代理工厂类,它创建代理对象并返回。

当调用代理对象的 request() 方法时,会先输出 “before…”,然后调用实际对象的 request() 方法,最后输出 “after…”。这样,我们就可以在代理对象中添加额外的功能,而不会改变实际对象的行为。

2.类代理

​ 类代理也称为静态代理,它是通过代理类继承或实现原有类或接口实现的。代理类重写原有类或接口的方法,并在方法中调用实际对象的方法,从而实现代理。

示例代码如下:

public interface ISubject {
    void request();
}

public class RealSubject implements ISubject {
    @Override
    public void request() {
        System.out.println("RealSubject request.");
    }
}

public class ProxySubject implements ISubject {
    private ISubject realSubject;

    public ProxySubject(ISubject realSubject) {
        this.realSubject = realSubject;
    }

    @Override
    public void request() {
        System.out.println("before...");
        realSubject.request();
        System.out.println("after...");
    }
}

public class Main {
    public static void main(String[] args) {
        ISubject realSubject = new RealSubject();
        ISubject proxy = new ProxySubject(realSubject);
        proxy.request();
    }
}

上面这段代码实现了代理模式的类代理一个示例,其具体含义如下:

  1. ISubject 是一个接口,其中定义了一个 request() 方法,代表某个操作。
  2. RealSubjectISubject 接口的实现类,实现了 request() 方法,具体实现为输出 “RealSubject request.”。
  3. ProxySubjectISubject 接口的代理类,它包含了一个 realSubject 成员变量,该变量指向一个 ISubject 类型的真实主题(即被代理的对象)。在 ProxySubject 中,重写了 request() 方法,在真实主题的操作前后添加了一些额外的操作,具体实现为输出 “before…” 和 “after…”。
  4. Main 类中,创建了一个 RealSubject 对象 realSubject,并使用它创建了一个代理对象 proxy,即 ProxySubject。在调用 proxyrequest() 方法时,会先输出 “before…”,然后调用真实主题的 request() 方法,即 RealSubjectrequest() 方法,最后输出 “after…”。因此,通过代理对象可以在不修改真实主题的情况下,对其进行增强或控制。

代理模式常用于控制对一个对象的访问,它可以使得代理对象控制对真实主题的访问,并在访问前后执行一些额外的操作,如安全检查、性能优化、日志记录等。

3.动态代理都是通过反射实现的吗

是的,动态代理通常都是基于 Java 反射机制实现的。

在 Java 中,我们可以使用 java.lang.reflect.Proxy 类来创建代理对象,该类提供了一个 newProxyInstance() 方法,用于创建一个实现了指定接口的代理对象。

该方法接收三个参数:

  1. ClassLoader loader:指定代理类的类加载器。
  2. Class<?>[] interfaces:指定实现的接口。
  3. InvocationHandler h:指定代理对象的调用处理程序,即对代理对象方法的调用会被转发到该处理程序的 invoke() 方法中。

invoke() 方法中,我们可以通过反射机制调用实际对象的方法,并添加一些额外的功能。

因此,动态代理通常都是通过反射机制实现的。

4.jdk动态代理和cglib动态代理的区别

JDK 动态代理和 CGLIB 动态代理都是常见的 Java 动态代理方式,它们的区别主要有以下几点:

  1. 实现方式不同

JDK 动态代理是基于接口的代理方式,它要求代理类实现与目标类相同的接口。代理类在运行时通过反射机制动态生成,它只能代理接口,而不能代理类。

CGLIB 动态代理是基于继承的代理方式,它要求目标类不能被 final 修饰,代理类会继承目标类,并重写其中的方法。代理类在运行时通过 ASM 字节码生成框架动态生成,它既可以代理接口,也可以代理类。

  1. 性能不同

JDK 动态代理在生成代理类时,需要实现接口并通过反射机制调用目标方法,因此在处理速度和效率上比 CGLIB 动态代理慢一些。但是,JDK 动态代理不会生成代理类的字节码,因此占用内存更小。

CGLIB 动态代理在生成代理类时,直接继承目标类并重写其中的方法,因此在处理速度和效率上比 JDK 动态代理快一些。但是,CGLIB 动态代理会生成代理类的字节码,并在内存中保存,因此占用内存更大。

  1. 代理目标不同

JDK 动态代理只能代理实现了接口的类,不能代理没有实现接口的类。而 CGLIB 动态代理可以代理任何没有被 final 修饰的类。

总的来说,JDK 动态代理和 CGLIB 动态代理各有优缺点,选择哪种代理方式取决于具体应用场景。如果目标类实现了接口,建议使用 JDK 动态代理;如果目标类没有实现接口或者需要代理的方法比较多,建议使用 CGLIB 动态代理。
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值