代理模式
代理模式是一种应用非常广泛的设计模式,当客户端代码需要调用某个对象时,客户端实际上也不关心是否准确得到该对象,它只要一个能提供该功能的对象即可,此时我们就可返回该对象的代理(Proxy)。
在这种设计方式下,系统会为某个对象提供一个代理对象,并由代理对象控制对源对象的引用。代理就是一个 Java 对象代表另一个 Java 对象来采取行动。在某些情况下,客户端代码不想或不能够直接调用被调用者,代理对象可以在客户和目标对象之间起到中介的作用。
对客户端而言,它不能分辨出代理对象与真实对象的区别,它也无须分辨代理对象和真实对象的区别。客户端代码并不知道真正的被代理对象,客户端代码面向接口编程,它仅仅持有一个被代理对象的接口。
总而言之,只要客户端代码不能或不想直接访问被调用对象——这种情况有很多原因,比如需要创建一个系统开销很大的对象,或者被调用对象在远程主机上,或者目标对象的功能还不足以满足需求……,而是额外创建一个代理对象返回给客户端使用,那么这种设计方式就是代理模式。
下面示范一个简单的代理模式,程序首先提供了一个 Image 接口,代表大图片对象所实现的接口,该接口代码如下:
清单 3. Image.java
public interface Image
{
void show();
}
该接口提供了一个实现类,该实现类模拟了一个大图片对象,该实现类的构造器使用 Thread.sleep() 方法来暂停 3s。下面是该 BigImage 的程序代码。
清单 4. BigImage.java
// 使用该 BigImage 模拟一个很大图片
public class BigImage implements Image
{
public BigImage()
{
try
{
// 程序暂停 3s 模式模拟系统开销
Thread.sleep(3000);
System.out.println("图片装载成功 ...");
}
catch (InterruptedException ex)
{
ex.printStackTrace();
}
}
// 实现 Image 里的 show() 方法
public void show()
{
System.out.println("绘制实际的大图片");
}
}
上面的程序代码暂停了 3s,这表明创建一个 BigImage 对象需要 3s 的时间开销——程序使用这种延迟来模拟装载此图片所导致的系统开销。如果不采用代理模式,当程序中创建 BigImage 时,系统将会产生 3s 的延迟。为了避免这种延迟,程序为 BigImage 对象提供一个代理对象,BigImage 类的代理类如下所示。
清单 5. ImageProxy.java
public class ImageProxy implements Image
{
// 组合一个 image 实例,作为被代理的对象
private Image image;
// 使用抽象实体来初始化代理对象
public ImageProxy(Image image)
{
this.image = image;
}
/**
* 重写 Image 接口的 show() 方法
* 该方法用于控制对被代理对象的访问,
* 并根据需要负责创建和删除被代理对象
*/
public void show()
{
// 只有当真正需要调用 image 的 show 方法时才创建被代理对象
if (image == null)
{
image = new BigImage();
}
image.show();
}
}
上面的 ImageProxy 代理类实现了与 BigImage 相同的 show() 方法,这使得客户端代码获取到该代理对象之后,可以将该代理对象当成 BigImage 来使用。
在 ImageProxy 类的 show() 方法中增加了控制逻辑,这段控制逻辑用于控制当系统真正调用 image 的 show() 时,才会真正创建被代理的 BigImage 对象。下面程序需要使用 BigImage 对象,但程序并不是直接返回 BigImage 实例,而是先返回 BigImage 的代理对象,如下面程序所示。
清单 6. BigImageTest.java
public class BigImageTest
{
public static void main(String[] args)
{
long start = System.currentTimeMillis();
// 程序返回一个 Image 对象,该对象只是 BigImage 的代理对象
Image image = new ImageProxy(null);
System.out.println("系统得到 Image 对象的时间开销 :" +
(System.currentTimeMillis() - start));
// 只有当实际调用 image 代理的 show() 方法时,程序才会真正创建被代理对象。
image.show();
}
}
上面程序初始化 image 非常快,因为程序并未真正创建 BigImage 对象,只是得到了 ImageProxy 代理对象——直到程序调用 image.show() 方法时,程序需要真正调用 BigImage 对象的 show() 方法,程序此时才真正创建 BigImage 对象。运行上面程序,看到如图 6 所示的结果。
图 6. 使用代理模式提高性能
图 6. 使用代理模式提高性能
看到如图 6 所示的运行结果,读者应该能认同:使用代理模式提高了获取 Image 对象的系统性能。但可能有读者会提出疑问:程序调用 ImageProxy 对象的 show() 方法时一样需要创建 BigImage 对象啊,系统开销并未真正减少啊?只是这种系统开销延迟了而已啊?
我们可以从如下两个角度来回答这个问题:
把创建 BigImage 推迟到真正需要它时才创建,这样能保证前面程序运行的流畅性,而且能减少 BigImage 在内存中的存活时间,从宏观上节省了系统的内存开销。
有些情况下,也许程序永远不会真正调用 ImageProxy 对象的 show() 方法——意味着系统根本无须创建 BigImage 对象。在这种情形下,使用代理模式可以显著地提高系统运行性能。
与此完全类似的是,Hibernate 也是通过代理模式来“推迟”加载关联实体的时间,如果程序并不需要访问关联实体,那程序就不会去抓取关联实体了,这样既可以节省系统的内存开销,也可以缩短 Hibernate 加载实体的时间。
回页首
小结
Hibernate 的延迟加载(lazy load)本质上就是代理模式的应用,我们在过去的岁月里就经常通过代理模式来降低系统的内存开销、提升应用的运行性能。Hibernate 充分利用了代理模式的这种优势,并结合了 Javassist 或 CGLIB 来动态地生成代理对象,这更加增加了代理模式的灵活性,Hibernate 给这种用法一个新名称:延迟加载。无论怎样,充分分析、了解这些开源框架的实现可以更好的感受经典设计模式的优势所在。
分享到:
相关推荐
《Hibernate延迟加载与代理模式解析》 在Java的持久化框架Hibernate中,延迟加载(Lazy Load)是一项重要的优化策略,其核心目标是提高系统性能,减少内存占用,避免不必要的数据库交互。延迟加载允许我们在需要...
2. **懒加载的工作机制**:MyBatis通过代理对象实现延迟加载。当我们尝试访问延迟加载的属性时,代理对象会检查该属性是否已经被加载,如果没有,则执行SQL查询并返回结果。 3. **注意事项**:延迟加载只有在会话...
**jQuery图片延迟加载技术详解** 在网页设计中,图片加载是一项关键任务,尤其对于内容丰富的网站,如果所有图片一次性加载,可能会导致页面加载速度变慢,用户体验下降。为了解决这个问题,开发人员引入了“图片...
图片延迟加载是一种优化网页性能的技术,它通过只加载视口内的图片来减少页面初始化时的数据传输量,提高页面加载速度,提升用户体验。在本场景中,我们关注的是使用jQuery库实现这一功能的jQuery.lazyload插件。 ...
- **Hibernate的代理对象**:在Session关闭前,通过调用关联对象的方法触发加载。但这种方法需要对代码逻辑有所了解,避免在不必要的地方触发加载。 - **使用Spring Data JPA的`@Transactional`注解**:在服务层方法...
在Hibernate中,延迟加载是通过代理模式实现的。当Hibernate加载一个实体时,默认不会立即加载其关联的实体或集合属性。相反,它会创建一个代理对象来表示这些属性。当程序试图访问这些属性时,Hibernate会在后台...
**jQuery图片延迟加载技术详解** 在网页设计中,图片往往是页面加载速度的主要影响因素,尤其当页面包含大量图片时,用户可能需要等待较长时间才能看到完整的内容。为了解决这个问题,"图片延迟加载"(Lazy Load)...
### js设置延迟加载 在现代Web开发中,为了提高用户体验并优化资源管理,开发者们常常会用到“延迟加载”(Lazy Loading)技术。本文将详细介绍如何使用JavaScript实现页面元素或功能的延迟加载,帮助读者更好地...
延迟加载的核心思想是只在用户需要时才加载图像或其他资源,而不是一次性全部加载。 首先,我们来详细了解一下延迟加载的基本原理。当一个网页被加载时,通常会包含大量的图像、视频等媒体元素。这些元素往往占据了...
在JavaScript的世界里,延迟加载(Lazy Loading)是一种优化网页性能的技术,它允许我们仅在真正需要时才加载资源,如图片、脚本或视频。这种技术可以显著减少初始页面加载时间,提高用户体验,并减少服务器压力。...
"延迟加载"是一种常见的策略,用于提升网页的加载速度和用户体验。本篇文章将详细讲解延迟加载在JavaScript(js)和jQuery中的应用,以及如何实现页面和图片的延迟加载。 一、延迟加载的概念 延迟加载,也称为懒...
一种解决方法是在HTML中保留原始的"src"属性,仅对用户代理(浏览器)应用延迟加载。 通过以上介绍,我们了解了如何利用jQuery实现图片延迟加载。这种技术在现代网页开发中具有广泛的应用,不仅可以提升网页性能,...
延迟加载是一种优化策略,它的核心思想是不立即加载所有数据,而是在实际需要时才进行加载。在 Mybatis 中,延迟加载主要应用于关联对象。例如,当我们查询一个用户时,如果不使用延迟加载,那么用户的订单、地址等...
这是一款有关网页图片延迟加载的小案例,主要包括了图片随滚动条延迟加载、整个页面loading延迟加载、图片延迟加载、iframe打开页面延迟加载的技术。通过延迟加载技术可以提升网站的性能,有需要的朋友可以下载看看...
延迟加载(Lazy Loading)是一种设计模式,其核心思想是在真正需要数据时才加载数据,而不是一开始就加载所有数据。这种策略能够有效地减少应用程序启动时的内存占用,提高系统的性能。 在Hibernate中,延迟加载...
网页图片延迟加载,也称为懒加载(Lazy Loading),是一种优化网页性能的技术,它允许网页在初始加载时只加载可见区域的图片,而将其他非可视区域的图片推迟到用户滚动到相应位置时再加载。这种技术可以显著减少网页...
这种技术允许网页在不阻塞页面渲染的情况下,延迟加载非关键性的脚本和样式表,从而提高页面的初始加载速度,提升用户体验。尤其在支持像IE6这样的较旧浏览器时,这种策略显得尤为重要,因为这些浏览器可能对大量...
图片延迟加载技术是一种优化网页性能的方法,主要用于提升页面加载速度和节省用户数据流量。在“Fish整理图片延迟加载技术”中,我们主要关注如何利用这种技术来提高网站用户体验。Fish可能是一个开发人员的名字,他...