Spring 是指 SpringFramework,就是 Spring 框架,可以让 Java企业级 的应用程序开发起来更简单。有一句话概括起来就是:Spring 是包含了众多工具方法的 IoC 容器。容器就是容纳某种物品的装置。像 List/Map 就是数据存储的容器。Tomcat 就是 web容器。
IoC 就是 Inversion of Control ,就是 “控制反转” 。控制反转 是两个词:控制+反转。指的是:之前程序的控制权限是在我们自己手上,现在,我们把这个控制权交出去了。
比如说要构造一辆车,传统方法是从车身开始构造,如下图:
就是需要先构造车身,然后车身又需要底盘,然后底盘有需要轮胎,这样一套走完之后,一辆车才算是构造完成.
代码示例如下:
public class NewCar {
public static void main(String[] args) {
Car car = new Car();
car.init();
}
/**
* 汽车对象
*/
static class Car {
public void init() {
// 依赖车身
Framework framework = new Framework();
framework.init();
}
}
/**
* 车身类
*/
static class Framework {
public void init() {
// 依赖底盘
Bottom bottom = new Bottom();
bottom.init();
}
}
/**
* 底盘类
*/
static class Bottom {
public void init() {
// 依赖轮胎
Tire tire = new Tire();
tire.init();
}
}
/**
* 轮胎类
*/
static class Tire {
// 尺寸
private int size = 30;
public void init() {
System.out.println("轮胎尺寸:" + size);
}
}
}
运行结果如下:
但是上面这样的代码的耦合性会很高。假如不同的用户,对车子轮胎的大小有不同的要求,那么就需要去修改轮胎尺寸,就是通过用户输入去改变参数,但是会影响整个业务的调用链:
如果要增加一个轮胎颜色,那么改了 轮胎的参数之后,上面的调用类,也得继续修改对轮胎的调用类。
也就是说,如果想要添加一个功能,全部程序就需要修改。这就是传统开发的弊端。
控制反转之后,就是把 关于对象的创建 的权限交给 Spring:
代码示例如下:
public class NewCar {
public static void main(String[] args) {
Tire tire = new Tire(50, "红色");
Bottom bottom = new Bottom(tire);
Framework framework = new Framework(bottom);
Car car = new Car(framework);
car.run();
}
static class Car {
private Framework framework;
public Car(Framework framework) {
this.framework = framework;
}
public void run() {
framework.init();
}
}
static class Framework {
private Bottom bottom;
public Framework(Bottom bottom) {
this.bottom = bottom;
}
public void init() {
bottom.init();
}
}
static class Bottom {
private Tire tire;
public Bottom(Tire tire) {
this.tire = tire;
}
public void init() {
tire.init();
}
}
static class Tire {
private int size;
private String color;
public Tire(int size, String color) {
this.size = size;
this.color = color;
}
public void init() {
System.out.println("轮胎:" + size + " | 颜色:" + color);
}
}
}
这样的话,如果要增加功能的话,就只需要对相应的类进行修改就可以了,就极大程度解耦合了。而且 对象 的生命周期就交给 IoC 来维护了。就像自己去餐厅吃饭,只管吃就行,就不用像自己做饭,买这买那很麻烦。
IoC 的创建流程:
控制权就发生了反转。
Spring IoC 容器的核心功能:
DI 是和 IoC 分不开的词,就是 Dependency Injection 的缩写,翻译成中文就是 :依赖注入 的意思。Dependency 和 pom.xml 里面的依赖是一个意思:
就是在 IoC 容器运行期间,动态的将某种以来关系注入到对象之中。所以,依赖注入(DI)和控制反转(IoC)讲的是一个东西,不过是角度不同罢了。
IoC 和 DI 的区别:IoC 是一种思想,DI 是一种实现。就像想要吃好吃的,然后去撸串了。要吃好的就是 IoC,撸串就是 DI。
先创建一个 maven 项目。
a)
直接 Create 就好了。
b)进来之后,就可以创建 Java 类了
添加 Spring 框架支持(spring-context/spring-beans)。
a)在 pom.xml 当作加入依赖:
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.2.3.RELEASE</version>
</dependency>
</dependencies>
粘贴完之后,刷新 maven:
创建一个启动类,并且添加 main :
能运行出来,就说明 Spring 项目创建好了:
现在 Spring 项目中添加配置文件(第一次需要这样做)。要创建一个文件,放到 resources 目录下,我们创建一个名为 spring-config.xml
,然后把下面这段代码粘贴进去就好了:
<?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.xsd">
</beans>
创建一个 Bean 对象。
在配置文件中将需要保存到 Spring 中的 Bean 对象进行注册。在配置文件里面加一个 bean 标签:
<?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.xsd">
<!--将一个对象存储到 spring 容器当中-->
<bean id="user" class="com.beans.User"></bean>
</beans>
意思就是存的 Bean 对象的 id 是 user(可以不等于 class 里面的类名,但这样比较好记和好理解),存的对象 class 是 com.beans.User 。存储的时候,是用 Map 存储的。
先得到 Spring 上下文对象。通过 ApplicationContext 来获取:
public class Test1 {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
}
}
里面的 spring-config.xml 就是配置文件的名字。
再通过上下文对象提供的方法获取咱们需要的 Bean 对象。通过 getBean
来直接获取,需要传递一个 Bean 的名字,Bean 的名字就是我们在配置文件里面的 id:
public class Test1 {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
User user = (User) context.getBean("user");
}
}
这里的 id 和 Bean 对象的名字是一样的。
使用 Bean 对象。直接调用 user 里面的 sayHi 方法就可以了:
public class Test1 {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
User user = (User) context.getBean("user");
user.sayHi("zhangsan");
}
}
除了通过 ApplicationContext 来获取,还可以通过 BeanFactory 来得到 Bean :
public class Test1 {
public static void main(String[] args) {
//得到 bean 工厂
BeanFactory factory = new XmlBeanFactory(new ClassPathResource("spring-config.xml"));
//获取 bean
User user = (User) factory.getBean("user");
//使用 bean
user.sayHi("李四");
}
}
运行结果如下:
ApplicationContext 和 BeanFactory 的区别:
再创建一个 Bean 来验证是否全部加载:
public class Article {
public Article() {
System.out.println("加载了 Article");
}
public void sayHi() {
System.out.println("hello Article");
}
}
并且放到配置文件当中:
然后在 User 对象里面也加一个构造方法:
public class User {
public User () {
System.out.println("加载了 User");
}
public void sayHi(String name) {
System.out.println("你好:"+ name);
}
}
使用 ApplicationContext 运行结果如下:
ApplicationContext 就把对象全部进行了加载。
BeanFactory 运行结果如下:
BeanFactory 就只是把需要的对象加载了。
ApplicationContext 用的更多,所以我们来看 ApplicationContext 提供的 getBean 方法:
也就是我们上面使用的方法:
这种是需要强制类型转换的:
就是在 getBean 的参数里面直接使用 User.class :
public class Test1 {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
User user = context.getBean(User.class);
user.sayHi("张三");
}
}
运行结果如下:
但是如果把一个对象,在 Spring 中注入多次,就会报错了:
就会显示不是唯一的 Bean 对象:
就是在 getBean 当作把 name 和 类型,都写入:
public class Test1 {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
User user = context.getBean("user", User.class);
user.sayHi("张三");
}
}
这样也没有强制类型转换,是要用一个 name 为 user ,类型为 User.class 的 bean 对象。这样的话,就算一个对象被注入多次也没事:
本文的操作流程图,大概就是这样: