2023-07-21Spring中用到的设计模式之一--适配器模
一张图说明 Aware的原理
![](https://img.haomeiwen.com/i1436393/7f8dc001080ffa39.png)
Spring中的Aware接口是一种适配器模式(Adapter Pattern)的应用。
适配器模式是一种结构型设计模式,它允许将一个类的接口转换为另一个类的接口,从而使不兼容的接口可以协同工作。在Spring中,Aware接口充当了适配器的角色,它将Spring容器中的一些特定功能暴露给Bean,使得Bean可以获取与Spring容器相关的信息和功能。
Spring中的Aware接口通常以Aware命名,例如ApplicationContextAware、BeanFactoryAware等。当Bean实现这些Aware接口时,Spring在初始化Bean的时候,会自动调用相应的set方法,将相应的资源或信息注入到Bean中。
以ApplicationContextAware为例,它允许Bean获取对ApplicationContext的引用,从而可以通过ApplicationContext来访问Spring容器的各种服务和功能。在这种情况下,ApplicationContext就是一个适配器,将Spring容器的功能适配给了Bean。
使用Aware接口的好处是,它能够在Bean的生命周期中注入所需的资源或信息,而不需要Bean自己主动去查找或请求。这种模式降低了Bean对Spring容器的依赖性,提高了代码的可扩展性和灵活性。
总结一下,Spring中的Aware接口采用了适配器模式,允许Bean获取对Spring容器的引用或其他特定资源,从而将Spring的功能适配给Bean,提供更灵活和松耦合的设计。
有人可能将Spring中的Aware接口与模板方法模式(Template Method Pattern)进行类比,这是因为在某种程度上它们有一些相似之处,但也要注意它们之间的区别。
模板方法模式是一种行为型设计模式,它定义了一个算法的骨架,将一些步骤延迟到子类来实现。这样可以使得算法的结构稳定,而具体的实现可以在子类中灵活地改变,从而实现了代码复用和扩展。
在模板方法模式中,通常有一个抽象类,其中定义了一个模板方法,该方法包含了算法的主要步骤,并通过调用一些抽象方法和钩子方法来完成具体的实现。子类继承这个抽象类并实现抽象方法,从而完成对算法的定制。
现在让我们看看Spring中的Aware接口和模板方法模式之间的相似之处:
都涉及到在父类(或接口)中定义一些骨架结构:在模板方法模式中,抽象类中的模板方法就是算法的骨架,而在Spring的Aware接口中,接口中的set*方法就可以看作是Bean获取资源的骨架。
都允许子类(或实现类)进行自定义:在模板方法模式中,子类实现抽象方法可以自定义算法的实现细节,而在Spring的Aware接口中,Bean实现接口的方法可以获取到特定资源或信息,完成自定义的逻辑。
虽然有上述相似之处,但需要强调的是,Aware接口并不是典型的模板方法模式的应用。在模板方法模式中,抽象类定义了算法的骨架,而在Spring的Aware接口中,接口只是定义了一个回调方法,用于在Bean的初始化阶段注入特定资源。Aware接口更像是一个回调接口,而不是模板方法。
在软件设计中,常常会发现某些模式和原则之间有一些相似之处或共通点,因此有时会有人将它们进行类比或联想。虽然Aware接口与模板方法模式之间有一些类似之处,但仍然需要理解它们的不同和各自的设计目的。
常见的 Spring Aware 接口
Aware子接口 | 描述 |
---|---|
BeanNameAware | 获取容器中 Bean 的名称 |
BeanFactoryAware | 获取当前 BeanFactory ,这样可以调用容器的服务 |
ApplicationContextAware | 同上,在BeanFactory 和 ApplicationContext 的区别 中已明确说明 |
MessageSourceAware | 获取 Message Source 相关文本信息 |
ApplicationEventPublisherAware | 发布事件 |
ResourceLoaderAware | 获取资源加载器,这样获取外部资源文件 |
当然不止以上这些 Aware, 通常使用 Spring Aware 的目的是为了让 Bean 获得 Spring 容器的服务。
代码中 有一段是资源权限问题的处理(方法 AccessController.doPrivileged() 90行位置)
参考文章:
https://www.cnblogs.com/liruilong/p/14810513.html
补充说明:
程序A想在/tmp目录中新建一个文件,它没有相应的权限,但是它引用了另外一个B.Jar包,刚好B有权限在/tmp目录中新建文件,而B在新建文件的时候采用的是AccessController.doPrivileged方法进行的,这种情况下A就可以调用B的创建文件方法进行文件创建。
AccessController.doPrivileged中断了栈检查过程,使得后续原本没有权限的代码也可以正常执行,从而成功创建文件,如果不使用AccessController.doPrivileged,会一直进行栈检查直到栈底位置,在程序A的栈帧(栈底)中会抛出权限异常,文件创建失败。