Spring涉及的设计模式很多,不下于十几种,我们就总结性的罗列一下,限于篇幅,不可能对每种设计模式都详细的讲解,只能说一些简单的概述

适配器模式在Spring中应用

在SpringMVC中,对于定义Controller,可以有多种实现方式

1,通过@Controller来标记某个类是Controller类,并且通过@RequestMapping注解来标记函数对应的URL,进行实现

2.实现Controller接口或者Servlet接口,来定义一个Controller

常见的方法如下:

// 方法一:通过@Controller、@RequestMapping来定义

@Controller

public class DemoController {

@RequestMapping(“/employname”)

public ModelAndView getEmployeeName() {

ModelAndView model = new ModelAndView(“Greeting”);

model.addObject(“message”, “Dinesh”);

return model;

}

}

// 方法二:实现Controller接口 + xml配置文件:配置DemoController与URL的对应关系

public class DemoController implements Controller {

@Override

public ModelAndView handleRequest(HttpServletRequest req, HttpServletResponse resp) throws Exception {

ModelAndView model = new ModelAndView(“Greeting”);

model.addObject(“message”, “Dinesh Madhwal”);

return model;

}

}

// 方法三:实现Servlet接口 + xml配置文件:配置DemoController类与URL的对应关系

public class DemoServlet extends HttpServlet {

@Override

protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

this.doPost(req, resp);

}

@Override

protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

resp.getWriter().write(“Hello World.”);

}

}

在应用启动的时候,Spring加载这些Controller,并且解析出URL对应的处理函数,封装成Handler对象,存储到HandlerMapping对象中,当有请求到来的时候,DispatcherServlet会从HanderMapping中,查找请求的URL对应的Handler,然后调用执行Handler对应的函数代码,将执行结果返回给客户端

但是,不同方式定义的Controller,其函数的定义是不统一的,如上面示例代码,不同的类中,定义的函数不一致,Controller注解中的函数千奇百怪,使用Controller接口,定义的是handleRequest,最后函数定义的是service(),DispatcherServlet需要调用不同的类型的Controller,调用不同的函数

Handler handler = handlerMapping.get(URL);

if (handler instanceof Controller) {

((Controller)handler).handleRequest(…);

} else if (handler instanceof Servlet) {

((Servlet)handler).service(…);

} else if (hanlder 对应通过注解来定义的Controller) {

反射调用方法…

}

上面可以看出,我们实现中存在着多种if-else分支判断,

于是我们可以使用适配器模式对代码进行改造,让其满足开闭原则,更好的支持扩展,适配器的一个作用就是统一多个类的接口设计,将不同方式定义在Controller类中的函数,适配为同一个函数定义,这样我们就能在DispatcherServlet类代码中,移除了if-else判断,

我们统一定义了接口 HandlerAdapter,并且对每种Controller定义了对应的适配器类

public interface HandlerAdapter {

boolean supports(Object var1);

ModelAndView handle(HttpServletRequest var1, HttpServletResponse var2, Object var3) throws Exception;

long getLastModified(HttpServletRequest var1, Object var2);

}

// 对应实现Controller接口的Controller

public class SimpleControllerHandlerAdapter implements HandlerAdapter {

public SimpleControllerHandlerAdapter() {

}

public boolean supports(Object handler) {

return handler instanceof Controller;

}

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

return ((Controller)handler).handleRequest(request, response);

}

public long getLastModified(HttpServletRequest request, Object handler) {

return handler instanceof LastModified ? ((LastModified)handler).getLastModified(request) : -1L;

}

}

// 对应实现Servlet接口的Controller

public class SimpleServletHandlerAdapter implements HandlerAdapter {

public SimpleServletHandlerAdapter() {

}

public boolean supports(Object handler) {

return handler instanceof Servlet;

}

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

((Servlet)handler).service(request, response);

return null;

}

public long getLastModified(HttpServletRequest request, Object handler) {

return -1L;

}

}

//AnnotationMethodHandlerAdapter对应通过注解实现的Controller,

//代码太多了,我就不贴在这里了

在DispathcerServlet中,我们不需要区分对待不同的Controller对象了,统一调用HandlerAdapter的handle()函数就可以了,按照这个思路实现的代码,就不需要if-else了

策略模式在Spring汇总的应用

SpringAOP是通过动态代理实现,Spring提供了两种动态代理的实现方式,一种是JDK提供的动态代理实现方法,一种是Cglib提供的动态代理实现方式

前者需要被代理的类有抽象的接口定义,后者不需要,针对不同的被代理类,Spring会动态选择不同的代理实现方式,这个应用场景就是策略模式的典型应用场景

策略模式分为三个部分,策略定义,创建和使用,我们看一下,这三个部分如何体现在Spring源码红的

策略模式汇总,策略定义很简单,定义一个策略接口,让不同的策略实现一个接口,对应到Spring源码,JdkDynamicAopProxy,CglibAopProxy是两个实现AopProxy接口的策略类,AopProxy接口的定义如下

public interface AopProxy {

Object getProxy();

Object getProxy(ClassLoader var1);

}

