Java中的代理模式详解及实例代码
发布时间 - 2026-01-10 22:51:47 点击率:次java 代理模式详解

前言:
在某些情况下,一个客户不想或者不能直接引用一个对象,此时可以通过一个称之为“代理”的第三者来实现间接引用。代理对象可以在客户端和目标对象之间起到 中介的作用,并且可以通过代理对象去掉客户不能看到 的内容和服务或者添加客户需要的额外服务。
简单来说代理模式就是通过一个代理对象去访问一个实际对象,并且可以像装饰模式一样给对象添加一些功能。
静态代理
所谓静态代理即在程序运行前代理类就已经存在,也就是说我们编写代码的时候就已经把代理类的代码写好了,而动态代理则是在程序运行时自动生成代理类。
描述起来太过抽象,看一下代码就明白是怎么回事了
main
public class Main {
public static void main(String[] args) {
Water water = new Water();
WaterProxy waterProxy = new WaterProxy(water);
waterProxy.drink();
}
}
接口
//代理类与被代理类共同实现的接口
public interface Drink {
void drink();
}
被代理类
//被代理的类
public class Water implements Drink {
@Override
public void drink() {
System.out.println("drink water");
}
}
代理类
//代理类
//与被代理类实现同一个接口
public class DrinkProxy implements Drink {
private Drink drinkImpl;
//通过构造函数传入Water对象
public DrinkProxy(Drink drinkImpl) {
this.drinkImpl = drinkImpl;
}
@Override
public void drink() {
//在执行被代理对象的方法前做一些事情
System.out.println("before drink");
//执行被代理对象的方法
drinkImpl.drink();
//在执行被代理对象的方法后做一些事
System.out.println("after drink");
}
}
执行结果
before drink drink water after drink
动态代理
有时候我们只想改变代理类所代理的类,但是代理对象执行实际对象的方法前后所做的事情是一样的,正所谓铁打的代理类,流水的被代理类。而采用静态代理就只能代理实现了同一接口的类,如果要代理任意类则必须写很多重复的代理类。此时我们可以采用动态代理,Java已经为实现动态代理提供了一套比较方便的工具。
java.lang.reflect.Proxy类中可以动态生成代理对象的方法
/** *返回实现了指定接口的对象,调用代理对象的方法会调用 *InvocationHandler的invoke方法 * * @param loader 获取代理类所使用的类加载器 * @param interfaces 代理类所要实现的接口 * @param h 实现了InvocationHandler接口的对象 * @return 代理对象 */ public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces, InvocationHandler h)
InvocationHandler接口
/**
*每个代理类都有一个关联的InvocationHandler
*当代理对象执行一个方法的时候会直接执行invoke方法
*/
public interface InvocationHandler {
/**
* @param 调用该方法的代理对象
* @param method 代理对象所调用的方法
* @param args 调用的方法的参数
* @return 调用的方法的返回值
*/
public Object invoke(Object proxy, Method method, Object[] args)
}
描述总是比较抽象,还是看实际例子比较好理解
例子
InvocationHandler接口的实现类
public class CommonInvocationHandler implements InvocationHandler {
//被代理的对象
private Object proxied;
public CommonInvocationHandler(Object proxied) {
this.proxied = proxied;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//在调用被代理对象的方法前做一些事情
System.out.println("before doing something");
//调用被代理对象的方法
Object result = method.invoke(proxied, args);
//在调用被代理对象的方法后做一些事情
System.out.println("after doing something");;
return result;
}
}
Main
public class Main {
public static void main(String[] args) {
//被代理的对象
Water water = new Water();
//动态获取代理对象
Drink waterProxy =
(Drink) Proxy.newProxyInstance(water.getClass().getClassLoader(),
water.getClass().getInterfaces(),
new CommonInvocationHandler(water));
//通过代理对象调用方法
waterProxy.drink();
}
}
输出结果
before doing something drink water after doing something
也可以不要具体的被代理对象,但是必须有相应的接口(没有实现接口的类可以使用cglib实现动态代理)才可以动态获取代理对象。像最近比较火的Retrofit就直接通过声明好的接口使用动态代理进行网络请求。
例子
简单的模拟一下retrofit
POST注解
//Post请求注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface POST {
String value() default "";
}
Query注解
//Post请求注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface POST {
String value() default "";
}
Service接口
public interface Service {
//用POST注解声明请求的方式和相对路径
@POST("/login")
//@Query注解声明请求的参数名
void login(@Query("username")String username,
@Query("password")String password);
}
Main
public class Main {
public static void main(String[] args) {
// 动态获取Service接口的代理
Service service = (Service) Proxy.newProxyInstance(Service.class.getClassLoader(),
new Class[] { Service.class }, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 通过注解获取请求的相对路径
String retativePath = ((POST) method.getAnnotations()[0]).value();
System.out.println("relative path: " + retativePath);
// 获取参数的注解
Annotation[][] parameterAnnotations = method.getParameterAnnotations();
// 通过参数的注解获取请求参数
for (int i = 0; i < parameterAnnotations.length; i++) {
if (parameterAnnotations[i].length != 0) {
for (int j = 0; j < parameterAnnotations[i].length; j++) {
Query query = (Query) parameterAnnotations[i][j];
System.out.println(query.value() + ": " + args[i].toString());
}
}
}
return null;
}
});
// 调用代理对象的方法
service.login("hello", "world");
}
}
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!
# java
# 代理模式
# 代理模式详解
# 代理模式实例
# java代理模式与动态代理模式详解
# java实现http的Post、Get、代理访问请求
# Java中反射动态代理接口的详解及实例
# 基于接口实现java动态代理示例
# 详解java中动态代理实现机制
# java动态代理(jdk与cglib)详细解析
# java实现动态代理方法浅析
# Java动态代理的应用详解
# 详解java动态代理的2种实现方式
# 浅谈Java注解和动态代理
# Java基础之代理原理与用法详解
# 可以通过
# 实现了
# 都有
# 好了
# 则是
# 我们可以
# 希望能
# 才可以
# 比较好
# 太过
# 只想
# 可以使用
# 所做
# 看一下
# 谢谢大家
# 所要
# 来实现
# 即在
# 自动生成
# 正所谓
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
Laravel如何使用Facades(门面)及其工作原理_Laravel门面模式与底层机制
如何构建满足综合性能需求的优质建站方案?
北京企业网站设计制作公司,北京铁路集团官方网站?
Swift中switch语句区间和元组模式匹配
python中快速进行多个字符替换的方法小结
Laravel如何获取当前登录用户信息_Laravel Auth门面使用与Session用户读取【技巧】
高防服务器租用首荐平台,企业级优惠套餐快速部署
如何在Tomcat中配置并部署网站项目?
Laravel Admin后台管理框架推荐_Laravel快速开发后台工具
千问怎样用提示词获取健康建议_千问健康类提示词注意事项【指南】
制作电商网页,电商供应链怎么做?
如何在建站之星绑定自定义域名?
教学论文网站制作软件有哪些,写论文用什么软件
?
惠州网站建设制作推广,惠州市华视达文化传媒有限公司怎么样?
如何在阿里云高效完成企业建站全流程?
Bootstrap CSS布局之列表
Android中Textview和图片同行显示(文字超出用省略号,图片自动靠右边)
Laravel如何使用Blade组件和插槽?(Component代码示例)
,交易猫的商品怎么发布到网站上去?
linux top下的 minerd 木马清除方法
如何在腾讯云服务器快速搭建个人网站?
Laravel Artisan命令怎么自定义_创建自己的Laravel命令行工具完全指南
制作旅游网站html,怎样注册旅游网站?
Bootstrap整体框架之JavaScript插件架构
如何用5美元大硬盘VPS安全高效搭建个人网站?
Laravel怎么处理异常_Laravel自定义异常处理与错误页面教程
网站制作企业,网站的banner和导航栏是指什么?
Java Adapter 适配器模式(类适配器,对象适配器)优缺点对比
电商网站制作多少钱一个,电子商务公司的网站制作费用计入什么科目?
阿里云网站搭建费用解析:服务器价格与建站成本优化指南
如何在建站主机中优化服务器配置?
html如何与html链接_实现多个HTML页面互相链接【互相】
javascript日期怎么处理_如何格式化输出
Python结构化数据采集_字段抽取解析【教程】
极客网站有哪些,DoNews、36氪、爱范儿、虎嗅、雷锋网、极客公园这些互联网媒体网站有什么差异?
Laravel观察者模式如何使用_Laravel Model Observer配置
如何在万网利用已有域名快速建站?
公司门户网站制作公司有哪些,怎样使用wordpress制作一个企业网站?
实例解析angularjs的filter过滤器
如何用美橙互联一键搭建多站合一网站?
HTML透明颜色代码怎么让图片透明_给img元素加透明色的技巧【方法】
北京专业网站制作设计师招聘,北京白云观官方网站?
如何在阿里云部署织梦网站?
如何在不使用负向后查找的情况下匹配特定条件前的换行符
Laravel如何创建自定义中间件?(Middleware代码示例)
昵图网官网入口 昵图网素材平台官方入口
如何在搬瓦工VPS快速搭建网站?
制作网站软件推荐手机版,如何制作属于自己的手机网站app应用?
Laravel如何集成微信支付SDK_Laravel使用yansongda-pay实现扫码支付【实战】
UC浏览器如何切换小说阅读源_UC浏览器阅读源切换【方法】

