1. 概述
1.1 Spring Framework是什么
Spring 是最受欢迎的企业级 Java 应用程序开发框架。
Spring 框架是一个开源的 Java 平台,它最初是由 Rod Johnson 编写的,并且于 2003 年 6 月首次在 Apache 2.0 许可下发布。
Spring 是轻量级的框架,其基础版本只有 2 MB 左右的大小。
Spring 框架的核心特性是可以用于开发任何 Java 应用程序,但是在 Java EE 平台上构建 web 应用程序是需要扩展的。 Spring 框架的目标是使 J2EE 开发变得更容易使用,通过启用基于 POJO 的编程模型来促进良好的编程实践。
POJO编程模型就是普通的javabean,它一般用来存储数据对象,每个属性就是一个类型的数据,多个属性合起来就应该数据集。
例如存储MySQL返回的查询结果:
POJO编程模型BooK,Book类中的属性对应数据表中的字段,且每个字段都要get/set方法。像这Book种类就是POJO编程模型。
1.2 为什么使用它
因为Spring Framework优秀的特性:
- 非侵入式:使用 Spring Framework 开发应用程序时,Spring 对应用程序本身的结构影响非常小。对领域模型可以做到零污染;对功能性组件也只需要使用几个简单的注解进行标记,完全不会破坏原有结构,反而能将组件结构进一步简化。这就使得基于 Spring Framework 开发应用程序 时结构清晰、简洁优雅。
- 控制反转:IOC——Inversion of Control,翻转资源获取方向。把自己创建资源、向环境索取资源变成“环境将资源准备好,我们享受资源注入。”
- 面向切面编程:AOP——Aspect Oriented Programming,在不修改源代码的基础上增强代码功 能。
- 容器:Spring IOC 是一个容器,因为它包含并且管理组件对象的生命周期。组件享受到了容器化 的管理,替程序员屏蔽了组件创建过程中的大量细节,极大的降低了使用门槛,大幅度提高了开发 效率。
- 组件化:Spring 实现了使用简单的组件配置组合成一个复杂的应用。在 Spring 中可以使用 XML 和 Java 注解组合这些对象。这使得我们可以基于一个个功能明确、边界清晰的组件有条不紊的搭建超大型复杂应用系统。
- 声明式:很多以前需要编写代码才能实现的功能,现在只需要声明需求即可由框架代为实现。
- 一站式:在 IOC 和 AOP 的基础上可以整合各种企业应用的开源框架和优秀的第三方类库。而且 Spring 旗下的项目已经覆盖了广泛领域,很多方面的功能性需求可以在 Spring Framework 的基础上全部使用 Spring 来实现。
我觉得最重要的就是其通过IoC容器实现充分解耦:
- 在写代码时会出现耦合度偏高的现象,而耦合度偏高就会导致“牵一发而动全身”。
例如:产品第一代版本有如下业务层实现和数据层实现
public class BookServiceImpl implements BookService{
private BookDao bookDao new BookDaoImp1(); //生成数据层类的对象
public void save(){
bookDao.save();
}
}
public class BookDaoImpl implements BookDao
public void save(){
System.out.println("book dao save ...")
}
如果:由于数据的变化需要对数据层代码进行更新,则使数据层BookDaoImpl
变为BookDaoImpl_2
并且新添了参数之类的,这时业务层BookServiceImpl里new的BookDaoImpl
对象也要跟着变化,之后可能整个产品代码都要跟着修改,这样大大消耗了人力物力。
public class BookServiceImpl implements BookService{
//需要根据数据层的变化而更改
private BookDao bookDao new BookDaoImp1_2(int 新参数, spring 新参数);
public void save(){
bookDao.save();
}
}
- 耦合度:业务模块间的耦合度是指模块之间的依赖关系,包括控制关系、调用关系、数据传递关系。模块间联系越多,其耦合性越强,同时表明其独立性越差。
2. 为了将耦合度降低(解耦)就有了如下解决方案:
使用对象时,在程序中不要主动使用new产生对象,转换为由外部提供对象。也就是IoC(Inversion of Control)控制反转。
- IoC:是一种编程思想。使用对象时,由主动new产生对象转换为由外部提供对象,此过程中对象创建控制权由程序转移到外部,此思想称为控制反转。(就是将在业务层里new数据层对象的行为交给别人来做,业务层只需要调用new好的对象即可。)
- Spring的核心容器模块中就实现了这一思想。
Spring提供了一个容器,称为IoC容器,用来充当IoC思想中的外部。
IoC容器负责对象的创建、初始化等一系列工作,被创建或被管理的对象在Ioc容器中统称为Bean。
3. 如果,业务层与数据层的有依赖关系(就如前面业务层里要调用bookDao.save();
就必须要先获取dao对象才行)并且业务层和数据层对象都由IoC容器管理,则IoC容器就会将其进行依赖绑定(DI),就不用在业务层中创建dao的对象了。
DI(Dependency Injection)依赖注入
- 在容器中建立bean与bean之间的依赖关系的整个过程,称为依赖注入。
4. 以上操作都是为了完成一个目标:充分解耦
- 使用IoC容器管理bean(IoC)
- 在IoC容器内将有依赖关系的bean进行关系绑定(DI)
最终效果
- 使用对象时不仅可以直接从IoC容器中获取,并且获取到的bean已经绑定了所有的依赖关系。
1.3 Spring Framework 的模块化
Spring 是模块化的,不同的模块有不同的功能,在使用Spring进行项目开发时,我们也可以根据需要选择引入不同的模块,以满足具体的业务需求。
- Core Container 核心容器,在 Spring 环境下使用任何功能都必须基于 IOC 容器。
- AOP和Aspects 面向切面编程
- Test 提供了对 junit 或 TestNG 测试框架的整合。
- Data Access/Integration 提供了对数据访问/集成的功能。
- Spring MVC 提供了面向Web应用程序的集成功能。
1.4 Spring Framework 入门案例
第一步,先用idea创建一个普通的Maven项目。
第二步,再在pom.xml里导入相应的依赖:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.1</version>
</dependency>
第三步,在src/main/java目录下创建一个类(什么都可以):
package test;
public class MyTestCode {
public void info(){
System.out.println("测试");
}
}
第四步,在src/main/resources目录下配置spring配置文件,并将创建的MyTestCode对象的bean,将其加入Spring的容器里,此时MyTestCode对象就会被Spring管理:
<?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
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd" >
<!--
属性id:javabean的唯一标识
属性class:指定此bean对应的类(全类名)
-->
<bean id="testCode" class="test.MyTestCode"/>
</beans>
然后就可以测试了:
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
public class SpringBeanTest {
public static void main(String[] args) {
//解析配置文件,获取bean
ApplicationContext context = new FileSystemXmlApplicationContext("soring配置文件的文件路径");
//根据id获取bean
MyTestCode code =(MyTestCode) context.getBean("testCode");
code.info();
}
}
运行后发现:明明没有new MyTestCode的对象,但却可以获取到它的对象,并调用方法。这是因为Spring 底层默认通过反射技术调用组件类的无参构造器来创建组件对象,这一点需要注意。如果在需要 无参构造器时,没有无参构造器,则会抛出异常。
如,将MyCodeTest类添加属性,并将构造方法更改为有参构造方法:
public class MyTestCode {
private String name;
public MyTestCode(String name){
this.name=name;
}
public void info(){
System.out.println("测试");
}
}
然后运行就会报错:
警告: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'testCode' defined in file [SpringF\src\main\resources\test.xml]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [test.MyTestCode]: No default constructor found; nested exception is java.lang.NoSuchMethodException: test.MyTestCode.<init>()