单例设计模式
单例模式主要是为了避免因为创建了多个实例造成资源的浪费,且多个实例由于多次调用容易导致结果出现错误,而使用单例模式能够保证整个应用中有且只有一个实例。
Spring 中的Bean 默认都是单例设计模式,如下源码所示:
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry { /** 保存单例Objects的缓存集合ConcurrentHashMap,key:beanName --> value:bean实例 */ private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) { Assert.notNull(beanName, "Bean name must not be null"); synchronized (this.singletonObjects) { //检查缓存中是否有实例,如果缓存中有实例,直接返回 Object singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null) { //省略... try { //通过singletonFactory获取单例 singletonObject = singletonFactory.getObject(); newSingleton = true; } //省略... if (newSingleton) { addSingleton(beanName, singletonObject); } } //返回实例 return singletonObject; } }
单例模式的好处在于:省略了创建对象花费的时间,减少了系统的开销,极大的减少new操作的次数,减少了GC线程回收内存的压力。
工厂设计模式
工厂模式属于创建型设计模式,需要生成的对象叫做产品,生成对象的地方叫做工厂。
工厂模式在Spring中的应用非常广泛,这里举的例子是ApplicationContext和BeanFactory,这也是Spring的IOC容器的基础。
Spring使用工厂模式可以通过 BeanFactory 或 ApplicationContext 创建 bean 对象。
1.BeanFactory
延迟注入使用到某个 bean 的时候才会注入,相比于BeanFactory来说会占用更少的内存,程序启动速度更快。
2.ApplicationContext
BeanFactory 仅提供了最基本的依赖注入支持,ApplicationContext 扩展了 BeanFactory ,除了有BeanFactory的功能还有额外更多功能,所以一般开发人员使用ApplicationContext会更多。
代理设计模式
代理模式:封装目标对象,并添加额外的功能,对客户端提供更多更优的服务,分类:静态代理和动态代理。
Spring AOP实现原理其实很简单,就是通过动态代理实现的。
Spring AOP 采用了两种混合的实现方式:JDK 动态代理和 CGLib 动态代理。
- JDK动态代理:Spring AOP的首选方法。 每当目标对象实现一个接口时,就会使用JDK动态代理。目标对象必须实现接口
- CGLIB代理:如果目标对象没有实现接口,则可以使用CGLIB代理。
Spring默认使用JDK的动态代理实现AOP,类如果实现了接口,Spring就会使用这种方式实现动态代理。
如下源码所示:
/** * 动态代理 * * @author mikechen */ public class JdkProxySubject implements InvocationHandler { private Subject subject; public JdkProxySubject(Subject subject) { this.subject = subject; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("before 前置通知"); Object result = null; try { result = method.invoke(subject, args); }catch (Exception ex) { System.out.println("ex: " + ex.getMessage()); throw ex; }finally { System.out.println("after 后置通知"); } return result; } }
然后JDK动态代理需要使用的第二个组件就是Proxy这个类,我们可以通过这个类的newProxyInstance方法,返回一个代理对象。
模板方法模式
模板方法模式:定义了操作中的算法的骨架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构,就可以重定义该算法的某些特定步骤。
1.抽象模板(Abstract Class)角色
抽象模板类:负责给出一个算法的轮廓和骨架,它由一个模板方法和若干个基本方法构成。
2.具体实现(Concrete Class)角色
具体实现类:它是抽象类的子类,用于实现在父类中声明的抽象基本操作以完成子类特定算法的步骤,也可以覆盖在父类中已经实现的具体基本操作。
Spring中jdbcTemplate、hibernateTemplate 等以 Template 结尾的对数据库操作的类,它们就使用到了模板模式。
回顾下JDBC的操作流程:有加载驱动程序、获取连接、创建会话、执行SQL、处理结果、释放资源。
倘若每次数据库操作都需要如此繁琐的步骤,那么程序员会疯,Spring对如此不友好的API设计早已看不下去,故针对原生JDBC进行了封装,即JdbcTemplate。
public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
观察者模式
观察者顾名思义,就是一个监听者,类似监听器的存在,一旦被观察/监听的目标发生的情况,就会被监听者发现。
Spring 事件驱动模型就是观察者模式很经典的一个应用,Spring 事件驱动模型非常有用,在很多场景都可以解耦我们的代码。
比如:我们每次添加商品的时候都需要重新更新商品索引,这个时候就可以利用观察者模式来解决这个问题。
Spring 基于观察者模式,实现了自身的事件机制,由三部分组成:
- 事件 ApplicationEvent:通过继承它,实现自定义事件;
- 事件发布者 ApplicationEventPublisher:通过它,可以进行事件的发布;
- 事件监听器 ApplicationListener:通过实现它,进行指定类型的事件的监听;
适配器模式
适配器模式将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作。
如下图所示:
我们知道 Spring AOP 的实现是基于代理模式,但是 Spring AOP 的增强或通知(Advice)使用到了适配器模式,与之相关的接口是AdvisorAdapter 。
Spring MVC 中也是用到了适配器模式适配Controller,在Spring MVC中DispatcherServlet 根据请求信息调用 HandlerMapping,解析请求对应的 Handler。
解析到对应的 Handler,也就是我们平常说的 Controller 控制器后,开始由HandlerAdapter 适配器处理。
HandlerAdapter 作为期望接口,具体的适配器实现类用于对目标类进行适配,Controller 作为需要适配的类。
Spring设计模式总结
Spring使用工厂模式通过 BeanFactory、ApplicationContext 创建 bean 对象;
代理设计模式 : Spring AOP 功能的实现;
单例设计模式 : Spring 中的 Bean 默认都是单例的;
模板方法模式 : Spring 中 jdbcTemplate、hibernateTemplate 等以 Template 结尾的对数据库操作的类,它们就使用到了模板模式;
观察者模式: Spring 事件驱动模型就是观察者模式很经典的一个应用;
适配器模式 :Spring AOP 的增强或通知(Advice)使用到了适配器模式、spring MVC 中也是用到了适配器模式适配Controller。