策略模式,策略创建一般通过工厂模式实现,对应到Spring中,AopProxyFactroy是一个工厂类接口,DefaultAopProxyFactory是一个默认的工厂类,用来创建AopProxy对象

public interface AopProxyFactory {

AopProxy createAopProxy(AdvisedSupport var1) throws AopConfigException;

}

public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {

public DefaultAopProxyFactory() {

}

public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {

if (!config.isOptimize() && !config.isProxyTargetClass() && !this.hasNoUserSuppliedProxyInterfaces(config)) {

return new JdkDynamicAopProxy(config);

} else {

Class<?> targetClass = config.getTargetClass();

if (targetClass == null) {

throw new AopConfigException(“TargetSource cannot determine target class: Either an interface or a target is required for proxy creation.”);

} else {

return (AopProxy)(!targetClass.isInterface() && !Proxy.isProxyClass(targetClass) ? new ObjenesisCglibAopProxy(config) : new JdkDynamicAopProxy(config));

}

}

}

//用来判断用哪个动态代理实现方式

private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {

Class<?>[] ifcs = config.getProxiedInterfaces();

return ifcs.length == 0 || ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0]);

}

}

通过环境变量,状态值,算出使用哪一个策略,对应到Spring源码中,可以看到给出的DefaultAopProxtFactory类中的createAopProxt()函数的代码实现

组合模式在Spring中的应用组合

组合模式就好比一个树,包含叶子节点和中间节点,SpringCache就提供了一套抽象的Cache接口,我们统一不同缓存实现的不同的访问方式,Spring中针对不同缓存实现的不同缓存访问类,

比如EnCacheCache,GuavaCache,NoOpCache,RedisCache,JCacheCache,ConcurrentMapCache

CaffeineCacahe

共同利用一个Cache接口

public interface Cache {

String getName();

Object getNativeCache();

Cache.ValueWrapper get(Object var1);

<T> T get(Object var1, Class<T> var2);

<T> T get(Object var1, Callable<T> var2);

void put(Object var1, Object var2);

Cache.ValueWrapper putIfAbsent(Object var1, Object var2);

void evict(Object var1);

void clear();

public static class ValueRetrievalException extends RuntimeException {

private final Object key;

public ValueRetrievalException(Object key, Callable<?> loader, Throwable ex) {

super(String.format(“Value for key ‘%s’ could not be loaded using ‘%s'”, key, loader), ex);

this.key = key;

}

public Object getKey() {

return this.key;

}

}

public interface ValueWrapper {

Object get();

}

}

实际的开发中,一个项目可能会用到不同的缓存,既用到Google Guava的缓存,也用到了Redis缓存,比如同一个缓存实例,可以根据业务的不同,分割成多个小的逻辑缓存单元

Spring还提供了缓存管理功能,不过,包含的功能很简单,有两部分,一个是根据缓存的名字,获取Cache对象,一个是获取管理器管理的所有缓存的名字列表

public interface CacheManager {

Cache getCache(String var1);

Collection<String> getCacheNames();

}

在组合模式的叶子节点和中间节点中,对应到Spring源码中,EhCacheManager,SimpleCacheManager,NoOpCacheManager,RedisCacheManager可以当做叶子节点,CompositeCacheManager,也可以是具体的管理器,比如EhCacheManager,RedisManger等

比如中间层管理器,CompositeCacheManager的代码贴到了下面,可以结合着讲解一下,其中getCache(),getCacheNames()两个函数实现都用到了递归,这既是树形结构的体现

public class CompositeCacheManager implements CacheManager, InitializingBean {

private final List<CacheManager> cacheManagers = new ArrayList();

private boolean fallbackToNoOpCache = false;

public CompositeCacheManager() {

}

public CompositeCacheManager(CacheManager… cacheManagers) {

this.setCacheManagers(Arrays.asList(cacheManagers));

}

public void setCacheManagers(Collection<CacheManager> cacheManagers) {

this.cacheManagers.addAll(cacheManagers);

}

public void setFallbackToNoOpCache(boolean fallbackToNoOpCache) {

this.fallbackToNoOpCache = fallbackToNoOpCache;

}

public void afterPropertiesSet() {

if (this.fallbackToNoOpCache) {

this.cacheManagers.add(new NoOpCacheManager());

}

}

public Cache getCache(String name) {

Iterator var2 = this.cacheManagers.iterator();

Cache cache;

do {

if (!var2.hasNext()) {

return null;

}

CacheManager cacheManager = (CacheManager)var2.next();

cache = cacheManager.getCache(name);

} while(cache == null);

return cache;

}

public Collection<String> getCacheNames() {

Set<String> names = new LinkedHashSet();

Iterator var2 = this.cacheManagers.iterator();

while(var2.hasNext()) {

CacheManager manager = (CacheManager)var2.next();

names.addAll(manager.getCacheNames());

}

return Collections.unmodifiableSet(names);

}

}

装饰器模式在Spring中的应用,

缓存一般是配合数据库来使用的,如果写缓存成功,但是数据库的事务回滚了,那么缓存中就会有脏数据,为了解决这个问题,我们需要将缓存的写操作和数据库的写操作必须放在一个事务中,要么都成功,要么都失败

Spring用到了装饰器模式,TransactionAwareCacheDecorator增加了对事务的支持,在事务提交回滚的时候分别对Cache的数据进行处理

TransactionAwareCacheDecorator实现了Cache接口,并将操作都委托给了targetCache实现,对写操作实现了事务功能

public class TransactionAwareCacheDecorator implements Cache {

private final Cache targetCache;

public TransactionAwareCacheDecorator(Cache targetCache) {

Assert.notNull(targetCache, “Target Cache must not be null”);

this.targetCache = targetCache;

}

public Cache getTargetCache() {

return this.targetCache;

}

public String getName() {

return this.targetCache.getName();

}

public Object getNativeCache() {

return this.targetCache.getNativeCache();

}

public ValueWrapper get(Object key) {

return this.targetCache.get(key);

}

public <T> T get(Object key, Class<T> type) {

return this.targetCache.get(key, type);

}

public <T> T get(Object key, Callable<T> valueLoader) {

return this.targetCache.get(key, valueLoader);

}

public void put(final Object key, final Object value) {

if (TransactionSynchronizationManager.isSynchronizationActive()) {

TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {

public void afterCommit() {

TransactionAwareCacheDecorator.this.targetCache.put(key, value);

}

});

} else {

this.targetCache.put(key, value);

}

}

public ValueWrapper putIfAbsent(Object key, Object value) {

return this.targetCache.putIfAbsent(key, value);

}

public void evict(final Object key) {

if (TransactionSynchronizationManager.isSynchronizationActive()) {

TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {

public void afterCommit() {

TransactionAwareCacheDecorator.this.targetCache.evict(key);

}

});

} else {

this.targetCache.evict(key);

}

}

public void clear() {

if (TransactionSynchronizationManager.isSynchronizationActive()) {

TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {

public void afterCommit() {

TransactionAwareCacheDecorator.this.targetCache.clear();

}

});

} else {

this.targetCache.clear();

}

}

}

