SpringIOC
spring必知必会
1.问题的讨论
在讲解spring框架之前,我们先引入一个思考,目前我们实现一个功能的基本流程如下:
① 创建一个web项目
② 创建数据库
③ 使用jsp技术完成页面的创建
④ 使用Servlet+MVC+Mybatis完成功能开发。
但是在目前的流程中,代码的执行流程如下:
重复的代码需要我们在不同的功能中,重复编写,极大的影响了开发的效率,怎么办?
不同的功能重复的代码不再重复声明,只声明功能相关的代码即可。也就说重复的代码我们虽然不写了,但是JDK在执行的时候这部分重复的代码仍然是存在的,执行的是重复的+自己的。
① 不同的方法中出现了重复代码-->将重复代码封装为工具方法,然后在自己的方法中调用工具方法,同时声明自己的代码。
② 不同的类中出现了重复的代码--->封装工具类
③ 不同的项目出现了重复代码--->封装jar包
那么什么是jar包呢?
jar包的本质:其实就是代码的class文件的压缩包,jdk可以直接调用无需解压。
jar包的使用:将jar包资源放入到项目中后,需要add as library.
jar包的特点:在项目中引入其他已经完成的代码的同时,保证项目原有代码的结构层次。
2.框架的概念和使用
1.框架的概念
不同的项目会使用相同的代码进行开发。而这部分代码如果要进行封装不是一个类或者一个方法就能搞定的,需要封装出来很多的类文件,于是为了方便其他人使用,我们再次将这些代码封装为jar包,所以,框架其实就是不用的项目都会使用的代码的封装,软件的半成品。
2.框架的本质:
就是别人封装好的功能代码。
3.框架的具体表现形式:
一堆jar包:封装好了都要使用的代码。
4.框架的使用:
① 将jar包导入到自己的项目中
② 查阅API文档,调用jar包中的资源完成功能开发
③ 配置框架的配置文件(框架代码运行需要的常量数据)
数据和代码的解耦,使用者可以通过配置问价来自定义数据。
5.框架的学习:
就是使用别人的代码完成自己的功能开发。其实就是学习如何使用别人的代码。想当于javaSE阶段学习常用类。
3.Spring框架的介绍
概念:Spring是一个控制反转(IOC)和面向切面的(AOP)的轻量级框架.
使用范围:任何java程序.
作用:
①简化企业项目的开发的流程.提升开发效率
②便于代码的后期维护升级.
③将代码之间的耦合性降低.
内容:
SpringIOC的使用
SpringAOP的使用
SpringTX的使用
注意:
Spring是一个框架集,内部集成了很多的功能,可以根据需求 选择对应的子框架使用.
Spring框架的结构:
Test层:Spring提供测试功能.
Core Container层:Spring启动最基本条件。
-
Beans: Spring 负责创建类对象并管理对象。
-
core:核心类。
-
context:上下文参数,获取外部资源或管理注解。
-
SpEL:expression.jar(Expression Language)
注:spring启动需要的4个jar包。
Aop:实现aop功能需要依赖
Aspects:切面Aop依赖的包
Data Access/Integartion:Spring封装数据访问层相关内容
-
JDBC:Spring对JDBC封装后的代码
-
ORM:封装了持久层框架的代码,比如:Hibernate。
-
TranSactions:对应Spring-tx.jar声明事务时使用。
Web:需要Spring完成web相关功能时需要
比如:由tomcat加载Spring配置文件时需要由Spring-web包。tomcat是servlet容器。
Spring发明人:Rod Johnson
4.SpringIOC的介绍和学习
中文名称:控制反转 英文名:Inversion of control
在使用MVC的结构体系来完成后台功能代码的声明时,在一定程度上降低了代码的冗余,但是层与层之间的耦合性过高,造成代码升级维护特别麻烦,比如,某天业务层某个类文件需要替换为新的类文件,那么,控制层所有调用该业务类的代码需要全部修改为调用新的业务类.
IOC是什么呢?
-
IOC完成的事情原先由程序员主动通过new实例化的对象的事情转交给Spring负责。
-
控制反转中控制指的是:控制类的对象
-
控制反转中反转指得是:转交给spring负责。
-
IOC最大的作用:解耦。程序员不需要管理对象,解除了对象管理和程序员的耦合。实现了层与层之间对象的逻辑性的解耦。
5.SpringIOC的基本使用
1.作用:
IOC将耦合性非常高的对象进行解耦.
2.时机:
什么时候使用IOC对对象进行解耦是一个主观问题,应当根据代码的结构以及功能的需求进行分析,然后决定哪些对象之间需要使用IOC解耦.一般情况下,在MVC代码结构中,会将Servlet和Service之间解耦,Service和mapper之间解耦.
3.基本使用流程:
- 导入IOC的jar包
- 在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
https://www.springframework.org/schema/beans/spring-beans.xsd>
<!--配置业务层的对象-->
<bean id="us" class="com.bjsxt.service.impl.ServiceImpl"></bean>
</beans>
- 在代码中创建ApplicationContext对象,并获取Spring容器中的对象,然后完成功能开发
6.SpringIOC创建对象的三种方式
在学习了SpringIOC的基本使用流程后,我们使用IOC解耦层与层之间的逻辑关系,但是我们发现,对象由以前我们自己根据需求在代码中直接new创建,变为从Spring容器中获取,也就说对象的创建由Spring容器来创建,我们直接获取使用即可.那么,如果我们需要一个带有指定的初始化数据的对象,如何让Spring容器对象帮我们创建呢?
在applicationContext.xml配置文件中,配置对象的创建方式以及初始化的方式.
1.通过构造器方式
- 无参数构造器(创建一个没有初始化数据的对象)
- 有参数构造器(创建一个带有初始化数据的对象)
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.pojo.Student"></bean>
<!--有参数的构造器
特点:Spring容器对根据配置调用的有参构造器创建一个带有初始化数据的对象
使用:constructor-arg:使用bean的字标签来声明调用的构造器的形参的个数
一个字标签表示一个参数
属性:index:参数的下标
type:参数的类型,全限定路径
name:参数的形参名
value:参数要给的值
-->
<bean id="stu2" class="com.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>
Test代码示例:
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);
}
}
2.通过属性注入(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.pojo.Student">
<property name="sid" value="2"></property>
<property name="sname" value="李四"></property>
</bean>
</beans>
TestObject代码示例:
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);
}
}
3.通过工厂模式
问题:
我们在使用Java代码处理某个问题的时候,需要创建A对象,调用 A对象中的某个方法,但是A对象的创建依赖B对象,而B对象的 创建又依赖于C对象,C对象的创建又依赖于D对象.....,如下:
D d=new D();
C c=new C(d);
B b=new B(c);
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.pojo.StudentFactory"></bean>
<!--生产Student对象-->
<bean id="stu4" factory-bean="factory" factory-method="newIntance"></bean>
<!--静态工厂-->
<!--可以理解为静态方法直接用类名调用-->
<bean id="stu5" class="com.pojo.StudentFactory2" factory-method="newIntance"></bean>
</beans>
TestObject代码示例:
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);
}
}
7.IOC的依赖注入DI
- 依赖注入DI的介绍
问题:
在学习了使用IOC创建对象的三种方式后,可以根据需求在applicationContext.xml文件中配置对象的创建方式.但是目前不管是属性注入方式,还是构造器方式,创建对象的时候,赋值赋予的都是基本类型的数据.但是对象中还有引用类型的属性,比如A对象中有属性B,我希望从Spring容器中获取一个B属性有值的A对象,怎么办?
对象之间的依赖关系:
我们在设计类对象时,会在类中声明其他类类型的属性,来调用其他类的资源完成当前类的功能处理,比如A类中声明B属性,在A类中就可以直接调用B类的资源完成A类的功能开发,但是A对象被创建时,其B属性必须有值,否则空指针异常,我们将此种也就是A和B的关系称为对象之间的依赖关系(A依赖B).
当一个类(A)中需要依赖另一个类(B)对象时,把B赋值给A的过程就叫依赖注入。
依赖责任链:
对象之间项目依赖形成的一条链式依赖关系.
D d=new D();
C c=new C(d)
B b=new B(c);
A a=new A(b);
A<---B<----C<----D
解决:
让Spring容器根据对象之间的依赖关系,将依赖责任连上的所有的对象全部配置为Bean对象.并且根据依赖关系完成对象之间的组装.将组装好的对象返回给用户使用.
概念:
DI:依赖注入,就是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">
<!--
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.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.pojo.Teacher">
<property name="tid" value="2"></property>
<property name="tname" value="刘老师"></property>
</bean>
</beans>
TestObject代码示例:
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();
}
}