在Spring框架中,设计模式被广泛运用以实现其强大的功能和灵活性。这些设计模式的使用使得Spring框架更加灵活、可扩展和易于维护。Spring框架中的设计模式主要包括以下几个方面:
1)单例模式:单例模式是一种创建型设计模式,其主要目的是确保类只有一个实例,并提供一个全局访问点。在Spring中,Bean的默认作用域就是单例(Singleton),这意味着在整个应用程序中只有一个Bean实例,由Spring容器负责管理。单例模式可以确保在应用程序中只存在一个共享的实例,从而节省资源并提高性能。
2)工厂模式:工厂模式是一种创建型设计模式,它提供了一个创建对象的接口,但允许子类决定实例化哪个类。在Spring中,工厂模式通过Bean工厂来创建和管理Bean。Spring中的BeanFactory和ApplicationContext负责创建和配置Bean,隐藏了具体实例化的细节,使得应用程序更易于扩展和维护。
3)代理模式:代理模式是一种结构型设计模式,它允许通过代理类控制对其他对象的访问。在Spring AOP(面向切面编程)中,代理模式被广泛用于实现横切关注点的代码分离,例如日志记录、事务管理等。Spring通过动态代理和CGLIB(Code Generation Library)来实现代理模式。
4)观察者模式:观察者模式是一种行为设计模式,用于建立一种对象(主题)与多个观察者之间的依赖关系,使得多个观察者对象可以同步获取主题对象的状态变化。在Spring中,事件监听机制是观察者模式的应用,它允许组件监听和响应特定类型的事件,实现了松耦合的组件通信。
5)适配器模式:适配器模式用于将一个类的接口转换成客户端期望的另一个接口,从而使原本因接口不兼容而不能一起工作的类能够一起工作。在SpringMVC中,HandlerAdapter允许不同类型的处理器适配到处理器接口,以实现统一的处理器调用。
实现过程:DispatcherServlet根据HandlerMapping返回的handler,向HandlerAdapter发起请求,处理handler。HandlerAdapter根据规则找到对应的Handler并让其执行,执行完毕后Handler会向HandlerAdapter返回一个ModelAndView,最后由HandlerAdapter向DispatcherServlet返回一个ModelAndView。
6)装饰器模式:装饰器模式允许在不改变原有对象的情况下,通过包装一个对象来增加新的功能。在Spring中,BeanWrapper允许在不修改原始Bean类的情况下添加额外的功能。
7)策略模式:策略模式定义了一系列的算法,并将每一个算法封装起来,使它们可以相互替换。在Spring中,策略模式用于实现不同的算法或策略,例如任务调度策略。
8)模板方法模式:模板方法模式定义了一个操作中的算法骨架,将一些步骤延迟到子类中实现。在Spring中,JdbcTemplate、HibernateTemplate等类使用了模板方法模式,提供了统一的接口同时允许用户根据自己的需求进行定制。
9)责任链模式:责任链模式用于将通知按顺序执行。在Spring AOP中,责任链模式实现通知的调用,确保通知按顺序执行。
这些设计模式的广泛应用使得Spring框架具有强大的功能和可定制性,能够适应各种复杂的应用场景。
控制反转(IoC)和依赖注入(DI)
IoC(Inversion of Control,控制反转) 是Spring 中一个非常非常重要的概念,它不是什么技术,而是一种解耦的设计思想。它的主要目的是借助于"第三方"(Spring 中的 IOC 容器) 实现具有依赖关系的对象之间的解耦(IOC容器管理对象,你只管使用即可),从而降低代码之间的耦合度。IOC 是一个原则,而不是一个模式,以下模式(但不限于)实现了IoC原则。
Spring IOC 容器就像是一个工厂一样,当我们需要创建一个对象的时候,只需要配置好配置文件/注解即可,完全不用考虑对象是如何被创建出来的。 IOC 容器负责创建对象,将对象连接在一起,配置这些对象,并从创建中处理这些对象的整个生命周期,直到它们被完全销毁。
在实际项目中一个 Service 类如果有几百甚至上千个类作为它的底层,我们需要实例化这个 Service,你可能要每次都要搞清这个 Service 所有底层类的构造函数,这可能会把人逼疯。如果利用 IOC 的话,你只需要配置好,然后在需要的地方引用就行了,这大大增加了项目的可维护性且降低了开发难度。
1、控制反转(IoC)的概念
控制反转(Inversion of Control,IoC)是面向对象编程中的一种设计原则,用于减低计算机代码之间的耦合度。通过控制反转,对象的创建和依赖关系由一个外部实体(通常是框架或容器)来管理,而不是由代码本身控制。这种设计原则的目的是提高代码的模块化和可测试性。
2、依赖注入(DI)的概念
依赖注入(Dependency Injection,DI)是控制反转的一种实现方式。在依赖注入中,对象所需的依赖关系不是由对象自身创建,而是由外部容器在运行时注入。例如,在Spring框架中,对象的实例不再由调用者创建,而是由Spring容器创建,并将依赖对象注入到需要的地方。这种机制降低了代码之间的耦合度,提高了系统的灵活性和可维护性。
3、控制反转和依赖注入的关系
控制反转和依赖注入经常一起使用。控制反转通过将对象的创建和依赖关系交给外部容器来管理,而依赖注入则是具体实现这一过程的方式。在Spring框架中,控制反转通过依赖注入来实现,Spring容器负责将被依赖对象赋值给调用者的成员变量,从而实现了依赖的注入。
**依赖注入(DI)**的三种基本形式:
构造函数注入:依赖项通过被构造对象的构造函数传递。
属性注入:依赖项通过被构造对象公开的可设置属性传递。
方法注入:依赖项通过被构造对象的方法调用传递。
在这些方式中,构造函数注入是最常见的一种方式,因为它可以确保所依赖的组件在对象创建之后就立即可用,同时将依赖项设置为不可变状态。
另外,重点说明一下几个设计模式:
工厂设计模式
Spring使用工厂模式可以通过 BeanFactory 或 ApplicationContext 创建 bean 对象。
两者对比:
BeanFactory :它是延迟注入,也就是使用到某个 bean 的时候才会注入,这样BeanFactory会占用更少的内存,程序启动速度更快。
ApplicationContext :容器启动的时候,不管你用没用到,一次性创建所有 bean 。BeanFactory仅提供了最基本的依赖注入支持,ApplicationContext 扩展了 BeanFactory ,除了有BeanFactory的功能还有额外更多功能,所以一般开发人员使用ApplicationContext会更多。
在Spring框架中,ApplicationContext是一个接口,它提供了访问Spring容器对象和服务的方法。ApplicationContext有三个常用的实现类:
ClassPathXmlApplicationContext:从类路径下加载配置文件。
FileSystemXmlApplicationContext:从文件系统中加载配置文件。
AnnotationConfigApplicationContext:当使用Java配置和注解时,用于初始化Spring容器。
核心容器的两个接口引发出的问题:
ApplicationContext:单例对象适用
它在构建核心容器时,创建对象采取的策略是采取立即加载的方式。也就是说,只要一读取完配置文件马上就创建配置文件中配置的对象。
BeanFactory:多例对象适用
它在构建核心容器时,创建对象采用的策略时采用延迟加载的方式。也就是说,什么时候根据id获取对象了,什么时候才真正创建对象。
单例设计模式
在我们的系统中,有一些对象其实我们只需要一个,比如说:线程池、缓存、对话框、注册表、日志对象、充当打印机、显卡等设备驱动程序的对象。事实上,这一类对象只能有一个实例,如果制造出多个实例就可能会导致一些问题的产生,比如:程序的行为异常、资源使用过量、或者不一致性的结果。
使用单例模式的好处:
对于频繁使用的对象,可以省略创建对象所花费的时间,这对于那些重量级对象而言,是非常可观的一笔系统开销;由于 new 操作的次数减少,因而对系统内存的使用频率也会降低,这将减轻 GC 压力,缩短 GC 停顿时间。
Spring 中 bean 的默认作用域就是 singleton(单例)的。
代理设计模式
代理模式在 AOP 中的应用 AOP(Aspect-Oriented Programming:面向切面编程)能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性。
Spring AOP 就是基于动态代理的,如果要代理的对象,实现了某个接口,那么Spring AOP会使用JDK Proxy,去创建代理对象,而对于没有实现接口的对象,就无法使用 JDK Proxy 去进行代理了,这时候Spring AOP会使用 Cglib 生成一个被代理对象的子类来作为代理。
当然你也可以使用 AspectJ ,Spring AOP 已经集成了AspectJ ,AspectJ 应该算的上是 Java 生态系统中最完整的 AOP 框架了。
使用 AOP 之后我们可以把一些通用功能抽象出来,在需要用到的地方直接使用即可,这样大大简化了代码量。我们需要增加新功能时也方便,这样也提高了系统扩展性。日志功能、事务管理等等场景都用到了 AOP 。
Spring AOP 和 AspectJ AOP 有什么区别?
Spring AOP 属于运行时增强,而 AspectJ 是编译时增强。 Spring AOP 基于代理(Proxying),而 AspectJ 基于字节码操作(Bytecode Manipulation)。
Spring AOP 已经集成了 AspectJ ,AspectJ 应该算的上是 Java 生态系统中最完整的 AOP 框架了。AspectJ 相比于 Spring AOP 功能更加强大,但是 Spring AOP 相对来说更简单,
如果我们的切面比较少,那么两者性能差异不大。但是,当切面太多的话,最好选择 AspectJ ,它比Spring AOP 快很多。
总结
Spring框架中的设计模式是多种多样的,它们共同构成了Spring强大的功能和灵活性。学习和理解这些设计模式不仅有助于我们更好地使用Spring框架,也有助于我们提高软件设计和开发的能力。Spring框架运用多种设计模式,如工厂、单例、代理、模板方法、观察者、策略和适配器等,实现其强大的功能和灵活性。这些设计模式使得Spring更加易于扩展和使用,同时也为学习和实践设计模式提供了机会。