一、Spring概述
- Spring 是轻量级的开源的 JavaEE 框架
- Spring 可以解决企业应用开发的复杂性
- Spring 有两个核心部分:IoC 和 AOP
(1)IoC:(Inversion of Control) 指控制反转或反向控制。在Spring框架中我们通过配置创建类对象,由Spring在运行阶段实例化、组装对象。(把创建对象过程交给 Spring 进行管理)
(2)AOP:(Aspect Oriented Programming)面向切面编程,其思想是在执行某些代码前执行另外的代码,使程序更灵活、扩展性更好,可以随便地添加、删除某些功能。Servlet中的Filter便是一种AOP思想的实现 - Spring 特点:
(1)方便解耦,简化开发
(2)AOP 编程支持
(3)方便程序测试
(4)方便和其他框架进行整合
(5)方便进行事务操作
(6)降低 API 开发难度
二、入门案例
-
下载 Spring5
-
打开 idea 工具,创建普通 Java 工程
-
导入 Spring5 相关 jar 包,并添加依赖
Spring核心容器:
因此我们需要导入上面四个包,另外我们还需要一个管理日志的包commons-logging.jar
建一个lib目录,复制jar包进来——>FILE——>Project Structure——>Modules——>Dependencies——>"+"——>JARs or directories——>添加需要的jar包依赖
-
创建普通类,在这个类创建普通方法
public class User {
public void hello(){
System.out.println("hello world");
}
}
- 创建 Spring 配置文件,在配置文件配置创建的对象
Spring 配置文件使用 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">
<!--配置User对象创建-->
<!--id:唯一标识(别名) class:全类名-->
<bean id="user" class="com.fox.bean.User"></bean>
</beans>
- 进行测试代码编写
import com.fox.bean.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
public static void main(String[] args) {
//1 加载 spring 配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
//2 获取配置创建的对象
User user = context.getBean("user", User.class);
System.out.println(user);
user.hello();
}
}
三、IoC详解
(一)概念和原理
1.什么是IoC
- IoC(Inversion of Control) 指控制反转或反向控制。在Spring框架中我们通过配置创建类对象,由Spring在运行阶段实例化、组装对象。(把创建对象过程交给 Spring 进行管理)
- 使用 IoC 目的:为了降低耦合度
- 什么是反转?
反转是相对于正向而言的,那么什么算是正向的呢?考虑一下常规情况下的应用程序,如果要在A里面使用C的方法,你会怎么做呢?当然是直接去创建C的对象,也就是说,是在A类中主动去获取所需要的外部资源C,这种情况被称为正向的。那么什么是反向呢?就是A类不再主动去获取C,而是被动等待,等待IoC的容器获取一个C的实例,然后反向的注入到A类中。
2.IoC底层原理
IoC是通过xml解析、工厂模式、反射共同实现的
(1)什么是工厂模式
该模式用于封装和管理对象的创建,是一种创建型模式。工厂模式的本质就是用工厂方法代替new操作创建一种实例化对象的方式。工厂模式可以降低耦合度。一句话中总结就是方便创建同种类型接口产品的复杂对象。
案例:
假如我们需要在一个类的方法中调用另一个类的方法,那么原始方式如下:
我们会发现,这样的方式,两个类的耦合度十分高,那么我们可以利用工厂模式进行优化:
耦合度是不能完全消除的,只能最大限度降低耦合度
(2)为什么要用工厂模式
- 解耦:把对象的创建和使用的过程分开。假如Class A 想调用 Class B ,而A只是想调用B的方法,至于B的实例化,就交给工厂类。
- 降低代码重复:如果创建某个对象的过程都很复杂,需要一定的代码量,而且很多地方都要用到,那么就会有很多的重复代码。
- 降低维护成本:由于创建过程都由工厂统一管理,所以发生业务逻辑变化,不需要找到所有需要创建某个对象的地方去逐个修正,只需要在工厂里修改即可,降低维护成本。
(3)理解IoC底层原理
举个不恰当的例子:就像找女朋友,如果我们自己找,就要想办法认识她们,投其所好送其所要,我们必须自己设计和面对每个环节,充满了耦合;而IoC就类似婚介帮我们找女朋友,婚介会按照我们的要求,提供一个女生,我们只需要去和她谈恋爱、结婚就行了。
(二) IoC 容器两种接口
IoC 思想基于 IoC 容器完成,IoC 容器底层就是对象工厂
Spring 提供了 IoC 容器两种实现方式:(两种接口)
(1)BeanFactory:IoC 容器基本实现,是 Spring 内部的使用接口,不提供开发人员进行使用
//加载 spring 配置文件
BeanFactory context = new ClassPathXmlApplicationContext("bean1.xml");
(2)ApplicationContext:BeanFactory 接口的子接口,提供更多更强大的功能,一般由开发人员进行使用
//加载 spring 配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
BeanFactory和ApplicationContext最大的区别:
- 用BeanFactory加载配置文件时候不会创建对象,在获取(使用)对象时才去创建对象
- 用ApplicationContext加载配置文件时候就会把在配置文件的对象进行创建
- 你可能会觉得要用时才创建的Beanfactory节省资源,但是还是推荐ApplicationContext,因为它可以在Tomcat服务器启动时(最耗时耗资源的阶段)把创建对象的工作给一并解决
ApplicationContext 接口有两个常用的实现类:
如果你的xml配置文件是在本地某盘符下,就可以用FileSystemXmlApplicationContext加载配置文件,而如果你的xml配置文件就在本项目的src下,就可以用ClassPathXmlApplicationContext加载配置文件。
(三)Bean管理
1.什么是 Bean 管理
- Bean 管理指的是两个操作:
- Spring 创建对象
- Spring 注入属性
- Bean 管理操作有两种方式:
- 基于 xml 配置文件方式实现
- 基于注解方式实现
2.基于xml配置文件方式实现Bean管理
(1)创建对象
<bean id="user" class="com.fox.bean.User"></bean>
- 在 spring 配置文件中,使用 bean 标签,标签里面添加对应属性,就可以实现对象创建
- 在 bean 标签中有很多属性,其中常用的属性:
- id 属性:唯一标识(别名)
- class 属性:类全路径
- name属性:类似id属性,但它可以包含特殊字符如“/”(name属性是早期为Structs1使用的,现在用得少)
- 创建对象时候,默认也是执行无参构造方法完成对象创建
(2)注入属性
在讲注入属性前,我们要先了解一个概念:DI(Dependency Injection),依赖注入
①什么是DI(依赖注入)
- 是指spring框架在创建bean对象时,动态的将依赖对象注入到bean组件中。组件之间依赖关系由容器在运行期决定,形象的说,依赖注入即由容器动态地将某个依赖关系注入到组件之中。通过依赖注入机制,我们只需要通过简单的配置,而无需任何代码就可指定目标需要的资源,完成自身的业务逻辑,而不需要关心具体的资源来自何处,由谁实现。
- 理解DI的关键是:“谁依赖谁,为什么需要依赖,谁注入谁,注入了什么”,那我们来深入分析一下:
- 谁依赖于谁:当然是对象依赖于IoC容器;
- 为什么需要依赖:对象需要IoC容器来提供对象需要的外部资源;
- 谁注入谁:很明显是IoC容器注入应用程序某个对象
- 注入了什么:就是注入某个对象所需要的外部资源(包括对象、资源、常量数据)。
②IoC和DI的区别:
- 控制反转就是对对象控制权的转移,从程序代码本身反转到了外部容器。把对象的创建、初始化、销毁等工作交给spring容器来做。由spring容器控制对象的生命周期。即是将new 的过程交给spring容器去处理;
DI依赖注入是指程序运行过程中,若需要调用另一个对象协助时,无须在代码中创建被调用者,而是依赖于外部容器,由外部容器创建后传递给程序。依赖注入是目前最优秀的解耦方式。依赖注入让Spring的Bean之间以配置文件的方式组织在一起,而不是以硬编码的方式耦合在一起的。 - DI是IoC中一种具体实现,DI的实现依赖于IoC,先有控制反转才有依赖注入(依赖注入需要在创建对象的基础上才能进行)。相对IoC 而言,“依赖注入”明确描述了“被注入对象依赖IoC容器配置依赖对象”。
- IoC模式太普遍,任何框架都是IoC,为了让表意更明确,决定用DI来精确指称这个模式。
举个不恰当的例子:
IoC ioc = the_pattern;
DI di = (DI)ioc;
显然,说the_pattern是IoC或DI都行。但严格说IoC.class == DI.class
肯定不为真,两者还是有区别,是is a
的关系。
③第一种注入属性方式:使用 set 方法进行注入
1、创建类,定义属性和对应的 set 方法
public class Book {
//创建属性
private String bname;
private String bauthor;
//创建属性对应的 set 方法
public void setBname(String bname) {
this.bname = bname;
}
public void setBauthor(String bauthor) {
this.bauthor = bauthor;
}
@Override
public String toString() {
return "Book{" +
"bname='" + bname + '\'' +
", bauthor='" + bauthor + '\'' +
'}';
}
}
2、在 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.xsd">
<bean id="book" class="com.fox.bean.Book">
<!--使用 property 完成属性注入
name:类里面属性名称
value:向属性注入的值
-->
<property name="bname" value="Java从入门到放弃"></property>
<property name="bauthor" value="小明"></property>
</bean>
</beans>
3、测试类
import com.fox.bean.Book;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
public static void main(String[] args) {
//1 加载 spring 配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
//2 获取配置创建的对象
Book book = context.getBean("book", Book.class);
System.out.println(book);
}
}
④第二种注入属性方式:使用有参数构造进行注入
1、创建类,定义属性,创建属性对应的有参构造方法
public class Book {
//创建属性
private String bname;
private String bauthor;
//创建属性对应的有参构造方法
public Book(String bname,String bauthor){
this.bname=bname;
this.bauthor=bauthor;
}
@Override
public String toString() {
return "Book{" +
"bname='" + bname + '\'' +
", bauthor='" + bauthor + '\'' +
'}';
}
}
2、在 spring 配置文件中进行配置
配置了constructor-arg组件以后,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.xsd">
<bean id="book" class="com.fox.bean.Book">
<constructor-arg name="bname" value="Java从入门到放弃"></constructor-arg>
<constructor-arg name="bauthor" value="小明"></constructor-arg>
<!-- 也可以用index取代name,index="0"代表此类的第一个属性,以此类推:-->
<!-- <constructor-arg index="0" value="Java从入门到放弃"></constructor-arg>-->
<!-- <constructor-arg index="1" value="小明"></constructor-arg>-->
</bean>
</beans>
3、测试类
import com.fox.bean.Book;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
public static void main(String[] args) {
//1 加载 spring 配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
//2 获取配置创建的对象
Book book = context.getBean("book", Book.class);
System.out.println(book);
}
}
⑤p名称空间注入(了解)
这个其实也是set方法进行注入的一种简化形式
1、创建类,定义属性和对应的 set 方法
public class Book {
//创建属性
private String bname;
private String bauthor;
//创建属性对应的 set 方法
public void setBname(String bname) {
this.bname = bname;
}
public void setBauthor(String bauthor) {
this.bauthor = bauthor;
}
@Override
public String toString() {
return "Book{" +
"bname='" + bname + '\'' +
", bauthor='" + bauthor + '\'' +
'}';
}
}
2、我们需要添加 p 名称空间到配置文件中
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="book" class="com.fox.bean.Book" p:bname="Java从入门到放弃" p:bauthor="小明">
</bean>
</beans>
3、测试类
import com.fox.bean.Book;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
public static void main(String[] args) {
//1 加载 spring 配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
//2 获取配置创建的对象
Book book = context.getBean("book", Book.class);
System.out.println(book);
}
}
⑥xml 注入其他类型属性
Ⅰ.注入字面量
1)注入null值:
<?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">
<bean id="book" class="com.fox.bean.Book">
<property name="bname" value="Java从入门到放弃"></property>
<!--给属性设置空值-->
<property name="bauthor">
<null/>
</property>
</bean>
</beans>
2)注入包含特殊符号的属性值:
需求:书名需要添加<<>>
这个特殊符号
- 方式一,利用转义字符:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi=