1. 装饰器模式 模式的本质是在不改变原有对象的基础上对原有的基础上进行方法或属性的增强。
例如 实现 使用装饰器模式实现 remove List 元素的记录 , HistorySet中只加了remove方法的处理逻辑,其他的方法没有动,使用的依然是Set原来的方法。体现出装饰器模式对原有对象增强的作用。
java
import java.util.*;
/// 装饰器模式
public class HistorySet<E> implements Set<E> {
private List<E> removeList = new ArrayList<E>();
// 代理对象
private final Set<E> delegate ;
// 代理对象
public HistorySet(Set<E> sets) {
this.delegate = sets;
}
@Override
public int size() {
return 0;
}
@Override
public boolean isEmpty() {
return false;
}
@Override
public boolean contains(Object o) {
return false;
}
@Override
public Iterator<E> iterator() {
return null;
}
@Override
public Object[] toArray() {
return new Object[0];
}
@Override
public <T> T[] toArray(T[] a) {
return null;
}
@Override
public boolean add(E e) {
return delegate.add(e);
}
@Override
public boolean remove(Object o) {
Boolean remove = delegate.remove(o);
if(remove){
removeList.add( (E)o );
return true;
}
return false;
}
@Override
public boolean containsAll(Collection<?> c) {
return false;
}
@Override
public boolean addAll(Collection<? extends E> c) {
return false;
}
@Override
public boolean retainAll(Collection<?> c) {
return false;
}
@Override
public boolean removeAll(Collection<?> c) {
return false;
}
@Override
public void clear() {
}
@Override
public String toString() {
return "HistorySet{" +
"removeList=" + removeList +
", sets=" + delegate +
'}';
}
}
- 示例代码
例如 实现 使用装饰器模式实现 remove List 元素的记录 , HistorySet中只加了remove方法的处理逻辑,其他的方法没有动,使用的依然是Set原来的方法。体现出装饰器模式对原有对象增强的作用。
java
import java.lang.reflect.Array;
import java.util.*;
public class Main {
public static void main(String[] args) {
Set<String> historySet = new HistorySet<>(new HashSet<>());
// 记录 remove 的 元素的方法
Set<String> set = new HistorySet<>(historySet);
set.add("a");
set.add("b");
set.add("c");
set.add("d");
set.remove("a");
set.remove("b");
set.remove("c");
System.out.println(set);
}
}
代码运行结果:
HistorySet{removeList=[a, b, c], sets=HistorySet{removeList=[a, b, c], sets=[d]}}
2. JDK中的实现 装饰器模式
java
// 将普通的list 包装成 线程安全的 List
Collection<Object> synchronizedList = Collections.synchronizedCollection(new ArrayList<>());
可以看到其底层是对代码的实现进行线程安全的增强(Synchronized 锁的增强),并没有改变原有的集合的方法实现。
java
SynchronizedCollection(Collection<E> c, Object mutex) {
this.c = Objects.requireNonNull(c);
this.mutex = Objects.requireNonNull(mutex);
}
public int size() {
synchronized (mutex) {return c.size();}
}
public boolean isEmpty() {
synchronized (mutex) {return c.isEmpty();}
}
public boolean contains(Object o) {
synchronized (mutex) {return c.contains(o);}
}
public Object[] toArray() {
synchronized (mutex) {return c.toArray();}
}
public <T> T[] toArray(T[] a) {
synchronized (mutex) {return c.toArray(a);}
}
public <T> T[] toArray(IntFunction<T[]> f) {
synchronized (mutex) {return c.toArray(f);}
}
public Iterator<E> iterator() {
return c.iterator(); // Must be manually synched by user!
}
public boolean add(E e) {
synchronized (mutex) {return c.add(e);}
}
public boolean remove(Object o) {
synchronized (mutex) {return c.remove(o);}
}
public boolean containsAll(Collection<?> coll) {
synchronized (mutex) {return c.containsAll(coll);}
}
public boolean addAll(Collection<? extends E> coll) {
synchronized (mutex) {return c.addAll(coll);}
}
public boolean removeAll(Collection<?> coll) {
synchronized (mutex) {return c.removeAll(coll);}
}
public boolean retainAll(Collection<?> coll) {
synchronized (mutex) {return c.retainAll(coll);}
}
public void clear() {
synchronized (mutex) {c.clear();}
}
public String toString() {
synchronized (mutex) {return c.toString();}
}
// Override default methods in Collection
@Override
public void forEach(Consumer<? super E> consumer) {
synchronized (mutex) {c.forEach(consumer);}
}
@Override
public boolean removeIf(Predicate<? super E> filter) {
synchronized (mutex) {return c.removeIf(filter);}
}
@Override
public Spliterator<E> spliterator() {
return c.spliterator(); // Must be manually synched by user!
}
@Override
public Stream<E> stream() {
return c.stream(); // Must be manually synched by user!
}
@Override
public Stream<E> parallelStream() {
return c.parallelStream(); // Must be manually synched by user!
}
@java.io.Serial
private void writeObject(ObjectOutputStream s) throws IOException {
synchronized (mutex) {s.defaultWriteObject();}
}
}
/**
* Returns a synchronized (thread-safe) set backed by the specified
* set. In order to guarantee serial access, it is critical that
* <strong>all</strong> access to the backing set is accomplished
* through the returned set.<p>
*
* It is imperative that the user manually synchronize on the returned
* collection when traversing it via {@link Iterator}, {@link Spliterator}
* or {@link Stream}:
* <pre>
* Set s = Collections.synchronizedSet(new HashSet());
* ...
* synchronized (s) {
* Iterator i = s.iterator(); // Must be in the synchronized block
* while (i.hasNext())
* foo(i.next());
* }
* </pre>
* Failure to follow this advice may result in non-deterministic behavior.
*
* <p>The returned set will be serializable if the specified set is
* serializable.
*
* @param <T> the class of the objects in the set
* @param s the set to be "wrapped" in a synchronized set.
* @return a synchronized view of the specified set.
*/
public static <T> Set<T> synchronizedSet(Set<T> s) {
return new SynchronizedSet<>(s);
}
static <T> Set<T> synchronizedSet(Set<T> s, Object mutex) {
return new SynchronizedSet<>(s, mutex);
}
/**
* @serial include
*/
static class SynchronizedSet<E>
extends SynchronizedCollection<E>
implements Set<E> {
@java.io.Serial
private static final long serialVersionUID = 487447009682186044L;
SynchronizedSet(Set<E> s) {
super(s);
}
SynchronizedSet(Set<E> s, Object mutex) {
super(s, mutex);
}
public boolean equals(Object o) {
if (this == o)
return true;
synchronized (mutex) {return c.equals(o);}
}
BufferReader 封装的Read 等方法,实现 文件从缓存区里面读取。
java
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* 从缓冲区中读取数据
*/
public class BufferedFileInputStream extends InputStream {
private final byte[] buffer = new byte[8192];
private final FileInputStream fileInputStream;
private int position = -1;
private int capacity = -1;
public BufferedFileInputStream(FileInputStream fileInputStream) {
this.fileInputStream = fileInputStream;
}
@Override
public int read() throws IOException {
if ( bufferCanRead() ) {
return readFromBuffer() ;
}
refreshBuffer();
if(!bufferCanRead()){
return -1;
}
return readFromBuffer() ;
}
private int readFromBuffer() {
// 去掉符号位
return buffer[position++] & 0xFF ;
}
private void refreshBuffer() throws IOException {
// 读取 的大小
capacity = this.fileInputStream.read(buffer);
position = 0;
// 置位读取
}
private boolean bufferCanRead() {
if(capacity == -1||position == capacity){
return false;
}
// position在 capacity 前
return true;
}
@Override
public void close() throws IOException {
super.close();
}
}
3. SpringBoot 中装饰器模式的使用 和 封装
首先会进入到 InvocableHandlerMethod 方法中 其中的 resolvers 是进行真正的参数解析逻辑,
java
public class InvocableHandlerMethod extends HandlerMethod {
private static final Object[] EMPTY_ARGS = new Object[0];
private static final Class<?>[] EMPTY_GROUPS = new Class<?>[0];
private HandlerMethodArgumentResolverComposite resolvers = new HandlerMethodArgumentResolverComposite();
private ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();
@Nullable
private WebDataBinderFactory dataBinderFactory;
@Nullable
private MethodValidator methodValidator;
private Class<?>[] validationGroups = EMPTY_GROUPS;
这个Composite 是一个经典的组合模式,里面有一个HandlerMethodArgumentResolver 的List ,通过这个list找到真正的解析方法,对参数进行解析。
java
/*
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.method.support;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.core.MethodParameter;
import org.springframework.lang.Nullable;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
/**
* Resolves method parameters by delegating to a list of registered
* {@link HandlerMethodArgumentResolver HandlerMethodArgumentResolvers}.
* Previously resolved method parameters are cached for faster lookups.
*
* @author Rossen Stoyanchev
* @author Juergen Hoeller
* @since 3.1
*/
public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgumentResolver {
private final List<HandlerMethodArgumentResolver> argumentResolvers = new ArrayList<>();
private final Map<MethodParameter, HandlerMethodArgumentResolver> argumentResolverCache =
new ConcurrentHashMap<>(256);
/**
* Add the given {@link HandlerMethodArgumentResolver}.
*/
public HandlerMethodArgumentResolverComposite addResolver(HandlerMethodArgumentResolver resolver) {
this.argumentResolvers.add(resolver);
return this;
}
/**
* Add the given {@link HandlerMethodArgumentResolver HandlerMethodArgumentResolvers}.
* @since 4.3
*/
public HandlerMethodArgumentResolverComposite addResolvers(
@Nullable HandlerMethodArgumentResolver... resolvers) {
if (resolvers != null) {
Collections.addAll(this.argumentResolvers, resolvers);
}
return this;
}
/**
* Add the given {@link HandlerMethodArgumentResolver HandlerMethodArgumentResolvers}.
*/
public HandlerMethodArgumentResolverComposite addResolvers(
@Nullable List<? extends HandlerMethodArgumentResolver> resolvers) {
if (resolvers != null) {
this.argumentResolvers.addAll(resolvers);
}
return this;
}
/**
* Return a read-only list with the contained resolvers, or an empty list.
*/
public List<HandlerMethodArgumentResolver> getResolvers() {
return Collections.unmodifiableList(this.argumentResolvers);
}
/**
* Clear the list of configured resolvers and the resolver cache.
* @since 4.3
*/
public void clear() {
this.argumentResolvers.clear();
this.argumentResolverCache.clear();
}
/**
* Whether the given {@linkplain MethodParameter method parameter} is
* supported by any registered {@link HandlerMethodArgumentResolver}.
*/
@Override
public boolean supportsParameter(MethodParameter parameter) {
return getArgumentResolver(parameter) != null;
}
/**
* Iterate over registered
* {@link HandlerMethodArgumentResolver HandlerMethodArgumentResolvers}
* and invoke the one that supports it.
* @throws IllegalArgumentException if no suitable argument resolver is found
*/
@Override
@Nullable
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);
if (resolver == null) {
throw new IllegalArgumentException("Unsupported parameter type [" +
parameter.getParameterType().getName() + "]. supportsParameter should be called first.");
}
return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
}
/**
* Find a registered {@link HandlerMethodArgumentResolver} that supports
* the given method parameter.
*/
@Nullable
public HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
if (result == null) {
for (HandlerMethodArgumentResolver resolver : this.argumentResolvers) {
if (resolver.supportsParameter(parameter)) {
result = resolver;
this.argumentResolverCache.put(parameter, result);
break;
}
}
}
return result;
}
}
实现真正意义上的参数的map形成。
java
public HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
if (result == null) {
for (HandlerMethodArgumentResolver resolver : this.argumentResolvers) {
if (resolver.supportsParameter(parameter)) {
result = resolver;
this.argumentResolverCache.put(parameter, result);
break;
}
}
}
return result;
}
而在 RequestResponseBodyMethodProcessor 这个类 (这个类继承了上面的ArugmentRsolver ) 中 必然会有相应的两个方法,以下下就是
java
public boolean supportsReturnType(MethodParameter returnType) {
return AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) || returnType.hasMethodAnnotation(ResponseBody.class);
}
@Nullable
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
parameter = parameter.nestedIfOptional();
Object arg = this.readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType());
if (binderFactory != null) {
String name = Conventions.getVariableNameForParameter(parameter);
ResolvableType type = ResolvableType.forMethodParameter(parameter);
WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name, type);
if (arg != null) {
this.validateIfApplicable(binder, parameter);
if (binder.getBindingResult().hasErrors() && this.isBindExceptionRequired(binder, parameter)) {
throw new MethodArgumentNotValidException(parameter, binder.getBindingResult());
}
}
if (mavContainer != null) {
mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult());
}
}
return this.adaptArgumentIfNecessary(arg, parameter);
}
因此我们实现继承 HanlderMethodArgumentResolver类 ,实现这两个方法
java
public class TimestmpRequestBodyMethodProcesor implements HandlerMethodArgumentResolver {
private RequestResponseBodyMethodProcessor processor;
private ApplicationContext applicationContext;
public TimestmpRequestBodyMethodProcesor(ApplicationContext applicationContext ) {
this.applicationContext = applicationContext;
}
public TimestmpRequestBodyMethodProcesor(RequestResponseBodyMethodProcessor processor) {
this.processor = processor;
}
// 装饰器
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasParameterAnnotation(TimestampRequestBody.class);
}
//
@Override
public Object resolveArgument(MethodParameter parameter,
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest,
WebDataBinderFactory binderFactory) throws Exception {
setupProcessor();
Object result = processor.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
if( !(result instanceof Map<?,?>) ) {
return result;
}
// 装饰器的本质
((Map) result).put("timestamp", System.currentTimeMillis());
return result;
}
private void setupProcessor() {
if(this.processor != null) {
return;
}
RequestMappingHandlerAdapter adapter = this.applicationContext.getBean(RequestMappingHandlerAdapter.class);
List<HandlerMethodArgumentResolver> argumentResolvers = adapter.getArgumentResolvers();
for (HandlerMethodArgumentResolver argumentResolver : argumentResolvers) {
if(argumentResolver instanceof RequestResponseBodyMethodProcessor) {
this.processor = (RequestResponseBodyMethodProcessor) argumentResolver;
return;
}
}
}
}
实现自定义注解
java
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TimestampRequestBody {
}