Spring中使用的設計模式

曹自標發表於2021-01-19

建立型

單例模式

單例模式概念是一個單一的類,該類負責建立自己的物件,同時確保只有單個物件被建立。Spring中預設Bean建立可以認為是一種使用ConcurrentHashMap實現的特殊的單例模式

@Bean

private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
	// Quick check for existing instance without full singleton lock
	Object singletonObject = this.singletonObjects.get(beanName);
	if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
		singletonObject = this.earlySingletonObjects.get(beanName);
		if (singletonObject == null && allowEarlyReference) {
			synchronized (this.singletonObjects) {
				// Consistent creation of early reference within full singleton lock
				singletonObject = this.singletonObjects.get(beanName);
				if (singletonObject == null) {
					singletonObject = this.earlySingletonObjects.get(beanName);
					if (singletonObject == null) {
						ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
						if (singletonFactory != null) {
							singletonObject = singletonFactory.getObject();
							this.earlySingletonObjects.put(beanName, singletonObject);
							this.singletonFactories.remove(beanName);
						}
					}
				}
			}
		}
	}
	return singletonObject;
}

ProxyFactoryBean

private synchronized Object getSingletonInstance() {
	if (this.singletonInstance == null) {
		this.targetSource = freshTargetSource();
		if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {
			// Rely on AOP infrastructure to tell us what interfaces to proxy.
			Class<?> targetClass = getTargetClass();
			if (targetClass == null) {
				throw new FactoryBeanNotInitializedException("Cannot determine target class for proxy");
			}
			setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));
		}
		// Initialize the shared singleton instance.
		super.setFrozen(this.freezeProxy);
		this.singletonInstance = getProxy(createAopProxy());
	}
	return this.singletonInstance;
}
簡單工廠模式

Spring中的BeanFactory就是簡單工廠模式的體現,根據傳入一個唯一的標識來獲得Bean物件

@Override
public Object getBean(String name) throws BeansException {
	return doGetBean(name, null, null, false);
}
工廠方法(Factory Method)

定義一個用於建立物件的介面,讓子類決定例項化哪一個類。Factory Method使一個類的例項化延遲到其子類。

在這裡插入圖片描述

建造者模式

建造者模式(Builder Pattern)使用多個簡單的物件一步一步構建成一個複雜的物件。

建造者模式結構
在這裡插入圖片描述

public final class BeanDefinitionBuilder {
	public static BeanDefinitionBuilder genericBeanDefinition() {
		return new BeanDefinitionBuilder(new GenericBeanDefinition());
	}
	
	public static BeanDefinitionBuilder rootBeanDefinition(String beanClassName, @Nullable String factoryMethodName) {
		BeanDefinitionBuilder builder = new BeanDefinitionBuilder(new RootBeanDefinition());
		builder.beanDefinition.setBeanClassName(beanClassName);
		builder.beanDefinition.setFactoryMethodName(factoryMethodName);
		return builder;
	}
	
	public static BeanDefinitionBuilder childBeanDefinition(String parentName) {
		return new BeanDefinitionBuilder(new ChildBeanDefinition(parentName));
	}

	public BeanDefinitionBuilder setParentName(String parentName) {
		this.beanDefinition.setParentName(parentName);
		return this;
	}

	public BeanDefinitionBuilder setFactoryMethod(String factoryMethod) {
		this.beanDefinition.setFactoryMethodName(factoryMethod);
		return this;
	}

	public BeanDefinitionBuilder setFactoryMethodOnBean(String factoryMethod, String factoryBean) {
		this.beanDefinition.setFactoryMethodName(factoryMethod);
		this.beanDefinition.setFactoryBeanName(factoryBean);
		return this;
	}

	public BeanDefinitionBuilder addConstructorArgValue(@Nullable Object value) {
		this.beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(
				this.constructorArgIndex++, value);
		return this;
	}
	...
}
原型模式

原型模式(Prototype Pattern)是用於建立重複的物件,同時又能保證效能

