Dawn's Blogs

分享技术 记录成长

0%

SSM学习之Spring (5) 用到的设计模式

本文总结 Spring 用到的一些设计模式。

工厂模式

Spring 可以通过 BeanFactory 或 ApplicationContext 创建 bean 对象,ApplicationContext 继承自 BeanFactory。

  • BeanFactory:延迟注入,所以占用更少的内存,程序启动速度更快。
  • ApplicationContext:容器启动的时候,不管你用没用到,一次性创建所有 bean 。并且 ApplicationContext 继承自 BeanFactory,扩展了功能。

ApplicationContext 有但不限于以下实现类:

  • ClassPathXmlApplicationContext:从 ClassPath 中加载 XML 配置文件,创建 ApplicationContext。
  • FileSystemXmlApplicationContext:从文件系统中加载 XML 配置文件,创建 ApplicationContext。
  • XmlWebApplicationContext:从 Web 系统中加载 XML 配置文件,创建 ApplicationContext。
  • AnnotationConfigApplicationContext:通过注解配置类,创建 ApplicationContext。

单例模式

bean 的作用域默认就是单例模式的,Spring 通过 ConcurrentHashMap 作为单例注册表来实现单例模式,key 为 bean name,value 为单例对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 通过 ConcurrentHashMap(线程安全) 实现单例注册表
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(64);

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "'beanName' must not be null");
synchronized (this.singletonObjects) {
// 检查缓存中是否存在实例
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
//...省略了很多代码
try {
singletonObject = singletonFactory.getObject();
}
//...省略了很多代码
// 如果实例对象在不存在,我们注册到单例注册表中。
addSingleton(beanName, singletonObject);
}
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
}
//将对象添加到单例注册表
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, (singletonObject != null ? singletonObject : NULL_OBJECT));

}
}
}

代理模式

Spring AOP 就是基于动态代理的,Spring AOP 根据被代理对象是否有实现接口,分别使用 JDK Proxy 和 CGLIB 实现动态代理。

模板方法

TransactionTemplate.execute 使用到了模板方法,实现事务。Spring 使用 Callback 模式与模板方法模式配合,既达到了代码复用的效果,同时增加了灵活性。

以 Template 结尾的对数据库操作的类,都使用到了模板方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Autowired
private TransactionTemplate transactionTemplate;
public void testTransaction() {

transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {

try {

// .... 业务代码
} catch (Exception e){
//回滚
transactionStatus.setRollbackOnly();
}

}
});
}

观察者模式

观察者模式是一种对象行为型模式。它表示的是一种对象与对象之间具有依赖关系,当一个对象发生改变的时候,依赖这个对象的所有对象也会做出反应。Spring 事件驱动模型就是观察者模式很经典的一个应用。Spring 事件驱动模型非常有用,在很多场景都可以解耦代码。比如我们每次添加商品的时候都需要重新更新商品索引,这个时候就可以利用观察者模式来解决这个问题。

Spring 事件驱动模型

Spring 事件驱动模型有三种角色:

  • 事件:ApplicationEvent 是一个抽象类,继承自 java.util.EventObject 并实现了 java.io.Serializable 接口。
  • 事件监听者:ApplicationListener 是一个接口,定义了 onApplicationEvent 方法来处理事件。只要实现了 ApplicationListener 接口,就可以完成对事件的监听。
  • 事件发布者:ApplicationEventPublisher 作为事件的发布者,也是一个接口。这个接口在 AbstractApplicationContext 中实现。

流程

Spring 中完成对事件的订阅和发布,流程如下:

  1. 定义一个事件,继承自 ApplicationEvent。
  2. 定义一个事件监听者,实现 ApplicationListener 接口,重写 onApplicationEvent 方法。
  3. 使用事件发布者发布消息,通过 ApplicationEventPublisher 的 publishEvent 方法发布消息。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// 定义一个事件,继承自ApplicationEvent并且写相应的构造函数
public class DemoEvent extends ApplicationEvent{
private static final long serialVersionUID = 1L;

private String message;

public DemoEvent(Object source,String message){
super(source);
this.message = message;
}

public String getMessage() {
return message;
}
}

// 定义一个事件监听者,实现ApplicationListener接口,重写 onApplicationEvent() 方法;
@Component
public class DemoListener implements ApplicationListener<DemoEvent>{

//使用onApplicationEvent接收消息
@Override
public void onApplicationEvent(DemoEvent event) {
String msg = event.getMessage();
System.out.println("接收到的信息是:"+msg);
}

}
// 发布事件,可以通过ApplicationEventPublisher 的 publishEvent() 方法发布消息。
@Component
public class DemoPublisher {

@Autowired
ApplicationContext applicationContext;

public void publish(String message){
//发布事件
applicationContext.publishEvent(new DemoEvent(this, message));
}
}

适配器模式

适配器模式将一个接口转换成客户希望的另一个接口,适配器模式使接口不兼容的那些类可以一起工作。

Spring AOP 通知

Spring AOP:通知用到了适配器模式,与之相关的接口是 AdvisorAdapter

Advice 常用的类型有:BeforeAdvice(目标方法调用前,前置通知)、AfterAdvice(目标方法调用后,后置通知)、AfterReturningAdvice(目标方法执行结束后,return 之前)等等。每个类型 Advice(通知)都有对应的拦截器:MethodBeforeAdviceInterceptorAfterReturningAdviceInterceptorThrowsAdviceInterceptor 等等。

Spring 预定义的通知要通过对应的适配器,适配成 MethodInterceptor 接口(方法拦截器)类型的对象(如:MethodBeforeAdviceAdapter 通过调用 getInterceptor 方法,将 MethodBeforeAdvice 适配成 MethodBeforeAdviceInterceptor )。

Spring MVC

Spring MVC:SpringMVC 中有 HandlerAdapter,用于适配执行 Handler。

为什么 SpringMVC 需要适配器?

Spring MVC 中的 Controller 种类众多,不同类型的 Controller 通过不同的方法来对请求进行处理。如果不利用适配器模式的话,DispatcherServlet 直接获取对应类型的 Controller,需要的自行来判断,像下面这段代码。新增的 Controller 类型就违反了设计模式中的开闭原则。

1
2
3
4
5
6
7
if(mappedHandler.getHandler() instanceof MultiActionController){
((MultiActionController)mappedHandler.getHandler()).xxx
}else if(mappedHandler.getHandler() instanceof XXX){
...
}else if(...){
...
}

装饰器模式

装饰者模式可以动态地给对象添加一些额外的属性或行为。相比于使用继承,装饰者模式更加灵活。Spring 中配置 DataSource 的时候,DataSource 可能是不同的数据库和数据源,可以通过装饰器模式动态的切换不同的数据源。

Spring 中用到的装饰器在类名上含有 Wrapper 或者 Decorator。