Spring 学习笔记
- Spring 学习笔记《准备工作》
- Spring 学习笔记《依赖注入》—— 配置 applicationContext.xml
- Spring 学习笔记《依赖注入》—— 扫描配置文件注入
- Spring 学习笔记《依赖注入》—— 自动注入
目录
自己瞎编
学新工具之前,先学会用,再研究他的实现原理。所谓:好读书,不求甚解;每有会意,欣然忘食。反之容易陷于细节而丢了大局。
资料准备了一大堆,所以这里就写点通俗易懂的东西,以便日后自己查阅。
- 我们学习的技术90%都是为了少写点代码,目前业界公认的思路就是代码重用。
- 为了更好的重用代码,我们总结出许多原则、规则,整理了许多规范(其实就是标出踩过的坑)
- 解耦就是个永恒的话题,你不解耦把代码都写死死的,别人还怎么重用?
- 既然要解耦,那就得增加工作量啦。提取公共的部分,隔离不相干的功能,每一个模块都只专注处理一个问题。
- 面对繁重的劳动,人类当然是靠发明工具来解决啊。难道去提升打字速度吗?
- Spring 就是这样的一系列工具。
- 先说下万恶之源
new
所有的性能开销和耦合都是因他而起(虽然推锅给new
有点违心,我们要申请资源,不new
难道凭空冒出来?) - 好吧退一万步说,我们的目的只是要资源,但怎么获得这些资源,就当是些见不得光的脏活,交给
Spring
去干吧。我的双手要干净。
Spring 做什么?
Spring
的核心就是【依赖注入】其他的功能都是围绕着【依赖注入】来实现具体的想法、解决具体的问题。后面我们会讲 XML
主要就是注入规则。在解释依赖注入
之前我们先看个栗子。
ClassZ z = new ClassZ();
ClassY y = new ClassY(z);
ClassX x = new ClassY(y);
...// 省略 ClassW 到 ClassD 这一串
ClassC c = new ClassC(d);
ClassB b = new ClassB(c);
ClassA a = new ClassA(b);
- 依赖 : 我们需要用到
ClassA
但创建A
需要参数B
,创建B
又要参数C
层层需要下去。。。这种关系就叫依赖
- 注入 : 你要什么对象、不用自己
new
而是Spring
帮你创建b
再塞给a
,这就是注入
- 构造注入:
Spring
通过构造方法塞,就是【构造注入】 - 属性注入:
Spring
通过setXXX() 方法塞,就是【属性注入】
现在有了【依赖注入】
你可以直接向Spring
要ClassA
拿来就用爽吧?那些依赖关系Spring
都帮你办妥了。
但Spring
是怎么知道这些依赖关系的哪?答案就是配置 XML
, 想要什么东西,配置在XML
中Spring
自然会按我们的配置创建好,我们只管跟 Spring
要就行了。所以学习使用Spring
的核心就是学习怎么配置XML
。怎么配?道上有道上的规矩,按规矩来就是了。(插播【控制反转】不要走开,马上回来)
【控制反转】
就是一种思路,通过【依赖注入】
这个手段来实现。
控制好理解,谁在干脏活,就是谁在掌控那些见不得光的事咯。
反转嘛,以前我自己干,默认是正常流程。那现在我不干了,让别人干,把结果给我。相当于流程翻过来了。坐享其成,何乐而不为呢。
我们做什么?
为了解决前面我们看到的那一连串 A
依赖B
,B
又依赖C
的问题,Spring
使出了法宝依赖注入
,怎么注入不能看心情啊,写在代码里当然不行,想灵活写配置文件
啊。因此对新手来说,千言万语不如一个带着注释的applicationContext.xml
这个名字不是强制的,只是个惯例。
- /SpringIoC/src/applicationContext.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
">
<!-- ************* Spring容器创建对象是通过定义<bean>标签来实现的 ************* -->
<!-- 构造器 -->
<!-- 无参构造 -->
<bean id="teacher" class="com.jerry.entity.Teacher" />
<bean id="student" class="com.jerry.entity.Student" />
<!-- 有参构造 -->
<!-- 通过参数列表来确定调用那个构造方法(原理和重载一样),参数顺序 index 形参名字 name 形参类型 type -->
<bean id="teacher2" class="com.jerry.entity.Teacher">
<constructor-arg index="0" name="name" type="String" value="张老强" ></constructor-arg>
<constructor-arg index="1" name="age" type="Integer" value="30" ></constructor-arg>
<constructor-arg index="2" name="adder" type="String" value="南天门8号" ></constructor-arg>
<constructor-arg index="3" name="tel" type="String" value="13838384388" ></constructor-arg>
<constructor-arg index="4" name="salary" type="Double" value="3000.0" ></constructor-arg>
</bean>
<!-- 对象工厂 -->
<!-- 静态工厂 : 直接调用工厂方法,获得生产的对象-->
<bean id="factoryTeacher" class="com.jerry.factory.TeacherFactory" factory-method="getInstance"></bean>
<!-- 动态态工厂 : 1、配置好工厂bean 2、配置学生bean时通过 factory-bean 属性告诉它用哪个工厂 -->
<bean id="studentFactory" class="com.jerry.factory.StudentFactory" ></bean>
<bean id="studentByFactory" class="com.jerry.entity.Student" factory-bean="studentFactory" factory-method="getInstance"/>
<!-- ***************************** 依赖注入 ***************************** -->
<!-- 上面学会了创建对象。下面讲解怎么注入。因为构造器创建对象也可注入值,但是不如 set 灵活。
所以一般我们都是先调用无参构造创建对象,然后 set 属性值 -->
<bean id="textbook" class="com.jerry.entity.Textbook" >
<property name="name" value="思想品德"></property>
<property name="level" value="小学二年级"></property>
</bean>
<!-- ref 引用其他 bean (【教师】依赖【课本】,这就是前面讲的 【A】依赖【B】的情况)-->
<bean id="teacherWithRef" class="com.jerry.entity.Teacher">
<property name="name" value="王大浪"></property>
<property name="age" value="35"></property>
<property name="textbook" ref="textbook"></property>
</bean>
<!-- 如果属性是集合 -->
<bean id="myCollection" class="com.jerry.entity.MyCollection">
<!-- 基础属性 -->
<property name="str" value="我有集合属性,我骄傲"></property>
<!-- 引用属性 : 这个最重要,他就是依赖注入的关键-->
<property name="teacher" ref="teacher"></property>
<property name="student" ref="student"></property>
<!-- 数组 -->
<property name="arr">
<array><!-- 数组用 array -->
<value>111</value>
<value>222</value>
<!-- 嵌套数组 (为了演示嵌套,所以 arr 声明为 Object数组)-->
<array>
<value>333</value>
<value>444</value>
</array>
</array>
</property>
<!-- 列表 -->
<property name="list">
<list>
<value>555</value>
<value>666</value>
</list>
</property>
<!-- map -->
<property name="map">
<map>
<!-- map的值特殊点,要用 entry -->
<entry key="aaa" value="777"></entry>
<entry key="bbb" value="888"></entry>
<!-- 看到 ref 就要联想到引用 -->
<entry key="textbook" value-ref="textbook" ></entry>
</map>
</property>
</bean>
</beans>
- /SpringIoC/src/com/jerry/test/TestSpringIoC.java
package com.jerry.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.jerry.entity.MyCollection;
import com.jerry.entity.Student;
import com.jerry.entity.Teacher;
import com.jerry.entity.Textbook;
public class TestSpringIoC {
public static void main(String[] args) {
// 获取Spring容器
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// ******************* Spring容器创建对象是通过定义<bean>标签来实现的 *********************
// --------------- 构造器方法创建 bean ---------------
// 无参构造
Teacher teacher= (Teacher)context.getBean("teacher");// 从容器中获取对象
System.out.println("无参构造,创建 bean : " + teacher.toString());// 查看结果
// 有参构造
Teacher teacher2= (Teacher)context.getBean("teacher2");// 从容器中获取对象
System.out.println("有参构造,创建 bean : " + teacher2.toString());// 查看结果
// --------------- 工厂方法创建 bean ---------------
// 静态工厂方法创建 bean
Teacher teacherByFactory = (Teacher)context.getBean("factoryTeacher");
System.out.println("静态工厂,创建 bean : " + teacherByFactory);
// 动态态工厂方法创建 bean
Student studentByFactory = (Student)context.getBean("studentByFactory");
System.out.println("动态工厂,创建 bean : " + studentByFactory);
// ********************************** 依赖注入 *************************************
// 无参构造 + 基础属性注入
Textbook textbook= (Textbook)context.getBean("textbook");// 从容器中获取对象
System.out.println("基础属性注入,创建 bean : " + textbook.toString());// 查看结果
// 无参构造 + 引用属性注入
Teacher teacherWithRef= (Teacher)context.getBean("teacherWithRef");// 从容器中获取对象
System.out.println("引用属性注入,创建 bean : " + teacherWithRef.toString());// 查看结果
// 无参构造 + 属性集合注入
MyCollection myCollection= (MyCollection)context.getBean("myCollection");// 从容器中获取对象
System.out.println("集合属性 : " + myCollection.toString());// 查看结果
}
}
看看效果
一月 20, 2019 8:20:17 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@14e8b5fe: startup date [Sun Jan 20 20:20:17 CST 2019]; root of context hierarchy
一月 20, 2019 8:20:17 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [applicationContext.xml]
无参构造,创建 bean : Teacher [name=李老师, age=27, adder=鸟不拉屎村, tel=10086, salary=5000.0, textbook=null]
有参构造,创建 bean : Teacher [name=张老强, age=30, adder=南天门8号, tel=13838384388, salary=10000.0, textbook=null]
静态工厂,创建 bean : Teacher [name=李老师, age=27, adder=鸟不拉屎村, tel=10086, salary=5000.0,
textbook=课本 [name=数学课本, level=大一]]
动态工厂,创建 bean : 同学 [ name=王二狗, age=18, adder=天堂路1号, tel=13866666666, chineseScore=null, mathScore=null, englishScore=null,
textbook=课本 [name=数学课本, level=大一]]
基础属性注入,创建 bean : 课本 [name=思想品德, level=小学二年级]
引用属性注入,创建 bean : Teacher [name=王大浪, age=35, adder=鸟不拉屎村, tel=10086, salary=5000.0,
textbook=课本 [name=思想品德, level=小学二年级]]
集合属性 : 对象含集合属性 [str=我有集合属性,我骄傲, arr=[111, 222, [Ljava.lang.Object;@58d872f5],
list=[555, 666],
map={aaa=777, bbb=888, textbook=课本 [name=思想品德, level=小学二年级]},
teacher=Teacher [name=李老师, age=27, adder=鸟不拉屎村, tel=10086, salary=5000.0, textbook=null],
student=同学 [ name=三毛, age=82, adder=流浪者居无定所, tel=110, chineseScore=null, mathScore=null, englishScore=null,
textbook=null]]
资源文件
所需的jar包,这是POM
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.jerry</groupId>
<artifactId>SpringIoC</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>SpringIoC Maven Webapp</name>
<url>http://maven.apache.org</url>
<properties>
<spring.version>5.1.1.RELEASE</spring.version>
</properties>
<dependencies>
<!-- spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
</dependencies>
<build>
<finalName>SpringIoC</finalName>
</build>
</project>