private synchronized Object newPrototypeInstance() {
	// In the case of a prototype, we need to give the proxy
	// an independent instance of the configuration.
	// In this case, no proxy will have an instance of this object's configuration,
	// but will have an independent copy.
	ProxyCreatorSupport copy = new ProxyCreatorSupport(getAopProxyFactory());

	// The copy needs a fresh advisor chain, and a fresh TargetSource.
	TargetSource targetSource = freshTargetSource();
	copy.copyConfigurationFrom(this, targetSource, freshAdvisorChain());
	if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {
		// Rely on AOP infrastructure to tell us what interfaces to proxy.
		Class<?> targetClass = targetSource.getTargetClass();
		if (targetClass != null) {
			copy.setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));
		}
	}
	copy.setFrozen(this.freezeProxy);

	return getProxy(copy.createAopProxy());
}

結構型

介面卡模式

介面卡模式(Adapter Pattern)是作為兩個不相容的介面之間的橋樑。

物件介面卡
在這裡插入圖片描述

類介面卡

在這裡插入圖片描述

SpringMVC中的介面卡HandlerAdatper
實現原理:

HandlerAdatper根據Handler規則執行不同的Handler。

實現過程:

DispatcherServlet根據HandlerMapping返回的handler,向HandlerAdatper發起請求,處理Handler。
HandlerAdapter根據規則找到對應的Handler並讓其執行,執行完畢後Handler會向HandlerAdapter返回一個ModelAndView,最後由HandlerAdapter向DispatchServelet返回一個ModelAndView。

實現意義:

HandlerAdatper使得Handler的擴充套件變得容易,只需要增加一個新的Handler和一個對應的HandlerAdapter即可。
因此Spring定義了一個適配介面,使得每一種Controller有一種對應的介面卡實現類,讓介面卡代替controller執行相應的方法。這樣在擴充套件Controller時,只需要增加一個介面卡類就完成了SpringMVC的擴充套件了。

public class SimpleControllerHandlerAdapter implements HandlerAdapter {

	@Override
	@Nullable
	public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {

		return ((Controller) handler).handleRequest(request, response);
	}
}
代理模式

在代理模式(Proxy Pattern)中,一個類代表另一個類的功能

