`
仅此而已
  • 浏览: 61780 次
  • 性别: Icon_minigender_1
  • 来自: 沈阳
社区版块
存档分类
最新评论

代理模式 延迟加载【转载】

 
阅读更多
代理模式

代理模式是一种应用非常广泛的设计模式,当客户端代码需要调用某个对象时,客户端实际上也不关心是否准确得到该对象,它只要一个能提供该功能的对象即可,此时我们就可返回该对象的代理(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 延迟加载剖析与代理模式应用

    《Hibernate延迟加载与代理模式解析》 在Java的持久化框架Hibernate中,延迟加载(Lazy Load)是一项重要的优化策略,其核心目标是提高系统性能,减少内存占用,避免不必要的数据库交互。延迟加载允许我们在需要...

    mybatis延迟加载样例

    2. **懒加载的工作机制**:MyBatis通过代理对象实现延迟加载。当我们尝试访问延迟加载的属性时,代理对象会检查该属性是否已经被加载,如果没有,则执行SQL查询并返回结果。 3. **注意事项**:延迟加载只有在会话...

    jquery图片延迟加载

    **jQuery图片延迟加载技术详解** 在网页设计中,图片加载是一项关键任务,尤其对于内容丰富的网站,如果所有图片一次性加载,可能会导致页面加载速度变慢,用户体验下降。为了解决这个问题,开发人员引入了“图片...

    图片延迟加载的jq

    图片延迟加载是一种优化网页性能的技术,它通过只加载视口内的图片来减少页面初始化时的数据传输量,提高页面加载速度,提升用户体验。在本场景中,我们关注的是使用jQuery库实现这一功能的jQuery.lazyload插件。 ...

    hibernate延迟加载解决

    - **Hibernate的代理对象**:在Session关闭前,通过调用关联对象的方法触发加载。但这种方法需要对代码逻辑有所了解,避免在不必要的地方触发加载。 - **使用Spring Data JPA的`@Transactional`注解**:在服务层方法...

    hibernate 延迟加载深入剖析

    在Hibernate中,延迟加载是通过代理模式实现的。当Hibernate加载一个实体时,默认不会立即加载其关联的实体或集合属性。相反,它会创建一个代理对象来表示这些属性。当程序试图访问这些属性时,Hibernate会在后台...

    jquery 图片延迟加载

    **jQuery图片延迟加载技术详解** 在网页设计中,图片往往是页面加载速度的主要影响因素,尤其当页面包含大量图片时,用户可能需要等待较长时间才能看到完整的内容。为了解决这个问题,"图片延迟加载"(Lazy Load)...

    js设置延迟加载

    ### js设置延迟加载 在现代Web开发中,为了提高用户体验并优化资源管理,开发者们常常会用到“延迟加载”(Lazy Loading)技术。本文将详细介绍如何使用JavaScript实现页面元素或功能的延迟加载,帮助读者更好地...

    延迟加载 html优化

    延迟加载的核心思想是只在用户需要时才加载图像或其他资源,而不是一次性全部加载。 首先,我们来详细了解一下延迟加载的基本原理。当一个网页被加载时,通常会包含大量的图像、视频等媒体元素。这些元素往往占据了...

    原生js延迟加载

    在JavaScript的世界里,延迟加载(Lazy Loading)是一种优化网页性能的技术,它允许我们仅在真正需要时才加载资源,如图片、脚本或视频。这种技术可以显著减少初始页面加载时间,提高用户体验,并减少服务器压力。...

    延迟加载js代码下载(包括页面延迟加载以及图片延迟加载)

    "延迟加载"是一种常见的策略,用于提升网页的加载速度和用户体验。本篇文章将详细讲解延迟加载在JavaScript(js)和jQuery中的应用,以及如何实现页面和图片的延迟加载。 一、延迟加载的概念 延迟加载,也称为懒...

    jquery延迟加载图片

    一种解决方法是在HTML中保留原始的"src"属性,仅对用户代理(浏览器)应用延迟加载。 通过以上介绍,我们了解了如何利用jQuery实现图片延迟加载。这种技术在现代网页开发中具有广泛的应用,不仅可以提升网页性能,...

    Mybatis延迟加载和缓存

    延迟加载是一种优化策略,它的核心思想是不立即加载所有数据,而是在实际需要时才进行加载。在 Mybatis 中,延迟加载主要应用于关联对象。例如,当我们查询一个用户时,如果不使用延迟加载,那么用户的订单、地址等...

    网页图片延迟加载案例.rar

    这是一款有关网页图片延迟加载的小案例,主要包括了图片随滚动条延迟加载、整个页面loading延迟加载、图片延迟加载、iframe打开页面延迟加载的技术。通过延迟加载技术可以提升网站的性能,有需要的朋友可以下载看看...

    Hibernate延迟加载以及利用Spring

    延迟加载(Lazy Loading)是一种设计模式,其核心思想是在真正需要数据时才加载数据,而不是一开始就加载所有数据。这种策略能够有效地减少应用程序启动时的内存占用,提高系统的性能。 在Hibernate中,延迟加载...

    网页图片延迟加载插件

    网页图片延迟加载,也称为懒加载(Lazy Loading),是一种优化网页性能的技术,它允许网页在初始加载时只加载可见区域的图片,而将其他非可视区域的图片推迟到用户滚动到相应位置时再加载。这种技术可以显著减少网页...

    html延迟加载JS和CSS

    这种技术允许网页在不阻塞页面渲染的情况下,延迟加载非关键性的脚本和样式表,从而提高页面的初始加载速度,提升用户体验。尤其在支持像IE6这样的较旧浏览器时,这种策略显得尤为重要,因为这些浏览器可能对大量...

    Fish整理图片延迟加载技术

    图片延迟加载技术是一种优化网页性能的方法,主要用于提升页面加载速度和节省用户数据流量。在“Fish整理图片延迟加载技术”中,我们主要关注如何利用这种技术来提高网站用户体验。Fish可能是一个开发人员的名字,他...

Global site tag (gtag.js) - Google Analytics