1.引言
Spring框架及其核心概念
Spring框架是一个开源的、轻量级的Java企业级应用程序开发框架,它提供了一系列的解决方案和工具,用于开发可扩展、可维护、高效的企业级应用程序。
Spring框架的核心概念包括:
1. 控制反转(IoC):Spring框架通过控制反转(IoC)实现了对象的创建和依赖关系的管理。传统的开发方式是由开发者手动创建对象并管理它们之间的依赖关系,而Spring框架将这些任务交给了框架来完成。开发者只需要通过配置文件或注解来描述对象的创建和依赖关系,框架会自动完成对象的创建和依赖注入。
2. 依赖注入(DI):依赖注入是控制反转的一种实现方式,它通过将对象的依赖关系从代码中移除,而是通过配置文件或注解来描述对象之间的依赖关系。这样可以提高代码的可读性和可维护性,并且使得对象之间的耦合度降低,方便进行单元测试和模块化开发。
3. 面向切面编程(AOP):面向切面编程是Spring框架的另一个核心概念,它通过将应用程序的业务逻辑和横切关注点(如日志、事务管理等)分离,实现了代码的模块化和重用。Spring框架通过AOP支持将横切关注点织入到应用程序的特定位置,而不需要修改原有的业务逻辑代码。
4. Spring MVC:Spring MVC是Spring框架的一个模块,用于开发基于MVC(Model-View-Controller)架构的Web应用程序。它提供了一套强大的Web开发框架,包括请求处理、视图解析、数据绑定等功能,使得开发者可以更加方便地开发和管理Web应用程序。
5. 数据访问:Spring框架提供了对各种数据访问技术的支持,包括JDBC、ORM(如Hibernate、MyBatis)、JPA等。它简化了数据访问的开发过程,并提供了一致的编程模型,使得开发者可以更加方便地操作和管理数据。
总之,Spring框架是一个功能强大、灵活易用的企业级应用程序开发框架,它通过控制反转、依赖注入、面向切面编程等核心概念,提供了一系列的解决方案和工具,帮助开发者开发高效、可扩展、可维护的企业级应用程序。
2.Spring Bean的概念和作用
2.1什么是Spring Bean?
在Spring框架中,Bean是指由Spring容器管理的对象。它是Spring框架中最基本的组件,用于封装应用程序中的业务逻辑和数据。Bean可以是任何普通的Java对象,例如POJO(Plain Old Java Object)、实体类、服务类等。
Spring Bean具有以下特点:
生命周期管理:Spring容器负责创建、初始化、使用和销毁Bean对象。开发者只需要通过配置文件或注解来描述Bean的创建和销毁方式,Spring容器会自动完成这些操作。
依赖注入:Spring容器负责管理Bean之间的依赖关系。开发者只需要通过配置文件或注解来描述Bean的依赖关系,Spring容器会自动将依赖的Bean注入到目标Bean中。
AOP支持:Spring容器支持面向切面编程(AOP),可 以将横切关注点(如日志、事务管理等)织入到Bean的特定位置,而不需要修改原有的业务逻辑代码。
配置灵活性:Spring容器提供了多种配置方式,包括XML配置、注解配置和Java配置等。开发者可以根据项目需求选择最合适的配置方式。
通过使用Spring Bean,开发者可以实现业务逻辑的解耦和模块化,提高代码的可读性、可维护性和可测试性。此外,Spring Bean还可以享受Spring框架提供的各种功能和特性,如事务管理、数据访问、缓存管理等,进一步简化开发过程。
3.生命周期流程图
Spring Bean的完整生命周期从创建Spring容器开始,直到最终Spring容器销毁Bean,这其中包含了一系列关键点。
若容器注册了以上各种接口,程序那么将会按照以上的流程进行。下面将仔细讲解各接口作用。
3.1各种接口方法分类
Bean的完整生命周期经历了各种方法调用,这些方法可以划分为以下几类:
1、Bean自身的方法:这个包括了Bean本身调用的方法和通过配置文件中<bean>的init-method和destroy-method指定的方法
2、Bean级生命周期接口方法:这个包括了BeanNameAware、BeanFactoryAware、InitializingBean和DiposableBean这些接口的方法
3、容器级生命周期接口方法:这个包括了InstantiationAwareBeanPostProcessor 和 BeanPostProcessor 这两个接口实现,一般称它们的实现类为“后处理器”。
4、工厂后处理器接口方法:这个包括了AspectJWeavingEnabler, ConfigurationClassPostProcessor, CustomAutowireConfigurer等等非常有用的工厂后处理器 接口的方法。工厂后处理器也是容器级的。在应用上下文装配配置文件之后立即调用
4.Spring Bean的作用域
当通过Spring容器创建一个Bean实例时,不仅可以完成Bean实例的实例化,还可以为Bean指定特定的作用域。Spring支持如下五种作用域:
singleton: 单例模式,在整个Spring IoC容器中,singleton作用域的Bean将只生成一个实例。
prototype: 每次通过容器的getBean()方法获取prototype作用域的Bean时,都将产生一个新的Bean实例。
request: 对于一次HTTP请求,request作用域的Bean将只生成一个实例,这意味着,在同一次HTTP请求内,程序每次请求该Bean,得到的总是同一个实例。只有在Web应用中使用Spring时,该作用域才真正有效。
session:该作用域将 bean 的定义限制为 HTTP 会话。 只在web-aware Spring ApplicationContext的上下文中有效。
global session: 每个全局的HTTP Session对应一个Bean实例。在典型的情况下,仅在使用portlet context的时候有效,同样只在Web应用中有效。
如果不指定Bean的作用域,Spring默认使用singleton作用域。prototype作用域的Bean的创建、销毁代价比较大。而singleton作用域的Bean实例一旦创建成果,就可以重复使用。因此,应该尽量避免将Bean设置成prototype作用域。
5.Spring Bean的依赖注入
依赖注入
Spring框架的核心功能有两个:
Spring容器作为超级大工厂,负责创建、管理所有的Java对象,这些Java对象被称为Bean。
Spring容器管理容器中Bean之间的依赖关系,Spring使用一种被称为"依赖注入"的方式来管理Bean之间的依赖关系。
使用依赖注入,不仅可以为Bean注入普通的属性值,还可以注入其他Bean的引用。依赖注入是一种优秀的解耦方式,其可以让Bean以配置文件组织在一起,而不是以硬编码的方式耦合在一起。
理解依赖注入
Rod Johnson是第一个高度重视以配置文件来管理Java实例的协作关系的人,他给这种方式起了一个名字:控制反转(Inverse of Control,IoC)。后来Martine Fowler为这种方式起了另一个名称:依赖注入(Dependency Injection),因此不管是依赖注入,还是控制反转,其含义完全相同。当某个Java对象(调用者)需要调用另一个Java对象(被依赖对象)的方法时,在传统模式下通常有两种做法:
原始做法: 调用者主动创建被依赖对象,然后再调用被依赖对象的方法。
简单工厂模式: 调用者先找到被依赖对象的工厂,然后主动通过工厂去获取被依赖对象,最后再调用被依赖对象的方法。
注意上面的主动二字,这必然会导致调用者与被依赖对象实现类的硬编码耦合,非常不利于项目升级的维护。使用Spring框架之后,调用者无需主动获取被依赖对象,调用者只要被动接受Spring容器为调用者的成员变量赋值即可,由此可见,使用Spring后,调用者获取被依赖对象的方式由原来的主动获取,变成了被动接受——所以Rod Johnson称之为控制反转。
另外从Spring容器的角度来看,Spring容器负责将被依赖对象赋值给调用者的成员变量——相当于为调用者注入它依赖的实例,因此Martine Fowler称之为依赖注入。
设值注入
设值注入是指IoC容器通过成员变量的setter方法来注入被依赖对象。这种注入方式简单、直观,因而在Spring的依赖注入里大量使用。
构造注入
利用构造器来设置依赖关系的方式,被称为构造注入。通俗来说,就是驱动Spring在底层以反射方式执行带指定参数的构造器,当执行带参数的构造器时,就可利用构造器参数对成员变量执行初始化——这就是构造注入的本质。
两种注入方式的对比
设值注入有如下优点:
与传统的JavaBean的写法更相似,程序开发人员更容易理解、接受。通过setter方法设定依赖关系显得更加直观、自然。
对于复杂的依赖关系,如果采用构造注入,会导致构造器过于臃肿,难以阅读。Spring在创建Bean实例时,需要同时实例化其依赖的全部实例,因而导致性能下降。而使用设值注入,则能避免这些问题。
尤其在某些成员变量可选的情况下,多参数的构造器更加笨重。
构造注入优势如下:
构造注入可以在构造器中决定依赖关系的注入顺序,优先依赖的优先注入。
对于依赖关系无需变化的Bean,构造注入更有用处。因为没有setter方法,所有的依赖关系全部在构造器内设定,无须担心后续的代码对依赖关系产生破坏。
依赖关系只能在构造器中设定,则只有组件的创建者才能改变组件的依赖关系,对组件的调用者而言,组件内部的依赖关系完全透明,更符合高内聚的原则。
注意:
建议采用设值注入为主,构造注入为辅的注入策略。对于依赖关系无须变化的注入,尽量采用构造注入;而其他依赖关系的注入,则考虑采用设值注入。
5.1配置依赖方式
使用@Resource配置依赖
@Resource位于javax.annotation包下,是来自JavaEE规范的一个Annotation,Spring直接借鉴了该Annotation,通过使用该Annotation为目标Bean指定协作者Bean。使用@Resource与<property.../>元素的ref属性有相同的效果。
@Resource不仅可以修饰setter方法,也可以直接修饰实例变量,如果使用@Resource修饰实例变量将会更加简单,此时Spring将会直接使用JavaEE规范的Field注入,此时连setter方法都可以不要。
使用@PostConstruct和@PreDestroy定制生命周期行为
@PostConstruct和@PreDestroy同样位于javax.annotation包下,也是来自JavaEE规范的两个Annotation,Spring直接借鉴了它们,用于定制Spring容器中Bean的生命周期行为。它们都用于修饰方法,无须任何属性。其中前者修饰的方法时Bean的初始化方法;而后者修饰的方法时Bean销毁之前的方法。
Spring4.0增强的自动装配和精确装配
Spring提供了@Autowired注解来指定自动装配,@Autowired可以修饰setter方法、普通方法、实例变量和构造器等。当使用@Autowired标注setter方法时,默认采用byType自动装配策略。在这种策略下,符合自动装配类型的候选Bean实例常常有多个,这个时候就可能引起异常,为了实现精确的自动装配,Spring提供了@Qualifier注解,通过使用@Qualifier,允许根据Bean的id来执行自动装配。
Spring Bean的生命周期管理
Spring Bean的生命周期包括以下几个阶段:
1.实例化:当容器加载Bean的配置信息并根据信息创建Bean时,就实例化了一个Bean对象。
2.属性赋值:在实例化Bean对象后,Spring会自动将配置文件中指定的各种属性值或引用值赋给实例化的Bean对象。
3.自定义初始化方法:在Bean的属性赋值完成后,Spring容器会调用Bean中自定义的初始化方法。
4.实现BeanPostProcessor接口的后置处理器方法:在Bean的初始化方法执行前后,Spring容器会先后执行实现了BeanPostProcessor接口的前置处理器和后置处理器方法。
5.使用:完成初始化之后,就可以将Bean注入到其他的Bean中使用了。
6.销毁:当容器关闭时,Spring容器会自动调用Bean中自定义的销毁方法。
需要注意的是,在整个Bean的生命周期中,有些方法可以让我们自定义Bean的行为,比如自定义初始化方法和销毁方法,而有些方法则是在Spring容器内部自动执行的,我们只能观察和学习。其中,实现BeanPostProcessor接口的后置处理器方法是一个非常重要的扩展点,可以对Bean的属性进行一些处理或者修改。
6.单例模式
在Spring中,单例模式是默认的Bean作用域(scope)。Spring容器在启动时创建一个实例,并在整个应用程序中共享该实例。
在单例模式下,所有对Bean的请求都将返回同一个实例。这意味着,如果一个组件修改了该Bean的状态,这个状态的改变将影响到所有正在使用的组件,因此需要考虑线程安全性。
单例模式适用于那些不需要太多状态共享的Bean,例如:配置类、工具类、缓存对象等。它们在整个应用程序中只需要一个实例,并且它们的状态相对稳定,不会被频繁改变。
需要注意的是,单例模式并不适合那些需要频繁创建和销毁的Bean,例如:会话Bean、请求Bean等。对于这些类别的Bean,应该使用作用域为“会话”或“请求”的范围,以便能够更好地控制生命周期和状态的共享。
Spring在默认情况下使用单例模式创建bean。单例模式的优点包括:
节省资源:创建单例bean只需要一次初始化和构造,以后的请求都会返回这个实例,避免了大量的重复创建和销毁对象的处理。
提高性能:单例模式在单实例的情况下,可以减少程序运行时的内存开销和对象初始化时间,从而提高应用程序的性能。
对象一致性:单例模式可以保证在一个JVM中只有一个实例存在,保证了对象的一致性和唯一性。
单例模式的缺点包括:
不支持多例:单例模式只能创建一个实例,不支持多例,这可能会造成一定的限制和不便。
难于扩展:由于单例模式只有一个实例,如果扩展出新的实例,会破坏单例模式的原则,因此扩展单例类可能比较困难。
全局可见性:单例模式是全局可见的,在整个应用程序中都可以访问它,这可能会导致一些不可预知的问题和副作用。
7.多例模式
在Spring中,多例(Prototype)模式是一种Bean作用域(scope),其Bean实例在每次请求时都会创建一个新的实例。
多例模式适用于需要频繁创建和销毁的Bean,例如:会话Bean、请求Bean等。这些Bean的生命周期很短,使用单例模式会导致过多的存储消耗和严重的并发问题。
使用多例模式的主要优点包括:
每次请求都会创建一个新的Bean实例,避免了并发访问的问题。
每个Bean实例都拥有自己独立的状态,不会受到其他Bean实例的影响。
多例模式的主要缺点包括:
每次请求都需要创建和初始化一个新的Bean实例,需要更多的资源和时间。
如果Bean的状态变得复杂,会增加调试和维护的难度。
需要注意的是,在使用多例模式时,Spring容器只负责创建和管理Bean实例,不会自动清理资源。因此,在使用多例模式时,需要确保适当清理和释放相关资源。