final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {

	private final AdvisedSupport advised;
	private final Class<?>[] proxiedInterfaces;
	private boolean equalsDefined;
	private boolean hashCodeDefined;

	@Override
	public Object getProxy(@Nullable ClassLoader classLoader) {
		if (logger.isTraceEnabled()) {
			logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
		}
		return Proxy.newProxyInstance(classLoader, this.proxiedInterfaces, this);
	}

	@Override
	@Nullable
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		Object oldProxy = null;
		boolean setProxyContext = false;

		TargetSource targetSource = this.advised.targetSource;
		Object target = null;

		try {
			if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
				// The target does not implement the equals(Object) method itself.
				return equals(args[0]);
			}
			else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
				// The target does not implement the hashCode() method itself.
				return hashCode();
			}
			else if (method.getDeclaringClass() == DecoratingProxy.class) {
				// There is only getDecoratedClass() declared -> dispatch to proxy config.
				return AopProxyUtils.ultimateTargetClass(this.advised);
			}
			else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
					method.getDeclaringClass().isAssignableFrom(Advised.class)) {
				// Service invocations on ProxyConfig with the proxy config...
				return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
			}

			Object retVal;

			if (this.advised.exposeProxy) {
				// Make invocation available if necessary.
				oldProxy = AopContext.setCurrentProxy(proxy);
				setProxyContext = true;
			}

			// Get as late as possible to minimize the time we "own" the target,
			// in case it comes from a pool.
			target = targetSource.getTarget();
			Class<?> targetClass = (target != null ? target.getClass() : null);

			// Get the interception chain for this method.
			List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

			// Check whether we have any advice. If we don't, we can fallback on direct
			// reflective invocation of the target, and avoid creating a MethodInvocation.
			if (chain.isEmpty()) {
				// We can skip creating a MethodInvocation: just invoke the target directly
				// Note that the final invoker must be an InvokerInterceptor so we know it does
				// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
				Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
				retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
			}
			else {
				// We need to create a method invocation...
				MethodInvocation invocation =
						new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
				// Proceed to the joinpoint through the interceptor chain.
				retVal = invocation.proceed();
			}

			// Massage return value if necessary.
			Class<?> returnType = method.getReturnType();
			if (retVal != null && retVal == target &&
					returnType != Object.class && returnType.isInstance(proxy) &&
					!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
				// Special case: it returned "this" and the return type of the method
				// is type-compatible. Note that we can't help if the target sets
				// a reference to itself in another returned object.
				retVal = proxy;
			}
			else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
				throw new AopInvocationException(
						"Null return value from advice does not match primitive return type for: " + method);
			}
			return retVal;
		}
		finally {
			if (target != null && !targetSource.isStatic()) {
				// Must have come from TargetSource.
				targetSource.releaseTarget(target);
			}
			if (setProxyContext) {
				// Restore old proxy.
				AopContext.setCurrentProxy(oldProxy);
			}
		}
	}
}
class CglibAopProxy implements AopProxy, Serializable {
	@Override
	public Object getProxy(@Nullable ClassLoader classLoader) {
		if (logger.isTraceEnabled()) {
			logger.trace("Creating CGLIB proxy: " + this.advised.getTargetSource());
		}

		try {
			Class<?> rootClass = this.advised.getTargetClass();
			Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");

			Class<?> proxySuperClass = rootClass;
			if (rootClass.getName().contains(ClassUtils.CGLIB_CLASS_SEPARATOR)) {
				proxySuperClass = rootClass.getSuperclass();
				Class<?>[] additionalInterfaces = rootClass.getInterfaces();
				for (Class<?> additionalInterface : additionalInterfaces) {
					this.advised.addInterface(additionalInterface);
				}
			}

			// Validate the class, writing log messages as necessary.
			validateClassIfNecessary(proxySuperClass, classLoader);

			// Configure CGLIB Enhancer...
			Enhancer enhancer = createEnhancer();
			if (classLoader != null) {
				enhancer.setClassLoader(classLoader);
				if (classLoader instanceof SmartClassLoader &&
						((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
					enhancer.setUseCache(false);
				}
			}
			enhancer.setSuperclass(proxySuperClass);
			enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
			enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
			enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(classLoader));

			Callback[] callbacks = getCallbacks(rootClass);
			Class<?>[] types = new Class<?>[callbacks.length];
			for (int x = 0; x < types.length; x++) {
				types[x] = callbacks[x].getClass();
			}
			// fixedInterceptorMap only populated at this point, after getCallbacks call above
			enhancer.setCallbackFilter(new ProxyCallbackFilter(
					this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
			enhancer.setCallbackTypes(types);

			// Generate the proxy class and create a proxy instance.
			return createProxyClassAndInstance(enhancer, callbacks);
		}
		catch (CodeGenerationException | IllegalArgumentException ex) {
			throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() +
					": Common causes of this problem include using a final class or a non-visible class",
					ex);
		}
		catch (Throwable ex) {
			// TargetSource.getTarget() failed
			throw new AopConfigException("Unexpected AOP exception", ex);
		}
	}

	protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {
		enhancer.setInterceptDuringConstruction(false);
		enhancer.setCallbacks(callbacks);
		return (this.constructorArgs != null && this.constructorArgTypes != null ?
				enhancer.create(this.constructorArgTypes, this.constructorArgs) :
				enhancer.create());
	}
}
裝飾器模式

裝飾器模式(Decorator Pattern)允許向一個現有的物件新增新的功能,同時又不改變其結構

在這裡插入圖片描述

HttpRequestWrapper不改變HttpRequest結構,但可以在此類中新增新功能

public class HttpRequestWrapper implements HttpRequest {

	private final HttpRequest request;

	public HttpRequestWrapper(HttpRequest request) {
		Assert.notNull(request, "HttpRequest must not be null");
		this.request = request;
	}

	public HttpRequest getRequest() {
		return this.request;
	}

	@Override
	@Nullable
	public HttpMethod getMethod() {
		return this.request.getMethod();
	}

	@Override
	public String getMethodValue() {
		return this.request.getMethodValue();
	}

	@Override
	public URI getURI() {
		return this.request.getURI();
	}

	@Override
	public HttpHeaders getHeaders() {
		return this.request.getHeaders();
	}

}

ServerHttpRequestDecorator不改變ServerHttpRequest結構,但可以在此類中新增新功能

public class ServerHttpRequestDecorator implements ServerHttpRequest {

	private final ServerHttpRequest delegate;


	public ServerHttpRequestDecorator(ServerHttpRequest delegate) {
		Assert.notNull(delegate, "Delegate is required");
		this.delegate = delegate;
	}


	public ServerHttpRequest getDelegate() {
		return this.delegate;
	}


	// ServerHttpRequest delegation methods...

	@Override
	public String getId() {
		return getDelegate().getId();
	}

	@Override
	@Nullable
	public HttpMethod getMethod() {
		return getDelegate().getMethod();
	}

	@Override
	public String getMethodValue() {
		return getDelegate().getMethodValue();
	}

	@Override
	public URI getURI() {
		return getDelegate().getURI();
	}

	@Override
	public RequestPath getPath() {
		return getDelegate().getPath();
	}
}

行為型模式

觀察者模式

建立一種物件與物件之間的依賴關係,一個物件發生改變時將自動通知其他物件,其他物件將相應做出反應。在此,發生改變的物件稱為觀察目標,而被通知的物件稱為觀察者

Spring中Observer模式常用的地方是listener的實現。如ApplicationListener

public class SpringApplication {
    public ConfigurableApplicationContext run(String... args) {
        SpringApplicationRunListeners listeners = this.getRunListeners(args);
        // 啟動事件
        listeners.starting(bootstrapContext, this.mainApplicationClass);
    }
}
策略模式

策略模式(Strategy Pattern):定義一系列演算法,將每一個演算法封裝起來,並讓它們可以相互替換。策略模式讓演算法獨立於使用它的客戶而變化,也稱為政策模式(Policy)

Resource 介面本身沒有提供訪問任何底層資源的實現邏輯,針對不同的底層資源,Spring 將會提供不同的 Resource 實現類,不同的實現類負責不同的資源訪問邏輯。

這些 Resource 實現類,針對不同的的底層資源,提供了相應的資源訪問邏輯,並提供便捷的包裝,以利於客戶端程式的資源訪問。

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;
	String getFilename();
	String getDescription();

}

在這裡插入圖片描述

模板方法模式(Template Method)

定義一個操作中的演算法的骨架,而將一些步驟延遲到子類中。模板方法使得子類可以不改變一個演算法的結構即可重定義該演算法的某些特定步驟。

Spring幾乎所有的外接擴充套件都採用這種模式。如JdbcTemplate、kafkaTemplate、RabbitmqTemplate

定義一個操作中的演算法的骨架,而將一些步驟延遲到子類中。Template Method使得子類可以不改變一個演算法的結構即可重定義該演算法的某些特定步驟。

Template Method模式一般是需要繼承的。這裡想要探討另一種對Template Method的理解。Spring中的JdbcTemplate,在用這個類時並不想去繼承這個類,因為這個類的方法太多,但是我們還是想用到JdbcTemplate已有的穩定的、公用的資料庫連線,那麼我們怎麼辦呢?我們可以把變化的東西抽出來作為一個引數傳入JdbcTemplate的方法中。但是變化的東西是一段程式碼,而且這段程式碼會用到JdbcTemplate中的變數。怎麼辦?那我們就用回撥物件吧。在這個回撥物件中定義一個操縱JdbcTemplate中變數的方法,我們去實現這個方法,就把變化的東西集中到這裡了。然後我們再傳入這個回撥物件到JdbcTemplate,從而完成了呼叫。這可能是Template Method不需要繼承的另一種實現方式吧

public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
	public <T> T execute(ConnectionCallback<T> action) throws DataAccessException {
		Assert.notNull(action, "Callback object must not be null");

		Connection con = DataSourceUtils.getConnection(obtainDataSource());
		try {
			// Create close-suppressing Connection proxy, also preparing returned Statements.
			Connection conToUse = createConnectionProxy(con);
			return action.doInConnection(conToUse);
		}
		catch (SQLException ex) {
			// Release Connection early, to avoid potential connection pool deadlock
			// in the case when the exception translator hasn't been initialized yet.
			String sql = getSql(action);
			DataSourceUtils.releaseConnection(con, getDataSource());
			con = null;
			throw translateException("ConnectionCallback", sql, ex);
		}
		finally {
			DataSourceUtils.releaseConnection(con, getDataSource());
		}
	}
}
直譯器模式
public class SpelExpressionParser extends TemplateAwareExpressionParser {
    private final SpelParserConfiguration configuration;

