什么是 Spring
Spring 是一个开源的, 轻量级 Java 开发框架; 其核心特性是可以用于开发任何 Java 应用程序, Spring 框架的目标是使 JavaEE 应用程序的开发变得更加容易, 核心概念是 IoC 和 AOP; 这也是学习 Spring 的重点所在;
Spring 不是针对某个具体功能, 具体层级的框架; 也就是说以前该有的系统分层, 结构, 设计模式都不需要改变, 而是让 Spring 加入进来, 让开发变得更简单; 记住 Spring 并不想取代某个已存在的框架, 反而可以让各个框架的配合使用难度降低, 它就像 502 胶水, 可快速的在系统中集成其他优秀的框架
Spring 也因其特性而得名, 寓意为 JavaEE 开发的春天来了
为什么需要 Spring
之前的课程中我们知道, EJB 是 JavaEE 规范中的一个, 主要用于开发分布式应用程序
从概念上来看:
Spring 是一个框了架, 框架是帮你实现了一部分功能的半成品
而 EJB 是一个规范, 用来规范 (指导) 开发者, 如何去实现 JavaEE 程序
所以这个问题其实是在问 Spring(框架)和 JavaEE(规范)的对比, 而因为两者不是同一种概念, 所以无法直接对比, 那到底在对比啥? 不能在卖关子了;
问题应该是: 使用 Spring 开发和完全按照 JavaEE 规范开发应用程序的区别
这个问题应该由 Spring 的作者 Rod Johnson 来回答:
#Rod Johnson 在 2002 年编写的《Expert One-to-One J2EE Design and Development》一书, Rod 在本书中对 J2EE 正统框架臃肿, 低效, 脱离现实的种种学院派做法提出了质疑, 并以此书为指导思想, 编写了 interface21 框架, 也就是后来的 Spring.
的确推出 Spring 推出就是民间开发者对官方规范的中不足的地方提出的质疑以及做出的强力回应, 在早期阶段, 开发者们经历了拥抱到抛弃, 从最早的 JavaEE 这一官方协议推出后, 开发者们非常拥戴, 毕竟是官方嘛, 后来慢慢发现这堆复杂, 晦涩, 学习成本极高的规范是多么的臃肿不堪, 就像你为了打一只小鸟而搬出了战斗机; 就在这时候 Spring 框架应运而生, 因其轻量级, 使用简单很快受到了大家的喜爱;
好在官方也意识到了问题, 于是在 EJB3.0 做出了大量的改进, 并借鉴了 Spring 中一些非常优秀的特性, 但如日中天的 Spring 好像并没有受到太大的影响, 大家一如既往的喜爱 Spring;
EJB 容器 IoC 容器
另一方面因为 Spring 具备 ICO 容器, 可以帮助我们管理 Bean, 而 EJB 的需要放在 EJB 容器中才能使用其提供的功能; EJB 主要用于提供分布式能力, 而 IoC 容器是帮助我们更好的解耦
Spring 的优点
Spring 对 JavaEE 中的一些 API(JDBC,JavaMail, 远程调用等), 提供了封装, 使这些 API 使用难度降低;
一站式框架, 可简单快速的集成其他框架;
IoC, 利用依赖注入, 极大的降低各组件间的耦合, 提高整体扩展性;
AOP(面向切面)编程的支持, 可以方便的对程序进行权限拦截, 运行监控等;
声明式事务支持, 通过配置就可以完成对事务的管理, 无序进行手动编程;
容器化, Spring 包含并管理应用对象的配置和生命周期, 你可以配置每个 bean 如何被创建以及 bean 是一个单独的实例或者每次需要时都生成一个新的实例, 以及它们是如何相互关联的.
IoC,DI
概念
控制反转(Inversion of Control, 缩写为 IoC), 是面向对象编程中的一种设计原则, 可以用来减低计算机代码之间的耦合度.
将原本由程序实现的一部分逻辑反过来交给系统来完成就称之为控制反转
其中最常见的方式叫做依赖注入 (Dependency Injection, 简称 DI) 通过控制反转, 可以说, 依赖被注入到对象中.
依赖注入是实现控制反转的一种手段;
为何需要 IoC
举个例子: 自己搭配组装机, 需要考虑各种部件的兼容性, 和自己的性能的要求, 如 CPU, 内存, 显卡等等; 但有了专门的组装机服务器商(IoC 容器), 你只要告诉他你的基本需求, 比如, 要一台吃鸡电脑, 剩下的就交给服务商去做了;
大多数应用程序, 都是有很多不同对象彼此合作来完成业务逻辑, 这导致在获取一个合作对象时, 必须显示的去 new 一个对象, 这将就导致代码高度耦合并且难以维护和调试. 像下面这样
- public class Controller {
- @Test
- public void doGet() throws Exception {
- // 这里需要依赖 Service 层
- UserService service = new UserService("参数 1","参数 2");
- }
当需要更换其他业务逻辑实现类时就不得不修改源代码, 并且若 Service 的实例化需要参数时, Controller 层就不得不为其提供必要的参数, 这反映了 Controller 与 Service 的耦合度是较高的
Spring 体系结构
core, 提供了框架基础组成部分, 包括 IoC 和 DI;
beans, 提供了 BeanFactory, 是工厂模式的实现, 提供普通对象和单例对象的获取
context, 建立在 core 和 bean 的基础上, 可将其他库集成到 Spring 中
SpEL(spring-expression Language)提供了表达式语言支持, 其对 JSP 中的 EL 进行了扩展
AOP, 提供了面向切面编程实现
Aspects 模块提供了与 AspectJ 的集成, 是一个功能强大且成熟的 AOP 框架
Instrumentation 用于代理监控 JVM 运行的 JAVA 程序, 对字节码修改以实现 AOP
Messaging 模块为 STOMP 提供了支持, 主要处理来自 webSocket 客户端的 STOMP 信息
强调:
Spring 是模块化的, 完全可以根据需要来导入所需模块
使用入门
传统写法
先来看一个不使用 Spring 时, 控制和业务逻辑层交互的案例, 控制器:
- public class Controller {
- @Test
- public void doGet() throws Exception {
- // 这里需要依赖 Service 层
- //v1 直接写
- //UserService service = new UserService();
- //v2 面向接口 某个实现类
- //UserService service = new UserServiceImpl();
- // 要跟换其他实现类时 违反了 OCP(开放封闭)原则
- //UserService service = new UserServiceImpl2();
- //v3 为避免修改源代码扩展 加入工厂
- ServiceFactory factory = new ServiceFactory();
- UserService service = factory.getService();
- // 调用业务方法
- service.userLogin("jerry","admin");
- }
- }
工厂:
- public class ServiceFactory {
- public UserService getService() throws Exception {
- // 此处 id 应配置在 xml 中
- String id = "UserServiceImpl";
- if (id.equals("UserServiceImpl")){
- return new UserServiceImpl();
- }else if(id.equals("UserServiceImpl2")){
- return new UserServiceImpl2();
- }
- throw new Exception("id:"+id + "not register");
- }
- }
使用工厂模式可以进一步降低组件间的耦合度, 但在完整的系统中有很多组件, 需要很多个工厂, 使程序变得复杂, 臃肿;
Spring 将自身设计为一个大型对象工厂, 负责管理系统中设计到的所有对象, 并利用 DI 处理对象的依赖关系, 当对象 A 需要对象 B 时不再自己创建而是从 Spring 中获取
补充说明: OCP
叫做开放封闭原则, 是应用程序开发中应该遵循的一个原则
open: 对扩展开放
close: 对修改源代码封闭
其目的是要在不修改源代码的情况下对已有功能进行扩展
使用 Spring
1. 创建 Maven 项目
2. 添加依赖
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-context</artifactId>
- <version>5.2.2.RELEASE</version>
- </dependency>
- <!-- Maven 会自动下载所有 Spring 核心容器和 aop 的依赖 -->
3. 创建配置文件
通常名为: applicationContext.xml 当然你也可以修改放在 resources 下
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- https://www.springframework.org/schema/beans/spring-beans.xsd">
- <!-- 使用 bean 标签, 创建 Service 对象, 并交给容器来管理 -->
- <bean id="UserService1" class="com.yyh.serviceimpl.UserServiceImpl"/>
- <bean id="UserService2" class="com.yyh.serviceimpl.UserServiceImpl2"/>
- </beans>
名称空间声明可到官网查找, 或是直接在 jar 中查找, 如:
4. 从 Spring 中获取需要的对象
- @Test
- public void doGetUseSpring() throws Exception {
- // 创建应用上下文 指定配置文件
- ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
- // 从 Spring 中获取所需对象
- UserService userService = (UserService)context.getBean("UserService2");
- // 调用业务逻辑方法
- userService.userLogin("jerry","admin");
- }
不难看出此时的 Spring 就是一个对象工厂, 但这仅仅 Spring 的基础功能
IoC 容器
容器可以理解为存放对象的地方, 当然不仅仅是存储, 还有对象的管理, 包括 - 创建 - 销毁 - 装配; 这样原本程序要做的事情交给了 Spring, 所以这属于 IoC, 称之为 IoC 容器;
Spring 有两个接口 ApplicationContext 是 BeanFactory 的子接口. 它们都可以作为 Spring 的容器;
两种容器的区别:
BeanFactory 作为顶级接口主要面向于 Spring 框架本身, 仅提供了基础基本的容器功能如 DI
ApplicationContext, 是 BeanFactory 的子接口, 意味着功能比 BeanFactory 更多, 诸如国际化, 注解配置, xml 配置等等
BeanFactory 采取的懒加载的方式, 在获取对象时才会实例化
ApplicationContext 会在工厂初始化时立即实例化对象
ApplicationContext 的两个实现类区别:
ClassPath 表示从类路径中获取配置文件
FileSystem 表示从文件系统获取配置文件
来源: https://www.cnblogs.com/yangyuanhu/p/12150153.html