1. 適配器模式的應用
1.1適配器模式(Adapter Pattern)的原始定義是:將一個類的接口轉換為客戶期望的另一個接口,適配器可以讓不兼容的兩個類一起協同工作。
1.2 AOP中的適配器模式
在Spring的AOP中,使用Advice(通知)來增強被代理類的功能。Advice的類型有:BeforeAdvice、AfterReturningAdvice、ThrowsAdvice。每種Advice都有對應的攔截器,如MethodBeforeAdviceInterceptor、AfterReturningAdviceInterceptor、ThrowsAdviceInterceptor。
1.3 代碼示例
以下示例展示了如何使用適配器模式在Spring AOP中增強一個目標類的功能。
public interface MyService {void doSomething();
}public class MyServiceImpl implements MyService {@Overridepublic void doSomething() {System.out.println("Doing something ...");}
}// 使用Advice(通知)來增強被代理類的功能
public class MyBeforeAdvice implements MethodBeforeAdvice {// 在目標方法執行前進行攔截@Overridepublic void before(Method method, Object[] objects, Object o) throws Throwable {System.out.println("我變強,也變禿了......");}
}// 自定義適配器對象,將BeforeAdvice對象適配為一個MethodBeforeAdviceInterceptor對象
public class MyBeforeAdviceAdapter extends MethodBeforeAdviceInterceptor {public MyBeforeAdviceAdapter(MethodBeforeAdvice advice) {super(advice);}
}public class Test01 {public static void main(String[] args) {// 創建前置通知對象MyBeforeAdvice advice = new MyBeforeAdvice();// 創建適配器對象,傳入通知對象MyBeforeAdviceAdapter adapter = new MyBeforeAdviceAdapter(advice);// 獲取目標對象的代理工廠ProxyFactory factory = new ProxyFactory(new MyServiceImpl());// 向代理對象中添加適配器對象factory.addAdvice(adapter);// 獲取代理對象MyService proxy = (MyService) factory.getProxy();// 調用代理方法proxy.doSomething();}
}
每個類對應適配器模式中的如下角色:
- Target:
MyServiceImpl
類是目標對象,即需要被代理的對象。 - Adapter:
MyBeforeAdviceAdapter
類是適配器對象,它將MyBeforeAdvice
對象適配為一個MethodBeforeAdviceInterceptor
對象,使得MyBeforeAdvice
可以被應用到目標對象的代理中。 - Adaptee:
MyBeforeAdvice
類是被適配的對象,它定義了一個前置通知方法,在目標方法執行前進行攔截。 - Client:
Test01
類是客戶端,它通過創建適配器對象并將其添加到目標對象的代理中,實現了在目標方法執行前應用MyBeforeAdvice
的前置通知。
2. 策略模式的應用
策略模式是一種行為設計模式,它允許定義一系列算法,將每個算法分別封裝起來,并使它們可以相互替換。這種模式使得算法可以在不影響客戶端的情況下發生變化。在Spring框架中,策略模式的應用十分廣泛,下面是Resource接口及其實現類的示例。
2.1 Resource 接口
Spring框架的資源訪問Resource接口提供了強大的資源訪問能力。Spring框架本身大量使用了Resource接口來訪問底層資源。Resource接口本身沒有提供訪問任何底層資源的實現邏輯,而是針對不同的底層資源提供了不同的Resource實現類,這些實現類負責不同的資源訪問邏輯。
Spring為Resource接口提供了如下實現類:
UrlResource
:訪問網絡資源的實現類。ClassPathResource
:訪問類加載路徑里的資源的實現類。FileSystemResource
:訪問文件系統里的資源的實現類。ServletContextResource
:訪問相對于ServletContext路徑里的資源的實現類。InputStreamResource
:訪問輸入流資源的實現類。ByteArrayResource
:訪問字節數組資源的實現類。
這些Resource實現類針對不同的底層資源提供了相應的資源訪問邏輯,并提供便捷的包裝,以便客戶端程序的資源訪問。
public class ResourceTest {public static void main(String[] args) throws IOException {// 創建ClassPathResource對象Resource resource = new ClassPathResource("application.properties");// 調用getInputStream()方法讀取資源InputStream is = resource.getInputStream();byte[] bytes = new byte[1024];int n;while ((n = is.read(bytes)) != -1) {System.out.println(new String(bytes, 0, n));}is.close();}
}
2.2 DefaultResourceLoader
ResourceLoader
接口用于返回Resource
對象,其實現可以看作是一個生產Resource的工廠類。當創建Resource對象時,Spring會根據傳入的資源路徑來選擇相應的Resource實現類。這一過程是由Spring中的ResourceLoader
接口及其實現類DefaultResourceLoader
來完成的。
DefaultResourceLoader
中的getResource
方法會根據傳入的資源路徑選擇相應的Resource
實現類,從而實現了策略模式的效果。
public Resource getResource(String location) {Assert.notNull(location, "Location must not be null");// 遍歷ProtocolResolver集合,通過ProtocolResolver來解析資源路徑for (ProtocolResolver protocolResolver : this.getProtocolResolvers()) {Resource resource = protocolResolver.resolve(location, this);if (resource != null) {return resource;}}// 沒有找到對應的ProtocolResolver,使用默認的處理方式if (location.startsWith("/")) {// 以斜杠開頭的路徑,表示基于ServletContext的相對路徑return this.getResourceByPath(location);} else if (location.startsWith("classpath:")) {// 以classpath:開頭的路徑,表示在classpath下查找資源return new ClassPathResource(location.substring("classpath:".length()), this.getClassLoader());} else {try {// 嘗試將路徑解析為URL,如果是文件URL則創建FileUrlResource,否則創建UrlResourceURL url = new URL(location);return (Resource) (ResourceUtils.isFileURL(url) ? new FileUrlResource(url) : new UrlResource(url));} catch (MalformedURLException var5) {// 如果路徑無法解析為URL,則當做相對路徑來處理return this.getResourceByPath(location);}}
}
在上述代碼中,getResource
方法根據傳入的資源路徑選擇相應的Resource實現類,從而實現了策略模式的效果。不同的實現類負責不同類型資源的訪問邏輯,使得Resource接口的使用更加靈活和便捷。