Spring学习(一)Spring概述 IOC容器和bean的配置
1、Spring概述
1.1、什么是Spring?
-
Spring 是一个开源框架.
-
Spring 为简化企业级应用开发而生. 使用 Spring 可以使简单的 JavaBean 实现以前只有 EJB 才能实现的功能.
-
Spring 是一个 IOC(DI) 和 AOP 容器框架.
-
Spring优良的特性
- 轻量:Spring 是非侵入性的 基于Spring开发的应用中的对象可以不依赖于Spring的API
- 依赖注入:DI——Dependency Injection,反转控制(IOC)最经典的实现。
- 面向切面编程:Aspect Oriented Programming——AOP
- 容器:Spring是一个容器,因为它包含并且管理应用对象的生命周期
- 框架:Spring实现了使用简单的组件配置组合成一个复杂的应用。在 Spring 中可以使用XML和Java注解组合这些对象。
- 一站式:在IOC和AOP的基础上可以整合各种企业应用的开源框架和优秀的第三方类库(实际上Spring 自身也提供了表述层的SpringMVC和持久层的Spring JDBC)。
-
Spring模块
1.2、Spring的第一个HelloWorld程序
这里是用maven建的项目导入Spring相关的依赖 maven帮我们自动下载(若不是用maven建的则自己导入Spring相关的jar包)
<dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.6.RELEASE</version>
</dependency>
</dependencies>
创建一个User实体类
public class User {
private String name;
public User() {
}
public User(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void show(){
System.out.println("我的名字叫:"+name);
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
}
注意每次写这种实体类时 最好把无参构造方法写上
Spring配置文件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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 使用bean元素定义一个由IOC容器创建的对象 -->
<!--id:指定用于引用bean实例的标识-->
<!--class:指定用于创建bean的全类名 -->
<bean id="User" class="com.song.pojo.User">
<property name="name" value="王五"></property>
</bean>
</beans>
测试
public static void main(String[] args) {
//创建IOC容器对象
ApplicationContext Context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
//根据id值获取bean实例对象
User user = (User) Context.getBean("User");
user.show();
}
2、IOC容器和Bean配置
2.1、IOC和DI
-
IOC(Inversion of Control):反转控制。
其思想是反转资源获取的方向. 传统的资源查找方式要求组件向容器发起请求查找资源. 作为回应, 容器适时的返回资源. 而应用了 IOC 之后, 则是容器主动地将资源推送给它所管理的组件, 组件所要做的仅是选择一种合适的方式来接受资源. 这种行为也被称为查找的被动形式
-
DI(Dependency Injection):依赖注入。
IOC 的另一种表述方式:即组件以一些预先定义好的方式(例如: setter 方法)接受来自如容器的资源注入.相对于 IOC 而言,这种表述更直接
2.2、在 Spring 的 IOC 容器里配置 Bean
- 在 Spring IOC 容器读取 Bean 配置创建 Bean 实例之前, 必须对它进行实例化. 只有在容器实例化后, 才可以从 IOC 容器里获取 Bean 实例并使用.
- Spring 提供了两种类型的 IOC 容器实现.
–BeanFactory: IOC 容器的基本实现.
–ApplicationContext: 提供了更多的高级特性. 是 BeanFactory 的子接口.
–BeanFactory 是 Spring 框架的基础设施,面向 Spring 本身;ApplicationContext 面向使用 Spring 框架的开发者,几乎所有的 应用场合都直接使用 ApplicationContext 而非底层的 BeanFactory
–无论使用何种方式, 配置文件时相同的.
2.2.1、ApplicationContext
-
ApplicationContext 的主要实现类:
–ClassPathXmlApplicationContext:从 类路径下加载配置文件
–FileSystemXmlApplicationContext: 从文件系统中加载配置文件
-
ConfigurableApplicationContext 扩展于 ApplicationContext,新增加两个主要方法:refresh() 和 close(), 让 ApplicationContext 具有启动、刷新和关闭上下文的能力
-
ApplicationContext 在初始化上下文时就实例化所有单例的 Bean。
-
WebApplicationContext 是专门为 WEB 应用而准备的,它允许从相对于 WEB 根目录的路径中完成初始化工作
2.2.1、环境搭配置测试
建一个学生基本信息实体类
public class Student {
private String name;//姓名
private Integer age;//年龄
private String books[];//上课的书籍 一个数组
private CourseTeacher courseTeacher; //每门课老师的姓名
private List<String> hobbys;//爱好
private Map<String,String> card;//每个学生的所在地邮政编号
private Set<String> games;//喜欢的游戏
private String girlfriend;//是否有女朋友
private Properties info;
public String getName() {
return name;
}
//等下用来测试构造方法注入的
public Student(String name) {
this.name = name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String[] getBooks() {
return books;
}
public void setBooks(String[] books) {
this.books = books;
}
public CourseTeacher getCourseTeacher() {
return courseTeacher;
}
public void setCourseTeacher(CourseTeacher courseTeacher) {
this.courseTeacher = courseTeacher;
}
public List<String> getHobbys() {
return hobbys;
}
public void setHobbys(List<String> hobbys) {
this.hobbys = hobbys;
}
public Map<String, String> getCard() {
return card;
}
public void setCard(Map<String, String> card) {
this.card = card;
}
public Set<String> getGames() {
return games;
}
public void setGames(Set<String> games) {
this.games = games;
}
public String getGirlfriend() {
return girlfriend;
}
public void setGirlfriend(String girlfriend) {
this.girlfriend = girlfriend;
}
public Properties getInfo() {
return info;
}
public void setInfo(Properties info) {
this.info = info;
}
public Student() {
}
//若写courseTeacher.toString()则要把CourseTeacher中属性值写上 不然会出现空指针异常
@Override
public String toString() {
return "Student{" +
"姓名='" + name + '\'' +
", 年龄=" + age +
", books=" + Arrays.toString(books) +
", courseTeacher=" + courseTeacher +
", 爱好=" + hobbys +
", card=" + card +
", games=" + games +
", girlfriend='" + girlfriend + '\'' +
", info=" + info +
'}';
}
}
//每门课程老师的名字
public class CourseTeacher {
private String math;
private String chinese;
private String english;
public CourseTeacher() {
}
public CourseTeacher(String math, String chinese, String english) {
this.math = math;
this.chinese = chinese;
this.english = english;
}
public String getMath() {
return math;
}
public void setMath(String math) {
this.math = math;
}
public String getChinese() {
return chinese;
}
public void setChinese(String chinese) {
this.chinese = chinese;
}
public String getEnglish() {
return english;
}
public void setEnglish(String english) {
this.english = english;
}
@Override
public String toString() {
return "CourseTeacher{" +
"math='" + math + '\'' +
", chinese='" + chinese + '\'' +
", english='" + english + '\'' +
'}';
}
}
基本注入
<!--常量注入-->
<bean id="User" class="com.song.pojo.User">
<property name="name" value="李四"></property>
</bean>
测试
@Test
public void test01(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = (User) context.getBean("User");
System.out.println(user);
}
引用其它 Bean注入
<!--引用其他bean 使用ref-->
<bean id="CourseTeacher" class="com.song.pojo.CourseTeacher">
<property name="chinese" value="语文老师"></property>
<property name="math" value="数学老师"></property>
<property name="english" value="英语老师"></property>
</bean>
<bean id="student2" class="com.song.pojo.Student">
<property name="name" value="小黄"></property>
<property name="courseTeacher" ref="CourseTeacher"></property>
</bean>
测试
@Test
public void test02(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Student student = (Student) context.getBean("student2");
System.out.println(student);
}
数组注入
<!--数组注入-->
<bean id="student3" class="com.song.pojo.Student">
<property name="books">
<array>
<value>Java入门到精通</value>
<value>go入门到精通</value>
<value>C++入门到精通</value>
<value>数据结构与算法</value>
</array>
</property>
</bean>
List注入
<!--List注入-->
<bean id="student4" class="com.song.pojo.Student">
<property name="hobbys">
<list>
<value>打篮球</value>
<value>看动漫</value>
<value>听歌</value>
</list>
</property>
</bean>
map注入
<!--Map注入-->
<bean id="student5" class="com.song.pojo.Student">
<property name="card">
<map>
<entry key="广州" value="1334"></entry>
<entry key="湖北" value="43346"></entry>
</map>
</property>
</bean>
set注入
<bean id="student6" class="com.song.pojo.Student">
<property name="games">
<set>
<value>王者荣耀</value>
<value>CF</value>
<value>吃鸡</value>
</set>
</property>
</bean>
null注入
<property name="girlfriend"><null/></property>
Propertise注入
<bean id="student7" class="com.song.pojo.Student">
<property name="info">
<props>
<prop key="学号">20190604</prop>
<prop key="系别">信息工程系</prop>
<prop key="专业">软件工程</prop>
</props>
</property>
</bean>
构造方法注入
<bean id="student7" class="com.song.pojo.Student">
<constructor-arg index="0" value="小张" ></constructor-arg>
</bean>
索引值指定参数位置
综合使用
<bean id="student8" class="com.song.pojo.Student">
<constructor-arg value="小张" index="0"></constructor-arg>
<property name="age" value="18"></property>
<property name="books">
<array>
<value>Java入门到精通</value>
<value>go入门到精通</value>
<value>C++入门到精通</value>
<value>数据结构与算法</value>
</array>
</property>
<property name="courseTeacher" ref="CourseTeacher"></property>
<property name="hobbys">
<list>
<value>打篮球</value>
<value>看动漫</value>
<value>听歌</value>
</list>
</property>
<property name="card">
<map>
<entry key="广州" value="1334"></entry>
<entry key="湖北" value="43346"></entry>
</map>
</property>
<property name="games">
<set>
<value>王者荣耀</value>
<value>CF</value>
<value>吃鸡</value>
</set>
</property>
<property name="info">
<props>
<prop key="学号">20190604</prop>
<prop key="系别">信息工程系</prop>
<prop key="专业">软件工程</prop>
</props>
</property>
<property name="girlfriend"><null/></property>
</bean>
//测试结果
Student{
姓名='小张',
年龄=18,
books=[Java入门到精通, go入门到精通, C++入门到精通, 数据结构与算法],
courseTeacher=CourseTeacher{math='数学老师', chinese='语文老师', english='英语老师'},
爱好=[打篮球, 看动漫, 听歌],
card={广州=1334, 湖北=43346},
games=[王者荣耀, CF, 吃鸡],
girlfriend='null',
info={学号=20190604, 专业=软件工程, 系别=信息工程系}
}
还有一种工厂方法注入 用得少
2.3、bean的高级配置
-
配置信息的继承
-
配置信息的继承
Spring允许继承bean的配置,被继承的bean称为父bean。继承这个父bean的bean称为子bean
子bean从父bean中继承配置,包括bean的属性配置
子bean也可以覆盖从父bean继承过来的配置
-
父bean可以作为配置模板,也可以作为bean实例。若只想把父bean作为模板,可以设置的abstract 属性为true,这样Spring将不会实例化这个bean
如果一个bean的class属性没有指定,则必须是抽象bean
并不是元素里的所有属性都会被继承。比如:autowire,abstract等。
也可以忽略父bean的class属性,让子bean指定自己的类,而共享相同的属性配置。但此时abstract必须设为true
2.3.1、bean之间的依赖
有的时候创建一个bean的时候需要保证另外一个bean也被创建,这时我们称前面的bean对后面的bean有依赖
依赖关系不等于引用关系
2.3.2、bean的作用域
在Spring中,可以在元素的scope属性里设置bean的作用域,以决定这个bean是单实例的还是多实例的。
默认情况下,Spring只为每个在IOC容器里声明的bean创建唯一一个实例,整个IOC容器范围内都能共享该实例:所有后续的getBean()调用和bean引用都将返回这个唯一的bean实例。该作用域被称为singleton,它是所有bean的默认作用域。
当bean的作用域为单例时,Spring会在IOC容器对象创建时就创建bean的对象实例。而当bean的作用域为prototype时,IOC容器在获取bean的实例时创建bean的实例对象。
2.3.3、bean的生命周期
-
Spring IOC容器可以管理bean的生命周期,Spring允许在bean生命周期内特定的时间点执行指定的任务。
-
Spring IOC容器对bean的生命周期进行管理的过程:
-
在配置bean时,通过init-method和destroy-method 属性为bean指定初始化和销毁方法
- 通过构造器或工厂方法创建bean实例
- 为bean的属性设置值和对其他bean的引用
- 调用bean的初始化方法
- bean可以使用了
- 当容器关闭时,调用bean的销毁方法
-
bean的后置处理器
- bean后置处理器允许在调用初始化方法前后对bean进行额外的处理
- bean后置处理器对IOC容器里的所有bean实例逐一处理,而非单一实例。其典型应用是:检查bean属性的正确性或根据特定的标准更改bean的属性。
- bean后置处理器时需要实现接口:org.springframework.beans.factory.config.BeanPostProcessor。在初始化方法被调用前后,Spring将把每个bean实例分别传递给上述接口的以下两个方法:
- postProcessBeforeInitialization(Object, String)
- postProcessAfterInitialization(Object, String)
5.添加bean后置处理器后bean的生命周期
- 通过构造器或工厂方法**创建****bean实例
- 为bean的属性设置值和对其他bean的引用
- 将bean实例传递给bean后置处理器的postProcessBeforeInitialization()方法
- 调用bean的初始化方法
- 将bean实例传递给bean后置处理器的postProcessAfterInitialization()**方法
- bean可以使用了
- 当容器关闭时调用bean的销毁方法
2.3.4、xml中实现自动装配
自动装配的概念:
- 手动装配:以value或ref的方式明确指定属性值都是手动装配。
- 自动装配:根据指定的装配规则,不需要明确指定,Spring自动将匹配的属性值注入bean中。
装配模式:
- 根据类型自动装配将类型匹配的bean作为属性注入到另一个bean中。若IOC容器中有多个与目标bean类型一致的bean,Spring将无法判定哪个bean最合适该属性,所以不能执行自动装配
- 根据名称自动装配:必须将目标bean的名称和属性名设置的完全相同
- 通过构造器自动装配:当bean中存在多个构造器时,此种自动装配方式将会很复杂。建议多使用注解(@autowire)实现自动装配
若想了解更多的Spring建议查看 Spring官网
谢谢大家的阅读! 若上面有写错的 欢迎纠正哦!