一、SpringIOC 的介绍与学习
1.SpringIOC的介绍
问题:
在使用MVC的结构体系来完成后台功能代码的声明时,在一定程度上降低了代码的冗余,但是层与层之间的耦合性过高,造成代码升级维护特别麻烦,比如,某天业务层某个类文件需要替换为新的类文件,那么,控制层所有调用该业务类的代码需要全部修改为调用新的业务类.
解决:
将层与层对象之间的关系进行解耦,由直接变为间接.
实现:
SpringIOC.作用:实现了代码层与层之间的解耦.
2.SpringIOC的原理
3. SpringIOC的使用
1. 作用:
IOC将耦合性非常高的对象进行解耦.
2. 时机:
什么时候使用IOC对对象进行解耦是一个主观问题,应当根据代码的结构以及功能的需求进行分析,然后决定哪些对象之间需要使用IOC解耦.一般情况下,在MVC代码结构中,会将Servlet和Service之间解耦,Service和mapper之间解耦.
3. 使用流程:
①创建Maven的war项目然后配置web的相关依赖以及项目结构的配置
注意:
如果我们使用Idea重新创建一个新的工作空间,则需要重新完成Maven的 集成。集成步骤参照Maven的知识。

②在pom.xml文件中配置SpringIOC的依赖

<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.bjsxt</groupId>
<artifactId>01_SpringIOC_BaseUse</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<!--配置版本号-->
<properties>
<servlet-version>3.1.0</servlet-version>
<jsp-version>2.2</jsp-version>
<jstl-version>1.2</jstl-version>
</properties>
<!--配置依赖-->
<dependencies>
<!--配置SpringIOC的依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.11.RELEASE</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.3</version>
</dependency>
<!--配置web开发相关的依赖-->
<!--servlet的资源坐标-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>${servlet-version}</version>
<scope>provided</scope>
</dependency>
<!--jsp的资源坐标-->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>${jsp-version}</version>
<scope>provided</scope>
</dependency>
<!--jstl的资源坐标-->
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>${jstl-version}</version>
</dependency>
</dependencies>
<!--配置tomcat插件-->
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<port>8080</port><!--配置tomcat启动的端口号-->
<path>/ioc</path><!--配置项目的访问名称-->
</configuration>
</plugin>
</plugins>
</build>
</project>
③在resources下创建并配置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 id="us" class="com.bjsxt.service.impl.UserServiceImpl2"></bean>
</beans>
④在业务层中创建UserService接口及其实现类
UserService接口:
package com.bjsxt.service;
public interface UserService {
//声明功能方法
String testIOCService();
}
UserServiceImpl实现类:
package com.bjsxt.service.impl;
import com.bjsxt.service.UserService;
public class UserServiceImpl implements UserService {
//测试IOC
@Override
public String testIOCService() {
return "SpringIOC Study";
}
}
⑤在项目中创建MVC的包结构,并创建IOCServlet,并在Service方法中获取Spring的容器对象,并从容器对象中获取业务层对象,完成业务操作。
package com.bjsxt.controller;
import com.bjsxt.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/ioc")
public class IOCServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置请求编码格式
//设置响应编码格式
//获取请求信息
//处理请求
//创建Spring的容器对象
ApplicationContext ac=new ClassPathXmlApplicationContext("applicationcontext.xml");
//获取容器中的业务层对象
UserService us = (UserService) ac.getBean("us");
//处理请求
String s = us.testIOCService();
//响应结果
resp.getWriter().write(s);
}
}
二、SpringIOC创建对象的三种方式
1. 问题及解决
问题:
在学习了SpringIOC的基本使用流程后,我们使用IOC解耦层与层之间的逻辑关系,但是我们发现,对象由以前我们自己根据需求在代码中直接new创建,变为从Spring容器中获取,也就说对象的创建由Spring容器来创建,我们直接获取使用即可.那么,如果我们需要一个带有指定的初始化数据的对象,如何让Spring容器对象帮我们创建呢?
解决:
在applicationcontext.xml配置文件中,配置对象的创建方式以及初始化的方式.
2. 通过构造器方式
①无参数构造器(创建一个没有初始化数据的对象)
②有参 数构造器(创建一个带有初始化数据的对象)
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">
<!--创建student的bean对象-->
<!--构造器方式-->
<!--
无参构造器
特点:Spring容器默认使用无参构造方式创建对象
使用:在配置文件中直接使用bean标签配置即可,无需过多声明
-->
<bean id="stu" class="com.bjsxt.pojo.Student"></bean>
<!--有参数的构造器
特点:Spring容器对根据配置调用的有参构造器创建一个带有初始化数据的对象
使用:constructor-arg:使用bean的字标签来声明调用的构造器的形参的个数
一个字标签表示一个参数
属性:index:参数的下标
type:参数的类型,全限定路径
name:参数的形参名
value:参数要给的值
-->
<bean id="stu2" class="com.bjsxt.pojo.Student">
<constructor-arg index="0" type="java.lang.Integer" name="sid" value="1"></constructor-arg>
<constructor-arg index="1" type="java.lang.String" name="sname" value="张三"></constructor-arg>
</bean>
</beans>
TestObject代码示例:
package com.bjsxt.controller;
import com.bjsxt.pojo.Student;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class testStu {
public static void main(String[] args) {
//创建容器对象
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationcontext.xml");
//获取容器中的对象
//无参构造器方式
Student student = (Student) ac.getBean("stu");
System.out.println("无参构造:"+student);
//有参构造器
Student student1= (Student) ac.getBean("stu2");
System.out.println("有参构造:"+student1);
}
}
3.通过属性注入(get/set)
先通过空构造器创建一个对象,然后再使用set方法进行初始化赋值.
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">
<!--创建student的bean对象-->
<!--
属性注入方式
特点:相当于创建一个空对象然后使用set方法赋值
使用:
property:在bean标签下使用子标签property,表示调用set方法给某个属性赋值
属性:name:要赋值的属性名
value:值
-->
<bean id="stu3" class="com.bjsxt.pojo.Student">
<property name="sid" value="2"></property>
<property name="sname" value="李四"></property>
</bean>
</beans>
TestObject代码示例:
package com.bjsxt.controller;
import com.bjsxt.pojo.Student;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author wuyw2020
* @date 2020/1/8 15:16
*/
public class testStu {
public static void main(String[] args) {
//创建容器对象
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationcontext.xml");
//获取容器中的对象
//属性注入方式
Student student = (Student) ac.getBean("stu3");
System.out.println("属性注入方式"+student);
}
}
4. 通过工厂模式
问题:
我们在使用Java代码处理某个问题的时候,需要创建A对象,调用 A对象中的某个方法,但是A对象的创建依赖B对象,而B对象的创建又依赖于C对象,C对象的创建又依赖于D对象…,如下:
D d=new D();
C c=new C(d);
B b=new B©;
A a=new A(b);
这样造成,代码的阅读性极差
解决:
将对象的创建过程进行封装,直接返回创建好的对象使用.
实现:
工厂设计模式
本质:
就是封装对象的创建过程的一种代码的编程思想
静态工厂:
生产对象的方法是静态方法
public class AFactory{
public static A newInstance(){
D d=new D();
C c=new C(d);
B b=new B(c);
A a=new A(b);
return a;
}
}
动态工厂:
生产对象的方法是非静态方法
public class AFactory{
public A newInstance(){
D d=new D();
C c=new C(d);
B b=new B(c);
A a=new A(b);
return a;
}
}
SpringIOC使用工厂创建对象:
传统方案:
我们自己创建工厂,然后调用工厂生产对象的方法,获取生产的对象,然后使用生产的对象完成功能开发.
IOC方案:
Spring容器创建工厂,并自动调用其创建的工厂的生产对象的方法,生产的对象直接存储在Spring容器中,我们直接从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 http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--创建student的bean对象-->
<!--工厂设计模式-->
<!--动态工厂-->
<bean id="factory" class="com.bjsxt.pojo.StudentFactory"></bean>
<!--生产Student对象-->
<bean id="stu4" factory-bean="factory" factory-method="newIntance"></bean>
<!--静态工厂-->
<!--可以理解为静态方法直接用类名调用-->
<bean id="stu5" class="com.bjsxt.pojo.StudentFactory2" factory-method="newIntance"></bean>
</beans>
TestObject示例:
package com.bjsxt.controller;
import com.bjsxt.pojo.Student;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class testStu {
public static void main(String[] args) {
//创建容器对象
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationcontext.xml");
//获取容器中的对象
//工厂设计模式
//动态工厂
Student student = (Student) ac.getBean("stu4");
System.out.println("动态工厂:"+student);
//静态工厂
Student student1 = (Student) ac.getBean("stu5");
System.out.println("静态工厂:"+student1);
}
}
三、IOC的依赖注入DI
1. 依赖注入DI的介绍
问题:
在学习了使用IOC创建对象的三种方式后,可以根据需求在applicationcontext.xml文件中配置对象的创建方式.但是目前不管是属性注入方式,还是构造器方式,创建对象的时候,赋值赋予的都是基本类型的数据.但是对象中还有引用类型的属性,比如A对象中有属性B,我希望从Spring容器中获取一个B属性有值的A对象,怎么办?
对象之间的依赖关系:
我们在设计类对象时,会在类中声明其他类类型的属性,来调用其他类的资源完成当前类的功能处理,比如A类中声明B属性,在A类中就可以直接调用B类的资源完成A类的功能开发,但是A 对象被创建时,其B属性必须有值,否则空指针异常,我们将此种也就是A和B的关系称为对象之间的依赖关系(A依赖B).
依赖链:
对象之间项目依赖形成的一条链式依赖关系.
D d=new D();
C c=new C(d);
B b=new B©;
A a=new A(b);
A<—B<----C<----D
解决:
让Spring容器根据对象之间的依赖关系,将依赖责任连上的所有的对象全部配置为Bean对象.并且根据依赖关系完成对象之间的组装.将组装好的对象返回给用户使用.
概念:
DI依赖注入:就是Spring容器根据对象之间的依赖关系完成对象的创建以及组装的过程.
2… DI依赖注入的代码实现
- 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">
<!--
DI依赖的使用流程
①将依赖责任链上的所有的对象都配置为bean
②根据依赖关系完成对象之间的组装配置
通过构造器方式:
i.必须在类中声明对应的构造器
ii.在bean标签下使用constructor-arg子标签完成以来注入
使用constructor-arg的属性ref,ref的值为要注入的bean的ID
通过set方法方式
i.必须在类中声明引用属性对应的set方法
ii.在bean标签下使用property子标签完成以来注入
在property子标签中使用ref属性,属性值为要被注入的bean的ID
-->
<!--配置学生bean对象-->
<bean id="stu" class="com.bjsxt.pojo.Student">
<!--构造器方式-->
<!--<constructor-arg index="0" name="teacher" type="com.bjsxt.pojo.Teacher" ref="tea" ></constructor-arg>-->
<!--set方式-->
<property name="teacher" ref="tea"></property>
<property name="sname" value="张三"></property>
<property name="sid" value="1"></property>
</bean>
<bean id="tea" class="com.bjsxt.pojo.Teacher">
<property name="tid" value="2"></property>
<property name="tname" value="刘老师"></property>
</bean>
</beans>
- TestIocDI代码示例
package com.bjsxt.contorller;
import com.bjsxt.pojo.Student;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author wuyw2020
* @date 2020/1/8 20:04
*/
public class TestIocDI {
public static void main(String[] args) {
//获取spring对象
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationcontext.xml");
Student stu = (Student) ac.getBean("stu");
System.out.println(stu);
stu.testStu();
}
}