阿里十年资深程序员吐血总结之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();
}
}
上面这段代码实现了代理模式的类代理一个示例,其具体含义如下:
ISubject
是一个接口,其中定义了一个request()
方法,代表某个操作。RealSubject
是ISubject
接口的实现类,实现了request()
方法,具体实现为输出 “RealSubject request.”。ProxySubject
是ISubject
接口的代理类,它包含了一个realSubject
成员变量,该变量指向一个ISubject
类型的真实主题(即被代理的对象)。在ProxySubject
中,重写了request()
方法,在真实主题的操作前后添加了一些额外的操作,具体实现为输出 “before…” 和 “after…”。Main
类中,创建了一个RealSubject
对象realSubject
,并使用它创建了一个代理对象proxy
,即ProxySubject
。在调用proxy
的request()
方法时,会先输出 “before…”,然后调用真实主题的request()
方法,即RealSubject
的request()
方法,最后输出 “after…”。因此,通过代理对象可以在不修改真实主题的情况下,对其进行增强或控制。
代理模式常用于控制对一个对象的访问,它可以使得代理对象控制对真实主题的访问,并在访问前后执行一些额外的操作,如安全检查、性能优化、日志记录等。
3.动态代理都是通过反射实现的吗
是的,动态代理通常都是基于 Java 反射机制实现的。
在 Java 中,我们可以使用 java.lang.reflect.Proxy
类来创建代理对象,该类提供了一个 newProxyInstance()
方法,用于创建一个实现了指定接口的代理对象。
该方法接收三个参数:
- ClassLoader loader:指定代理类的类加载器。
- Class<?>[] interfaces:指定实现的接口。
- InvocationHandler h:指定代理对象的调用处理程序,即对代理对象方法的调用会被转发到该处理程序的
invoke()
方法中。
在 invoke()
方法中,我们可以通过反射机制调用实际对象的方法,并添加一些额外的功能。
因此,动态代理通常都是通过反射机制实现的。
4.jdk动态代理和cglib动态代理的区别
JDK 动态代理和 CGLIB 动态代理都是常见的 Java 动态代理方式,它们的区别主要有以下几点:
- 实现方式不同
JDK 动态代理是基于接口的代理方式,它要求代理类实现与目标类相同的接口。代理类在运行时通过反射机制动态生成,它只能代理接口,而不能代理类。
CGLIB 动态代理是基于继承的代理方式,它要求目标类不能被 final 修饰,代理类会继承目标类,并重写其中的方法。代理类在运行时通过 ASM 字节码生成框架动态生成,它既可以代理接口,也可以代理类。
- 性能不同
JDK 动态代理在生成代理类时,需要实现接口并通过反射机制调用目标方法,因此在处理速度和效率上比 CGLIB 动态代理慢一些。但是,JDK 动态代理不会生成代理类的字节码,因此占用内存更小。
CGLIB 动态代理在生成代理类时,直接继承目标类并重写其中的方法,因此在处理速度和效率上比 JDK 动态代理快一些。但是,CGLIB 动态代理会生成代理类的字节码,并在内存中保存,因此占用内存更大。
- 代理目标不同
JDK 动态代理只能代理实现了接口的类,不能代理没有实现接口的类。而 CGLIB 动态代理可以代理任何没有被 final 修饰的类。
总的来说,JDK 动态代理和 CGLIB 动态代理各有优缺点,选择哪种代理方式取决于具体应用场景。如果目标类实现了接口,建议使用 JDK 动态代理;如果目标类没有实现接口或者需要代理的方法比较多,建议使用 CGLIB 动态代理。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· .NET10 - 预览版1新功能体验(一)