淺談Spring設計模式
工廠模式
BeanFactory,從xml或者註解載入BeanDefinition,然後例項化物件,其中AbstractAutowiredCapableBeanFactory實現了主要的邏輯
單例模式
spring建立的bean預設為singleton
介面卡模式
比如說Springmvc的HandlerInterceptorAdapter就是個介面介面卡,實現了AsyncHandlerInterceptor(HandlerInterceptor的子類),ThemeChangeInterceptor繼承至HandlerInterceptorAdapter,只需要重寫關注的方法即可,不相關的方法完全可以忽略。
public abstract class HandlerInterceptorAdapter implements AsyncHandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return true;
}
@Override
public void postHandle (
HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
throws Exception {
}
@Override
public void afterCompletion(
HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
}
@Override
public void afterConcurrentHandlingStarted(
HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
}
}
public class ThemeChangeInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws ServletException {
// do somethings
}
}
個人認為用得最好的地方莫過於spring-jms的MessagingMessageListenerAdapter,在onMessage中將jsm的Message轉換為message模組的Message物件(內部類的LazyResolutionMessage,重寫了getPayload、getHeader),並交給message模組的InvocableHandleMethod,這樣一來便可以實現jms與spring message無縫適配對接了,在spring-websocket也是相同的套路
public class MessagingMessageListenerAdapter extends AbstractAdaptableMessageListener {
private InvocableHandlerMethod handlerMethod;
public void setHandlerMethod(InvocableHandlerMethod handlerMethod) {
this.handlerMethod = handlerMethod;
}
@Override
public void onMessage(javax.jms.Message jmsMessage, Session session) throws JMSException {
Message<?> message = toMessagingMessage(jmsMessage);
if (logger.isDebugEnabled()) {
logger.debug("Processing [" + message + "]");
}
Object result = invokeHandler(jmsMessage, session, message);
if (result != null) {
handleResult(result, jmsMessage, session);
}
else {
logger.trace("No result object given - no result to handle");
}
}
protected Message<?> toMessagingMessage(javax.jms.Message jmsMessage) {
try {
return (Message<?>) getMessagingMessageConverter().fromMessage(jmsMessage);
}
catch (JMSException ex) {
throw new MessageConversionException("Could not convert JMS message", ex);
}
}
// 忽略部分程式碼
}
裝飾模式
裝飾模式是指在不影響其它類的情況下,動態透明的擴充套件一個物件的功能,比如TransactionAwareCacheDecorator增加了對事務的支援,在事務提交、回滾的時候分別對Cache的資料進行處理。不過,裝飾模式和靜態代理還是有區別的,裝飾模式只是在呼叫前後加了些邏輯,但是最終還是需要呼叫父類或者裝飾類;而代理模式是需要or不需要來完成對代理方法的呼叫,比如AOP可以有選擇性地處理某些方法,並不一定會執行代理類的具體方法。
public class TransactionAwareCacheDecorator implements Cache {
private final Cache targetCache;
@Override
public void put(final Object key, final Object value) {
if (TransactionSynchronizationManager.isSynchronizationActive()) {
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
@Override
public void afterCommit() {
targetCache.put(key, value);
}
});
}
else {
this.targetCache.put(key, value);
}
}
// 忽略部分程式碼
}
觀察者模式
在spring中我們藉助ApplicationListener、ApplicationEventPublisher便可以完成簡直的事件通知。當呼叫ApplicationEventPublisher#publishEvent()時,spring會查詢實現了ApplicationListener介面、並且使用了指定泛型的bean,然後呼叫其onApplicationEvent。下面的程式碼示範了spring發出ContextRefreshedEvent事件。
ApplicationEventPublisher eventPublisher = xxx;
eventPublisher.publishEvent( new ContextRefreshedEvent( applicationContext ) );
public class TestListener implements ApplicationListener<ContextRefreshedEvent> {
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
// invoke after spring context refreshed
}
}
策略模式
比如SpringMVC的HandlerMethodArgumentResolver介面,使用HandlerMethodArgumentResolverComposite(實現HandlerMethodArgumentResolver介面),通過遍歷內部所有的HandlerMethodArgumentResolver(當然有快取 機制),選擇support返回true的例項,並把介面的呼叫交給該例項處理
其實,我們在寫業務程式碼的時候,很多童鞋喜歡用Map儲存策略實現類,其實這樣並不好,不夠靈活,應該像spring這樣提供一個support方法,可以支援更加複雜的邏輯判斷
public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgumentResolver {
protected final Log logger = LogFactory.getLog(getClass());
private final List<HandlerMethodArgumentResolver> argumentResolvers =
new LinkedList<HandlerMethodArgumentResolver>();
private final Map<MethodParameter, HandlerMethodArgumentResolver> argumentResolverCache =
new ConcurrentHashMap<MethodParameter, HandlerMethodArgumentResolver>(256);
@Override
public boolean supportsParameter(MethodParameter parameter) {
return (getArgumentResolver(parameter) != null);
}
private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
if (result == null) {
for (HandlerMethodArgumentResolver methodArgumentResolver : this.argumentResolvers) {
if (methodArgumentResolver.supportsParameter(parameter)) {
result = methodArgumentResolver;
this.argumentResolverCache.put(parameter, result);
break;
}
}
}
return result;
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);
if (resolver == null) {
throw new IllegalArgumentException("Unknown parameter type [" + parameter.getParameterType().getName() + "]");
}
return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
}
}
代理模式
靜態代理在Spring websocket裡面非常常見,比如說WebsocketHandlerDecorator,因為它不方便直接操作開發者自定義的WebSocketHandler,因此使用了代理模式。另外,cglib、jdk動態代理在spring中也是非常常見
public class WebSocketHandlerDecorator implements WebSocketHandler {
private final WebSocketHandler delegate;
public WebSocketHandlerDecorator(WebSocketHandler delegate) {
Assert.notNull(delegate, "Delegate must not be null");
this.delegate = delegate;
}
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
this.delegate.afterConnectionEstablished(session);
}
@Override
public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
this.delegate.handleMessage(session, message);
}
// 省略部分程式碼
}
責任鏈模式
比如SpringMVC的HandlerExecutionChain與HandlerInterceptor,以及ExceptionHandlerResolver
下面是HandlerExecutionChain的部分程式碼,由DispatcherServlet呼叫,內部維護了interceptorIndex,用於標記當前呼叫HandlerInterceptor的位置
public class HandlerExecutionChain {
private final Object handler;
private HandlerInterceptor[] interceptors;
private int interceptorIndex = -1;
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = 0; i < interceptors.length; i++) {
HandlerInterceptor interceptor = interceptors[i];
if (!interceptor.preHandle(request, response, this.handler)) {
triggerAfterCompletion(request, response, null);
return false;
}
this.interceptorIndex = i;
}
}
return true;
}
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = interceptors.length - 1; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
interceptor.postHandle(request, response, this.handler, mv);
}
}
}
}
再比如說springMVC對異常的處理,DispatcherServlet會儲存所有的HandlerExceptionResolver,當出現異常時,挨個呼叫HandlerExceptionResolver例項的resolveException方法,直到返回ModelAndView
建設者模式(Builder)
為了簡化物件的建立過程而使用的一種設計模式,比如BeanDefinitionBuilder是為了簡化BeanDefinition的建立過程,每次setXXX都會返回BeanDefinitionBuilder例項,方便以鏈條編碼的方式建立BeanDefinitionBuilder
public class BeanDefinitionBuilder {
public static BeanDefinitionBuilder genericBeanDefinition(Class<?> beanClass) {
BeanDefinitionBuilder builder = new BeanDefinitionBuilder();
builder.beanDefinition = new GenericBeanDefinition();
builder.beanDefinition.setBeanClass(beanClass);
return builder;
}
private AbstractBeanDefinition beanDefinition;
public BeanDefinitionBuilder addConstructorArgValue(Object value) {
this.beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(
this.constructorArgIndex++, value);
return this;
}
public BeanDefinitionBuilder addPropertyValue(String name, Object value) {
this.beanDefinition.getPropertyValues().add(name, value);
return this;
}
}
模板模式
spring中很多地方會這樣做,在一個方法裡面完成了一小部分邏輯,然後接著呼叫一個或多個抽象方法,而這個抽象方法需要由子類重寫,比如AbstractApplicationContext裡面的refresh()、getBeanFactory()等等,這樣便可以很好的提高了程式的擴充套件性