    public SpelExpressionParser() {
        this.configuration = new SpelParserConfiguration();
    }

    public SpelExpressionParser(SpelParserConfiguration configuration) {
        Assert.notNull(configuration, "SpelParserConfiguration must not be null");
        this.configuration = configuration;
    }

    public SpelExpression parseRaw(String expressionString) throws ParseException {
        return this.doParseExpression(expressionString, (ParserContext)null);
    }

    protected SpelExpression doParseExpression(String expressionString, @Nullable ParserContext context) throws ParseException {
        return (new InternalSpelExpressionParser(this.configuration)).doParseExpression(expressionString, context);
    }
}
職責鏈模式
public class DefaultWebFilterChain implements WebFilterChain {

	private final List<WebFilter> allFilters;

	private final WebHandler handler;

	@Nullable
	private final WebFilter currentFilter;

	@Nullable
	private final DefaultWebFilterChain chain;

	public DefaultWebFilterChain(WebHandler handler, List<WebFilter> filters) {
		Assert.notNull(handler, "WebHandler is required");
		this.allFilters = Collections.unmodifiableList(filters);
		this.handler = handler;
		DefaultWebFilterChain chain = initChain(filters, handler);
		this.currentFilter = chain.currentFilter;
		this.chain = chain.chain;
	}

