Spring(一)——简介、IOC(控制反转)、DI(依赖注入)
Ⅰ、简介
即——Spring框架是一个轻量级、一站式、企业级应用、模块化、非侵入式的框架。
轻量级:其实代码量很大,但是因为它是模块化的框架,所以说它是轻量级框架;
一站式:一步到位,提供全方位服务,spring提供开发整个web企业项目所需要的所有模块;
企业级应用:企业JavaWeb项目开发;
非侵入式:不会因为引入spring框架而影响已经写好的业务逻辑。
相关模块
Ⅱ、核心容器IOC 0
一、简述
控制反转(Inversion of control),自定义类的权力交给IOC容器,由spring容器来创建类,从而降低类与类之间的联系,松耦合性。
1、管理流程是什么样的?
创建实例——>初始化实例——>容器中获取实例——>使用
2、哪些实例对象需要交给IOC?
全局实例对象,需要放在容器中。服务器关闭时,自动销毁(应用在javaWeb中,类似域对象Application(ServletContext),整个服务器内有效,服务器关闭时失效)。
3、spring整合其他框架是什么意思?
将其他框架(工具类)交给IOC管理。
初次接触spring IOC,下面使用案例来说明
pom.xml
<!--测试springIOC,3个jar包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.1.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.1.7.RELEASE</version>
</dependency>
StudentDaoImpl.java
public class StudentDaoImpl implements StudentDao {
@Override
public void insertStudent() {
System.out.println("添加学生成功");
}
}
springConfig.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"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<bean id="studentDao" class="com.hbw.dao.StudentDaoImpl"></bean>
</beans>
测试
@Test
public void test1(){
//使用IOC提供的API读取配置文件,完成初始化实例
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("springConfig.xml");
//获取实例,并使用
StudentDao studentDao = (StudentDao) applicationContext.getBean("studentDao");
studentDao.insertStudent();
}
二、IOC中常用的API 0
BeanFactory:核心API,提供了创建并管理所有实例。
*ApplicationContext:是BeanFactory的子接口,提供了创建并管理(生命周期),程序员自定义的所有实例。
其中三个实现类:
*ClassPathXMlApplication:根据类路径(Resources、Classes文件夹)解析配置文件,初始化容器(实例化)。
FileSystemXMlApplication:根据文件路径(D://…)解析配置文件。
AnnotationConfigApplication:通过读取注解配置,初始化容器。
提供close方法,但是不会手动调用,全局对象在服务器关闭时自动销毁(应用在javaWeb中类似域对象Application(ServletContext),整个服务器内有效,服务器关闭时失效)。
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("springConfig.xml");
三、IOC原理
1)????使用一般的实例化,当该类发生变化时,实例化的地方都需要改变TestDaoImpl tdi = new TestDaoImpl();
。耦合性高。
2)????使用接口编程的思想实例化,当该类发生改变时,只需要改变TestDao td = new TestDaoImpl();
实例化的一部分。耦合性较高。
3)????使用第三方类(工厂类)实例化需要的类TestDao td = new TestFactory().getTestDaoImpl()
,当实例化的类发生改变时,只需要修改工厂里面的部分内容即可。
TestFactory.java
public class TestFactory {
public StudentDao getStudentDaoImpl(){
return new StudentDaoImpl();
}
}
测试
@Test
public void test2(){
StudentDao studentDao = new TestFactory().getStudentDaoImpl();
studentDao.insertStudent();
}
4)????上分使用工厂类只能创建一种类,需要创建其他类时,又需要创建新的工厂,效率比较低。所以创建一个生产任意类的工厂,但是在使用该工厂实例化时,需要传入需要实例化类的全类名(反射)进行硬编码,使用时比较麻烦(每次都要传入全类名)。
TestFactory.java
/*获取任意实例*/
public Object getObjectImpl(String impl){
Object object = null;
try {
//获取字节码文件
Class clazz = Class.forName(impl);
//实例化
object = clazz.newInstance();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
return object;
}
StudentTest.java
/*获取任意类型的工厂*/
@Test
public void tes3(){
StudentDao studentDao = (StudentDao) new TestFactory().getObjectImpl("com.hbw.dao.StudentDaoImpl");
studentDao.insertStudent();
}
5)????通过属性配置文件或者xml进行实例化。
student.properties配置文件
studentDao=com.hbw.dao.StudentDaoImpl
TestFactory.java
根据配置文件的key,获取值,实例化并存放在map集合中
/*最终工厂*/
//用于存放实例化的类
Map<String,Object> map;
public TestFactory(String config) {
//初始化map集合
map = new HashMap<>();
//使用jdk自带的ApI解析配置文件
ResourceBundle resourceBundle = ResourceBundle.getBundle(config);
//获取配置文件中的所有key,返回类型是枚举类型
Enumeration<String> enumeration = resourceBundle.getKeys();
//根据key获取所有的值
while (enumeration.hasMoreElements()){
//获取每一个key
String key = enumeration.nextElement();
//获取key对应的value
String value = resourceBundle.getString(key);
try {
Class clazz = Class.forName(value);
Object object = clazz.newInstance();
//将实例化的类,存放在map集合中
map.put("studentDao",object);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
}
}
/*提供供外部获取实例的方法*/
public Object getObjectImplEnd(String impl){
return map.get(impl);
}
测试
/*最终版工厂*/
@Test
public void test4(){
//扫描属性配置文件student.properties
TestFactory testFactory = new TestFactory("student");
//从map集合中,根据键获取值
StudentDao studentDao = (StudentDao) testFactory.getObjectImplEnd("studentDao");
studentDao.insertStudent();
}
编码规则——约束优于配置,配置优于编码;高内聚,低耦合。
总结——IOC也是采取类似的措施(肯定复杂狠多啦),扫描xml或者属性文件进行创建实例
四、IOC XML配置文件 0
使用<bean></bean>
标签
1、通过构造方法实例化
<bean id="studentDao" class="com.hbw.dao.StudentDaoImpl"></bean>
2、通过普通工厂类提供的方法实例化
<bean id="ordinaryFactory" class="com.hbw.util.TestFactory"></bean>
<bean id="ordinaryFactoryOne" factory-bean="ordinaryFactory" factory-method="getStudentDaoImpl"></bean>
3、通过静态工厂类提供的方法实例化(需要提供一个静态方法)
<bean id="staticFactory" class="com.hbw.util.TestFactory" factory-method="getStaticStudentDaoImpl"></bean>
属性 0
id(唯一标识)、name属性(取别名),同一个配置文件中不可重复;多个配置文件中可重复,后解析的覆盖先解析的
init-method属性,指定初始化内容(不管程序员有没有使用那个bean,解析xml配置文件时,都会自动初始化)
destory-method属性,指定销毁方法(spring不会主动调用销毁方法,容器(Tomcat)关闭时,自动调用)
scope属性,指定创建的实例对象的作用范围
*Singleton:默认。以单例模式创建实例,实例作用范围在整个应用当中(调用一次获取一次,不会重复创建)。
prototype:以多例模式创建实例,但是不会管理该实例,实例范围在当前大括号内(局部变量一样,调用一次创建一个)
*单例模式实例是启动Tomcat时就初始化好了(只有一个);多例模式实例是程序员获取时才创建。
Request:创建的实例作用范围只在一次请求内有效
Session:创建的实例作用范围只在一次会话中有效
globalSession:用于分布式项目,表示作用范围在全局session中
下列对多例模式进行测试,单例模式改一下属性值即可
springConfig.xml
<bean id="studentDao" class="com.hbw.dao.StudentDaoImpl" scope="prototype"></bean>
TestStudent.java
@Test
public void test1(){
//使用IOC提供的API读取配置文件,完成初始化实例
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("springConfig.xml");
//获取实例,并使用
StudentDao studentDao = (StudentDao) applicationContext.getBean("studentDao");
System.out.println(studentDao);
StudentDao studentDao1 = (StudentDao) applicationContext.getBean("studentDao");
System.out.println(studentDao1);
studentDao.insertStudent();
}
结果
Ⅲ、核心容器DI
依赖注入(DI:dependency injection),前提——该类提供了 有参构造或set方法。
从容器中获取实例,自动将一个对象注入到另一个对象中(构造注入、setter注入,就是传递参数,初始化实体类)。
setter注入使用<property>
标签、构造注入使用<constructor-arg>
标签
下列对Student实体类进行初始化
Student实体类有如下属性
private int sid;
private String sname;
private Book book;
private Double[] heightWeight;
private List<Book> bookList;
private Set<Book> bookSet;
private Map<String,Book> bookMap;
1)使用Setter注入
<bean id="book" class="com.hbw.bean.Book">
<property name="bid" value="1"></property>
<property name="bname" value="小学数学上册"></property>
</bean>
<bean id="student" class="com.hbw.bean.Student">
<property name="sid" value="1"></property>
<property name="sname" value="张三"></property>
<property name="book" ref="book"></property>
<property name="heightWeight">
<array>
<value>175.0</value>
<value>120.1</value>
</array>
</property>
<property name="bookList">
<list>
<bean class="com.hbw.bean.Book">
<property name="bid" value="2"></property>
<property name="bname" value="小学语文上册"></property>
</bean>
<bean class="com.hbw.bean.Book">
<property name="bid" value="3"></property>
<property name="bname" value="小学英语上册"></property>
</bean>
</list>
</property>
<property name="bookSet">
<set>
<bean class="com.hbw.bean.Book">
<property name="bid" value="4"></property>
<property name="bname" value="小学美术上册"></property>
</bean>
</set>
</property>
<property name="bookMap">
<map>
<entry key="bookid" value-ref="book"></entry>
</map>
</property>
</bean>
2)使用构造注入
<!--通过构造注入-->
<bean id="book" class="com.hbw.bean.Book">
<property name="bid" value="1"></property>
<property name="bname" value="小学数学上册"></property>
</bean>
<bean id="studentConstructor" class="com.hbw.bean.Student">
<constructor-arg name="sid" value="2"></constructor-arg>
<constructor-arg name="sname" value="李四"></constructor-arg>
<constructor-arg name="book">
<bean id="book" class="com.hbw.bean.Book">
<!--Book中每没有给有参构造方法,只能使用settter注入-->
<property name="bid" value="1"></property>
<property name="bname" value="小学数学上册"></property>
</bean>
</constructor-arg>
<constructor-arg name="heightWeight">
<array>
<value>165.05</value>
<value>80.90</value>
</array>
</constructor-arg>
<constructor-arg name="bookList">
<list>
<bean id="book" class="com.hbw.bean.Book">
<property name="bid" value="2"></property>
<property name="bname" value="小学语文上册"></property>
</bean>
</list>
</constructor-arg>
<constructor-arg name="bookSet">
<set>
<bean id="book" class="com.hbw.bean.Book">
<property name="bid" value="3"></property>
<property name="bname" value="小学美术"></property>
</bean>
</set>
</constructor-arg>
<constructor-arg name="bookMap">
<map>
<entry key="book" value-ref="book"></entry>
</map>
</constructor-arg>
</bean>
依赖注入总结
依赖注入——依赖IOC容器,资源由IOC注入到应用程序中
一、不同点
setter注入
0)前提,该类中提供了set方法
1)setter注入使用<property></property>
标签
构造注入
0)前提,该类中提供了有参构造方法(有参构造中的所有参数,都必须初始化)
1)setter注入使用<constructor-arg></constructor-arg>
标签
二、相同点
1)普通类型参数的值,直接使用value属性进行赋值;
2)引用类型的参数赋值,两种:
使用ref属性,其值需要现在外面使用<bean>标签进行初始化,在通过id引入进来
<bean id="book" class="com.hbw.bean.Book">
<property name="bid" value="1"></property>
<property name="bname" value="小学数学上册"></property>
</bean>
<property name="book" ref="book"></property>
在其中直接使用<bean>标签进行赋值
<constructor-arg name="book">
<bean id="book" class="com.hbw.bean.Book">
<!--Book中每没有给有参构造方法,只能使用settter注入-->
<property name="bid" value="1"></property>
<property name="bname" value="小学数学上册"></property>
</bean>
</constructor-arg>
3)数组类型使用arry标签
<constructor-arg name="heightWeight">
<array>
<value>165.05</value>
<value>80.90</value>
</array>
</constructor-arg>
4)list、set、map使用<set><list><map>
标签,其中map集合赋值使用entry标签(key属性就是键名,value-ref属性就是其键对应的值)
<bean id="book" class="com.hbw.bean.Book">
<property name="bid" value="1"></property>
<property name="bname" value="小学数学上册"></property>
</bean>
<constructor-arg name="bookList">
<list>
<bean id="book" class="com.hbw.bean.Book">
<property name="bid" value="2"></property>
<property name="bname" value="小学语文上册"></property>
</bean>
</list>
</constructor-arg>
<constructor-arg name="bookSet">
<set>
<bean id="book" class="com.hbw.bean.Book">
<property name="bid" value="3"></property>
<property name="bname" value="小学美术"></property>
</bean>
</set>
</constructor-arg>
<constructor-arg name="bookMap">
<map>
<!--value-ref是引入的上方的book实例-->
<entry key="book" value-ref="book"></entry>
</map>
</constructor-arg>
上一篇: Spring IoC与DI(依赖注入)
下一篇: CSAPP实验-datalab
推荐阅读
-
Java:控制反转(IoC)与依赖注入(DI)
-
Spring 框架学习第三节:核心理念之一 —— IoC(控制反转)
-
个人对【依赖倒置(DIP)】、【控制反转(IOC)】、【依赖注入(DI)】浅显理解
-
ASP.NET MVC 中 Autofac依赖注入DI 控制反转IOC 了解一下
-
大话DI依赖注入+IOC控制反转(一) 之 定义
-
ASP.NET Core依赖注入系列教程之控制反转(IoC)
-
依赖注入(DI)和控制反转(IoC)的理解
-
Spring中的IOC(控制反转)是什么意思?简单理解一下
-
在Spring IoC中,依赖注入和依赖查找的数据来源一样吗?
-
Spring IOC DI依赖注入 IOC容器 Spring Bean的声明周期