工厂模式在Spring中的应用

在Spring中,工厂模式最经典的莫过于IOC容器,对应的Spring源码是BeanFactory和ApplicationContext相关类,

Spring中,创建Bean的方式有很多,比如纯粹的构造函数,或者无参构造加上setter

public class Student {

private long id;

private String name;

public Student(long id, String name) {

this.id = id;

this.name = name;

}

public void setId(long id) {

this.id = id;

}

public void setName(String name) {

this.name = name;

}

}

// 使用构造函数来创建Bean

<bean id=”student” class=”com.xzg.cd.Student”>

<constructor-arg name=”id” value=”1″/>

<constructor-arg name=”name” value=”wangzheng”/>

</bean>

// 使用无参构造函数+setter方法来创建Bean

<bean id=”student” class=”com.xzg.cd.Student”>

<property name=”id” value=”1″></property>

<property name=”name” value=”wangzheng”></property>

</bean>

我们或者使用工厂模式来创建一个Bean,用这种方式创建Bean的话,可以如下

public class StudentFactory {

private static Map<Long, Student> students = new HashMap<>();

static{

map.put(1, new Student(1,”wang”));

map.put(2, new Student(2,”zheng”));

map.put(3, new Student(3,”xzg”));

}

public static Student getStudent(long id){

return students.get(id);

}

}

// 通过工厂方法getStudent(2)来创建BeanId=”zheng””的Bean

<bean id=”zheng” class=”com.xzg.cd.StudentFactory” factory-method=”getStudent”>

<constructor-arg value=”2″></constructor-arg>

</bean>

其他模式在Spring中的应用

大部分是我们讲过的,其中还有我们上面没有提到的,简单的介绍一下

SPEL,Spring Expression Language,按照Spring中常用的来编写配置的表达式语言,定义了一系列的语法规则,我们按照这些语法规则来编写表达式,Spring可以解析出表达式的含义,这就是常见的解释器模式的应用场景

IOC还提供了单例模式,单元测试不友好的时候,应对策略就是通过IOC容器来管理对象,通过IOC容器来实现对象的唯一性控制,这样的单例利用IOC容器的唯一来控制唯一性

Spring还用到了观察者模式,模板模式,职责链模式,代理模式

Spring中,只要后缀带有Tempalte的类,基本上都是模板类,大部分利用了Callback回调,比如jadbTemplate,ReidsTemplate

拦截器使用了职责链模式

AOP使用了代理模式

本章重点:

Spring中涉及的设计模式,适配器模式 策略模式 组合模式 装饰器模式 工厂模式 单例模式 解释器模式 观察者模式 模板模式 职责链模式 代理模式

课后讨论

如何让Spring支持Builder模式创建Bean呢?

对象的初始化有两种实现方式。一种是在类中自定义一个初始化函数,并且通过配置文件,显式地告知 Spring,哪个函数是初始化函数

发表评论

邮箱地址不会被公开。 必填项已用*标注