	private static DefaultWebFilterChain initChain(List<WebFilter> filters, WebHandler handler) {
		DefaultWebFilterChain chain = new DefaultWebFilterChain(filters, handler, null, null);
		ListIterator<? extends WebFilter> iterator = filters.listIterator(filters.size());
		while (iterator.hasPrevious()) {
			chain = new DefaultWebFilterChain(filters, handler, iterator.previous(), chain);
		}
		return chain;
	}

	private DefaultWebFilterChain(List<WebFilter> allFilters, WebHandler handler,
			@Nullable WebFilter currentFilter, @Nullable DefaultWebFilterChain chain) {

		this.allFilters = allFilters;
		this.currentFilter = currentFilter;
		this.handler = handler;
		this.chain = chain;
	}

	public List<WebFilter> getFilters() {
		return this.allFilters;
	}

	public WebHandler getHandler() {
		return this.handler;
	}


	@Override
	public Mono<Void> filter(ServerWebExchange exchange) {
		return Mono.defer(() ->
				this.currentFilter != null && this.chain != null ?
						invokeFilter(this.currentFilter, this.chain, exchange) :
						this.handler.handle(exchange));
	}

	private Mono<Void> invokeFilter(WebFilter current, DefaultWebFilterChain chain, ServerWebExchange exchange) {
		String currentName = current.getClass().getName();
		return current.filter(exchange, chain).checkpoint(currentName + " [DefaultWebFilterChain]");
	}

}

https://mp.weixin.qq.com/s/gz2-izPrgW1AGbqqovT0cA
https://design-patterns.readthedocs.io/zh_CN/latest/structural_patterns/adapter.html
https://mp.weixin.qq.com/s/3AWW1OX5KwMDX4CM4c39kg
https://mp.weixin.qq.com/s/YarbOYMN5orskbgYiTQ-lA
https://www.cnblogs.com/yuefan/p/3763898.html
https://www.jianshu.com/p/09432974d7b9

相關文章