首页 > 编程笔记 > Java笔记

策略模式在Spring源码中的应用

在 Spring 中,Resource 类是基于策略模式实现的,也是策略模式的典型应用。Resource 类的代码如下。
package org.springframework.core.io;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URL;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;

import org.springframework.lang.Nullable;

public interface Resource extends InputStreamSource {
    boolean exists();
    default boolean isReadable() {
        return exists();
    }

    default boolean isOpen() {
        return false;
    }

    default boolean isFile() {
        return false;
    }

    URL getURL() throws IOException;
   
    URI getURI() throws IOException;

    File getFile() throws IOException;
   
    default ReadableByteChannel readableChannel() throws IOException {
        return Channels.newChannel(getInputStream());
    }

    long contentLength() throws IOException;
   
    long lastModified() throws IOException;
   
    Resource createRelative(String relativePath) throws IOException;
   
    @Nullable
    String getFilename();

    String getDescription();
}
虽然 Resource 接口本身没有提供访问任何底层资源的实现逻辑,但是 Spring 会针对不同的底层资源,提供不同的 Resource 实现类,不同的实现类负责不同的资源访问逻辑,如下所示。

* @see WritableResource
* @see ContextResource
* @see UrlResource
* @see FileUrlResource
* @see FileSystemResource
* @see ClassPathResource
* @see ByteArrayResource
* @see InputStreamResource

另外,Spring 的初始化也采用了策略模式,不同类型的类采用不同的初始化策略。

InstantiationStrategy 负责使用 Bean 类的默认构造函数、带参构造函数或者工厂方法等来实例化 Bean,是一个策略模式的接口。InstantiationStrategy 接口源码如下。
package org.springframework.beans.factory.support;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.lang.Nullable;

public interface InstantiationStrategy {

    Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner)
            throws BeansException;

    Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
            Constructor<?> ctor, Object... args) throws BeansException;

    Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
            @Nullable Object factoryBean, Method factoryMethod, Object... args)
            throws BeansException;
}
顶层的策略抽象非常简单,它下面有 SimpleInstantiationStrategy 和 CglibSubclassingInstantiationStrategy 两种策略。

SimpleInstantiationStrategy 类实现了 InstantiationStrategy 接口,是一个简单用于实例化 Bean 的类。该类有一个 instantiationWithMethodInjection 方法,但是实际上这只是个钩子,并非真正支持方法注入功能。

真正支持方法注入功能的是 CglibSubclassingInstantiationStrategy 类,它继承了 SimpleInstantiationStrategy 并覆盖了 instantiationWithMethodInjection 方法。不过使用这个方法必须用到 cglib 类库,它利用 cglib 为 bean 动态生成子类,也就是代理类,在子类中生成方法注入的逻辑,然后使用这个动态生成的子类创建 bean 的实例。 

其类图如下。

拓展:上图也说明在实际应用中,多种策略之间可以继承使用。小伙伴们可以把它作为一个参考,在实际业务场景中根据需要来设计。

所有教程

优秀文章