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 { @Override public void doSomething() { System.out.println("Doing something ..."); } } // 使用Advice(通知)来增强被代理类的功能 public class MyBeforeAdvice implements MethodBeforeAdvice { // 在目标方法执行前进行拦截 @Override public 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,否则创建UrlResource URL 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接口的使用更加灵活和便捷。