Spring是一个轻量级Java开发框架,最早有Rod Johnson创建,目的是为了解决企业级应用开发的业务逻辑层和其他各层的耦合问题。它是一个分层的JavaSE / JavaEE full-stack(一站式)轻量级开源框架,为开发Java应用程序提供全面的基础架构支持。Spring负责基础架构,因此Java开发者可以专注于应用程序的开发。
Spring最根本的使命是解决企业级应用开发的复杂性,即简化Java开发。
Spring可以做很多事情,它为企业级开发提供给了丰富的功能,但是这些功能的底层都依赖于它的两个核心特性,也就是 依赖注入(dependency injection,DI) 和 面向切面编程(aspect-oriented programming,AOP)。
为了降低Java开发的复杂性,Spring采取了以下4种关键策略
- 基于POJO的轻量级和最小侵入性编程;
- 通过依赖注入和面向接口实现松耦合;
- 基于切面和惯例进行声明式编程;
- 通过切面和模板减少样板式代码。
Spring设计目标: Spring为开发者提供一个一站式轻量级应用开发平台;
Spring设计理念: 在JavaEE开发中,支持POJO和JavaBean开发方式,使应用面向接口开发,充分支持OO(面向对象)设计方法;Spring通过IoC容器实现对象耦合关系的管理,并实现依赖反转,将对象之间的依赖关系交给IoC容器,实现解耦;
Spring框架的核心:IoC容器 和 AOP模块。通过IoC容器管理POJO对象以及他们之间的耦合关系;通过AOP以动态非侵入的方式增强服务。
IoC让相互协作的组件保持松散的耦合,而AOP编程允许你把遍布于应用各层的功能分离出来形成可重用的功能组件。
Spring优点:
- 方便解耦,简化开发
- Spring就是一个大工厂,可以将所有对象的创建和依赖关系的维护,交给Spring管理。
- AOP编程的支持
- Spring提供面向切面编程,可以方便的实现对程序进行权限拦截、运行监控等功能。
- 声明式事务的支持
- 只需要通过配置就可以完成对事务的管理,而无需手动编程。
- 方便程序的测试
- Spring对Junit4支持,可以通过注解方便的测试Spring程序。
- 方便集成各种优秀框架
- Spring不排斥各种优秀的开源框架,其内部提供了对各种优秀框架的直接支持(如:Struts、Hibernate、MyBatis等)。
- 降低JavaEE API的使用难度
- Spring对JavaEE开发中非常难用的一些API(JDBC、JavaMail、远程调用等),都提供了封装,使这些API应用难度大大降低。
Spring缺点:
- Spring明明一个很轻量级的框架,却给人感觉大而全。
- Spring依赖反射,反射影响性能。
- 使用门槛升高,入门Spring需要较长时间。
Spring的核心模块
Spring 总共大约有 20 个模块, 由 1300 多个不同的文件构成。 而这些组件被分别整合在核心容器(Core Container) 、 AOP(Aspect Oriented Programming)和设备支持(Instrmentation) 、数据访问与集成(Data Access/Integeration) 、 Web、 消息(Messaging) 、 Test等 6 个模块中。 以下是 Spring 5 的模块结构图:
- spring core: 提供了框架的基本组成部分,包括控制反转(Inversion of Control,IOC)和依赖注入(Dependency Injection,DI)功能。
- spring beans: 提供了BeanFactory,是工厂模式的一个经典实现,Spring将管理对象称为Bean。
- spring context: 构建于 core 封装包基础上的 context 封装包,提供了一种框架式的对象访问方法。
- spring jdbc: 提供了一个JDBC的抽象层,消除了烦琐的JDBC编码和数据库厂商特有的错误代码解析, 用于简化JDBC。
- spring aop: 提供了面向切面的编程实现,让你可以自定义拦截器、切点等。
- spring Web: 提供了针对 Web 开发的集成特性,例如文件上传,利用 servlet listeners 进行 ioc 容器初始化和针对 Web 的 ApplicationContext。
- spring test: 主要为测试提供支持的,支持使用JUnit或TestNG对Spring组件进行单元测试和集成测试。
目前github上能看到的最老版本的spring 源码是3.0.0.M1版本,时间是2008年,Spring的核心思想在这些早期版本中都已经得到了很好的体现,有兴趣的可以研究一下Spring的早期源码。
spring-projects/spring-framework at v3.0.0.M1 (github.com)
AOP 与IOC
Spring IOC 容器
控制反转即IoC (Inversion of Control),它把传统上由程序代码直接操控的对象的调用权交给容器,通过容器来实现对象组件的装配和管理。所谓的“控制反转”概念就是对组件对象控制权的转移,从程序代码本身转移到了外部容器。
Spring IOC 负责创建对象,管理对象(通过依赖注入(DI),装配对象,配置对象,并且管理这些对象的整个生命周期。
控制反转(IoC)的作用
-
管理对象的创建和依赖关系的维护。 对象的创建并不是一件简单的事,在对象关系比较复杂时,如果依赖关系需要程序猿来维护的话,那是相当头疼的。
-
解耦,由容器去维护具体的对象。
-
托管了类的产生过程,比如我们需要在类的产生过程中做一些处理,最直接的例子就是代理,如果有容器程序可以把这部分处理交给容器,应用程序则无需去关心类是如何完成代理的。
IOC的优点
-
IOC 或 依赖注入把应用的代码量降到最低。
-
它使应用容易测试,单元测试不再需要单例和JNDI查找机制。
-
最小的代价和最小的侵入性使松散耦合得以实现。
-
IOC容器支持加载服务时的饿汉式初始化和懒加载。
Spring IoC 的实现机制
Spring 中的 IoC 的实现原理就是工厂模式 加 反射机制。
Spring 的 IoC支持功能
Spring 的 IoC 设计支持以下功能:
- 依赖注入
- 依赖检查
- 自动装配
- 支持集合
- 指定初始化方法和销毁方法
- 支持回调某些方法(但是需要实现 Spring 接口,略有侵入)
其中,最重要的就是依赖注入,从 XML 的配置上说,即 ref 标签。对应 Spring RuntimeBeanReference 对象。
对于 IoC 来说,最重要的就是容器。容器管理着 Bean 的生命周期,控制着 Bean 的依赖注入。
BeanFactory和ApplicationContext
Spring 作者 Rod Johnson 设计了两个接口用以表示容器。
-
BeanFactory
-
ApplicationContext
BeanFactory 简单粗暴,可以理解为就是个 HashMap,Key 是 BeanName,Value 是 Bean 实例。通常只提供注册(put),获取(get)这两个功能。我们可以称之为 “低级容器”。
ApplicationContext 可以称之为 “高级容器”。因为他比 BeanFactory 多了更多的功能。他继承了多个接口。因此具备了更多的功能。例如资源的获取,支持多种消息(例如 JSP tag 的支持),对 BeanFactory 多了工具级别的支持等待。所以你看他的名字,已经不是 BeanFactory 之类的工厂了,而是 “应用上下文”, 代表着整个大容器的所有功能。该接口定义了一个 refresh 方法,此方法是所有阅读 Spring 源码的人的最熟悉的方法,用于刷新整个容器,即重新加载/刷新所有的 bean。
当然,除了这两个大接口,还有其他的辅助接口,这里就不介绍他们了。
BeanFactory和ApplicationContext的关系
为了更直观的展示 “低级容器” 和 “高级容器” 的关系,这里通过常用的 ClassPathXmlApplicationContext 类来展示整个容器的层级 UML 关系。
有点复杂? 先不要慌,我来解释一下。最上面的是 BeanFactory,下面的 3 个绿色的,都是功能扩展接口,这里就不展开讲。
看下面的隶属 ApplicationContext 粉红色的 “高级容器”,依赖着 “低级容器”,这里说的是依赖,不是继承哦。他依赖着 “低级容器” 的 getBean 功能。而高级容器有更多的功能:支持不同的信息源头,可以访问文件资源,支持应用事件(Observer 模式)。
通常用户看到的就是 “高级容器”。 但BeanFactory 也非常够用啦!左边灰色区域的是 “低级容器”, 只负载加载 Bean,获取 Bean。容器其他的高级功能是没有的。例如上图画的 refresh 刷新 Bean 工厂所有配置,生命周期事件回调等。
IoC 在 Spring 里,只需要低级容器就可以实现,2 个步骤:
-
加载配置文件,解析成BeanDefinition放在 Map 里。
-
调用getBean的时候,从BeanDefinition所属的Map里,拿出Class对象进行实例化,同时,如果有依赖关系,将递归调用getBean方法,完成依赖注入。
上面就是Spring低级容器(BeanFactory)的 IoC。
至于高级容器ApplicationContext,他包含了低级容器的功能,当他执行refresh模板方法的时候,将刷新整个容器的Bean。同时其作为高级容器,包含了太多的功能。一句话,他不仅仅是 IoC。他支持不同信息源头,支持BeanFactor 工具类,支持层级容器,支持访问文件资源,支持事件发布通知,支持接口回调等等。
Spring Beans
Spring beans是那些形成Spring应用的主干的java对象。它们被Spring IOC容器初始化,装配,和管理。这些beans通过容器中配置的元数据创建。比如,以XML文件中的形式定义。目前一般采用注解的方式来定义Spring Beans。
Spring支持的几种bean的作用域
Spring框架支持以下五种bean的作用域:
-
singleton : bean在每个Spring ioc 容器中只有一个实例。
-
prototype: 一个bean的定义可以有多个实例。
-
request: 每次http请求都会创建一个bean,该作用域仅在基于web的Spring ApplicationContext情形下有效。
-
session: 在一个HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。
-
global-session: 在一个全局的HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。
注意: 缺省的Spring bean 的作用域是Singleton。使用 prototype 作用域需要慎重的思考,因为频繁创建和销毁 bean 会带来很大的性能开销。
Spring Beans生命周期
整体上来讲,Spring的生命周期可以分为4个阶段:实例化、属性赋值、初始化、销毁。实例化和属性赋值对应构造方法和setter方法的注入,初始化和销毁是用户能自定义扩展的两个阶段。并且,在这四步之间穿插的各种扩展点。
-
实例化 Instantiation
-
属性赋值 Populate
-
初始化 Initialization
-
销毁 Destruction
-
实例化,创建一个Bean对象
-
填充属性,为属性赋值
-
初始化
- 如果实现了xxxAware接口,通过不同类型的Aware接口拿到Spring容器的资源。
- 如果实现了BeanPostProcessor接口,则会回调该接口的postProcessBeforeInitialzation和postProcessAfterInitialization方法。
- 如果配置了init-method方法,则会执行init-method配置的方法。
-
销毁
- 容器关闭后,如果Bean实现了DisposableBean接口,则会回调该接口的destroy方法。
- 如果配置了destroy-method方法,则会执行destroy-method配置的方法。
Spring常用注解
Spring常用注解表
注解 | DESCRIPTION |
---|---|
@Component, @Repository, and @Service | @Component annotation is the generalized form considered as a candidate for auto-detection when using annotation-based configuration and classpath scanning. It extended to more specific forms such as @Controller, @Repository, and @Service. |
@Autowired | The XML files define string bean dependencies, and the same can be automatically detected by the Spring container by using the @Autowired annotation. This would eliminate the use of XML configurations. |
@Qualifier | There may be scenarios when you create more than one bean of the same type and want to wire only one of them with a property. Control this using @Qualifier annotation along with the @Autowired annotation. |
@Required | @Required annotation applies to bean property setter methods and enforces required properties |
Difference between @Resource, @Autowired, and @Inject | This tutorial explains the difference between these three annotations @Resource, @Autowired and @Inject used for injecting the objects. |
@Inject and @Named | @Inject and @Named annotations are JSR-330 annotations were introduced in Spring 3 as an alternative for the spring annotations @Autowired and @Component. |
@Resource, @PostConstruct, and @PreDestroy | This tutorial explains the JSR-250 annotations that Spring 2.5 introduces, which include @Resource, @PostConstruct, and @PreDestroy annotations. |
@RestController | @RestController annotation is inherited from the @Controller annotation. This is the special version of @Controller annotation for implementing the RESTful Web Services. @RestController was added as part of the Spring 4 release. |
@RequestHeader | @RequestHeader annotation for facilitating us to get the header details easily in our controller class. This annotation would bind the header details with the method arguments, and it can be used inside the methods. |
@ControllerAdvice | @ControllerAdvice annotation used for defining the exception handler with specific exception details for each method. This component will handle any exception thrown on any part of the application. |
@ModelAttribute | @ModelAttribute annotation can be used as the method arguments or before the method declaration. The primary objective of this annotation to bind the request parameters or form fields to a model object. |
@Conditional | This tutorial explains one of the new features introduced in spring 4, conditional annotation type. |
@Query | This spring data series tutorial explains @query annotation and how to create a custom query using the @query annotation. |
@Profile | This tutorial explains how to enable profiles in your spring application for different environments. |
@Configuration | Instead of using the XML files, we can use plain Java classes to annotate the configurations by using the @Configuration annotation. If you annotate a class with @Configuration, it indicates that the class defines the beans using the @Bean annotation. |
@PathVariable | We have to use @PathVariable for accepting the customized or more dynamic parameters in the request paths. |
@Controller, @RequestMapping, @RequestParam, @SessionAttributes, and @InitBinder | This tutorial explains some of the key annotations that are related to Spring MVC applications @Controller, @RequestMapping, @RequestParam, @SessionAttributes, and @InitBinder |
Difference between @RequestParam and @PathVariable | This tutorial explains the difference between the two annotations @RequestParam and @PathVariable. |
@RequestMapping | You can use @RequestMapping annotation for mapping web requests to particular handler classes or handler methods. |
@Value | This tutorial shows how to load the properties file values using the @Value annotation. |
@Import | @Import is the annotation used for consolidating all the configurations defined in various configuration files using @Configuration annotation. |
@Transactional | Use annotation *@*Transactional to define a particular method that should be within a transaction. |
@SpringBootApplication | This is annotation is the heart of spring boot application. @SpringBootApplication indicates that it is the entry point for the spring boot application. |
@EnableAutoConfiguration | This example demonstrates how to use the @EnableAutoConfiguration annotations for auto-configuring the spring boot applications. |
@EnableCaching | @EnableCaching annotation is the annotation-driven cache management feature in the spring framework. This annotation added to the spring in version 3.1. |