✨✨个人主页:沫洺的主页
????????系列专栏: ???? JavaWeb专栏???? JavaSE专栏 ???? Java基础专栏????vue3专栏
????MyBatis专栏
????????如果文章对你有所帮助请留下三连✨✨
????????前言(很重要!!!)
????学习Spring框架(Spring Framework)之前先了解两个思想概念
- ????IOC控制反转: 由Spring帮我们实例化指定的bean(bean就是指Java类),把创建的实例存入IOC容器(ApplicationContext)中,然后结合DI给属性赋值
- ????DI依赖注入: (Dependency Injection)给所依赖的属性(就是声明的属性)赋值的过程
????什么意思呢?
????其实就是一种编程思想,在JavaWeb三层架构中就比如业务层去调用数据层时,要通过new对象的方式去调用数据层的方法,如下图所示
????这里就会出现一个问题,一旦数据层代码的实现方式发生改变,需要换一种实现方式,那么这里的业务层就需要相应的改变new的对象,就如下图所示
????这样会造成一种效果,对项目而言由于源代码发生了改变,那么该项目就要重新编译,重新测试,重新部署,重新发布,就企业级项目而言成本就非常的高
????总结来就是,由于在类中写了其他的一些实现,就会造成耦合度偏高,所以解决办法就是在使用对象时,在程序中不要主动使用new产生对象,而是转换为由外部提供对象,这个外部就是IOC容器,IOC容器负责对象的创建、初始化等一系列工作,被创建或被管理的对象在IoC容器中统称为Bean,这种解决办法的概念就是IOC控制反转
????那么实现控制反转之后,业务层和数据层并没有什么联系,也就是业务层此时还不能依赖数据层去运行,因此在IOC容器中又多了一个功能,既然IOC是创建对象的,那么业务层(service)和数据层(dao)的对象都可以在IOC容器中去创建,那既然对象都在容器中了,是否可以实现对象之间的依赖,从而建立绑定,这种绑定关系的整个过程就是DI依赖注入
????通过以上的解释可以大致这样理解
????以上就是学习Spring的目的
????Spring技术对IOC思想进行了实现
- ????Spring提供了一个容器,称为IoC容器,用来充当IOC思想中的“外部”
- ????IOC容器负责对象的创建、初始化等一系列工作,被创建或被管理的对象在IOC容器中统称为Bean
- ????在容器中建立bean与bean之间的依赖关系的整个过程,称为依赖注入
- ????IOC与DI思想的实现,其目的就是充分解耦
????最终效果: 使用对象时不仅可以直接从IOC容器中获取,并且获取到的bean已经绑定了所有的依赖关系
????Spring介绍
????Spring技术是JavaEE开发必备技能,企业开发技术选型命中率>90%
????为什么选型率这么高呢,有两点很关键
- ????简化开发,降低企业级开发的复杂性
- ????框架整合,高效整合其他技术,提高企业级应用开发与运行效率
????Spring Framework系统架构
????IOC与DI入门(XML格式)
????控制反转步骤
- ????导入Spring坐标
- ????定义Spring管理的类(接口)
- ????创建Spring配置文件,配置对应类作为Spring管理的bean对象
- ????初始化IOC容器(Spring核心容器/Spring容器),通过容器获取bean对象
????依赖注入步骤
- 删除使用new的形式创建对象的代码
- 提供依赖对象对应的setter方法
- 配置service与dao之间的关系
????导入Spring坐标
<!--导入spring的坐标spring-context,对应版本是5.2.10.RELEASE--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.10.RELEASE</version> </dependency>
????定义Spring管理的类(接口)
????com/moming/dao数据层
????创建BookDao接口,创建impl/BookDaoImpl实现类
????BookDao接口
package com.moming.dao; public interface BookDao { void save(); }
????BookDaoImpl实现类
package com.moming.dao.impl; import com.moming.dao.BookDao; public class BookDaoImpl implements BookDao { @Override public void save() { System.out.println("数据层执行"); } }
????com/moming/service业务层
????创建BookService接口,创建impl/BookServiceImpl实现类
????BookService接口
package com.moming.service; public interface BookService { void save(); }
????BookServiceImpl实现类
package com.moming.service.impl; import com.moming.dao.BookDao; import com.moming.service.BookService; public class BookServiceImpl implements BookService { //删除业务层中使用new的方式创建的dao对象 private BookDao bookDao; //提供set方法 public void setBookDao(BookDao bookDao) { this.bookDao = bookDao; } public void save(){ System.out.println("业务层执行"); bookDao.save(); } }
????resources下创建Spring配置文件(applicationContext.xml ),配置对应类作为Spring管理的bean对象, 配置service与dao之间的关系
????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"> <!-- bean标签:表示配置bean id属性:表示给bean起名字 class属性:表示给bean定义类型 --> <bean id="bookDao" class="com.moming.dao.impl.BookDaoImpl"/> <bean id="bookService" class="com.moming.service.impl.BookServiceImpl"> <!--配置service与dao的依赖关系 property标签:表示配置当前bean的属性 name属性:表示配置哪一个具体的属性 ref属性:表示参照哪一个bean --> <property name="bookDao" ref="bookDao"/> </bean> </beans>
????创建测试类App,获取IOC容器,获取bean,调用方法
????App
package com.moming; import com.moming.service.BookService; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class App { public static void main(String[] args) { //获取IOC容器 ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); //获取bean BookService bookService = (BookService) ac.getBean("bookService"); //调用 bookService.save(); } }
????运行结果
????bean配置
????bean基础配置
????bean别名配置
- ????获取bean无论是通过id还是name获取,如果无法获取到,将抛出异常NoSuchBeanDefinitionException: No bean named 'bookServiceImpl' available
????bean作用范围配置(一个bean造出来的是否是同一个对象)
????适合交给容器进行管理的bean
- ????表现层对象 业务层对象 数据层对象 工具对象
????不适合交给容器进行管理的bean
- ????封装实体的域对象
????bean初始化
????bean本质上就是对象,创建bean使用构造方法完成
????实例化bean的三种方式
- ????构造方法(常用)
- ????静态工厂(了解)
- ????FactoryBean(实用)
????构造方法(常用)
- ????提供可访问的构造方法
public class BookDaoImpl implements BookDao { public void save() { System.out.println("无参构造,默认存在 ..."); } }
- ????配置
<bean id="bookDao" class="com.moming.dao.impl.BookDaoImpl"/>
- ????无参构造方法如果不存在,将抛出异常BeanCreationException
????静态工厂(了解)
- ????静态工厂
public class BookDaoFactory{ public static BookDao getBookDao(){ return new BookDaoImpl; } }
- ????配置
<bean id="bookDao" factory-method="getBookDao" class="com.moming.factory.BookDaoFactory"/>
????FactoryBean(实用)
- ????FactoryBean
public class BookDaoFactoryBean implements FactoryBean<BookDao>{ public BookDao getObject() throws Exception{ return new BookDaoImpl(); } public Class<?> getObjectType(){ return BookDao.class; } }
- ????配置
<bean id="bookDao" class="com.moming.factory.BookDaoFactoryBean"/>
????bean生命周期
- ????生命周期:从创建到消亡的完整过程
- ????bean生命周期:bean从创建到销毁的整体过程
- ????bean生命周期控制:在bean创建后到销毁前做一些事情
????提供生命周期控制方法
public class BookDaoImpl implements BookDao { public void save() { System.out.println("数据层执行 ..."); } //表示bean初始化对应的操作 public void init(){ System.out.println("初始化执行 ..."); } //表示bean销毁前对应的操作 public void destory(){ System.out.println("销毁前执行 ..."); } }
????配置生命周期控制方法
<bean id="bookDao" class="com.moming.dao.impl.BookDaoImpl" init-method="init" destroy-method="destory"/>
????要想看到destory()执行,必须要关闭容器,因为程序结束后Java虚拟机就关闭了,destory()没机会执行,所以就要设置钩子在虚拟机退出前先关闭容器再退出虚拟机
????在service上按照spring接口的方式控制生命周期
???? BookServiceImpl
package com.moming.service.impl; import com.moming.dao.BookDao; import com.moming.service.BookService; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; public class BookServiceImpl implements BookService , InitializingBean, DisposableBean { //删除业务层中使用new的方式创建的dao对象 private BookDao bookDao; //提供set方法 public void setBookDao(BookDao bookDao) { System.out.println("属性设置"); this.bookDao = bookDao; } public void save(){ System.out.println("业务层执行"); bookDao.save(); } @Override public void destroy() throws Exception { System.out.println("service 销毁前执行"); } @Override public void afterPropertiesSet() throws Exception { System.out.println("service 属性设置完以后执行"); } }
???? App
package com.moming; import com.moming.service.BookService; import org.springframework.context.support.ClassPathXmlApplicationContext; public class App { public static void main(String[] args) { //获取IOC容器 //ApplicationContext没有close方法,所以去下一级找 ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); //获取bean BookService bookService = (BookService) ctx.getBean("bookService"); //调用 bookService.save(); //直接手动暴力关闭(不推荐) //ctx.close(); //获取钩子关闭 ctx.registerShutdownHook(); } }
????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"> <!-- bean标签:表示配置bean id属性:表示给bean起名字 class属性:表示给bean定义类型 --> <!--<bean id="bookDao" class="com.moming.dao.impl.BookDaoImpl"/>--> <bean id="bookDao" class="com.moming.dao.impl.BookDaoImpl" init-method="init" destroy-method="destory"/> <bean id="bookService" class="com.moming.service.impl.BookServiceImpl"> <!--配置service与dao的依赖关系 property标签:表示配置当前bean的属性 name属性:表示配置哪一个具体的属性 ref属性:表示参照哪一个bean --> <property name="bookDao" ref="bookDao"/> </bean> </beans>
????bean整个生命周期所经历的阶段
????初始化容器
- ????创建对象(内存分配)
- ????执行构造方法
- ????执行属性注入(set操作)
- ????执行bean初始化方法
????使用bean
- ????执行业务操作
????关闭/销毁容器
- ????执行bean销毁方法
????依赖注入方式
????向一个类中传递数据的方式有两种
- ????普通方法(set方法)
- ????构造方法
????依赖注入描述了在容器中建立bean与bean之间依赖关系的过程,如果bean运行需要的是数字或字符串呢
- ????引用类型
- ????简单类型(基本数据类型与String)
????依赖注入方式
????setter注入(推荐使用)
- ????简单类型
- ????引用类型
????构造器注入
- ????简单类型
- ????引用类型
????setter注入引用类型
- ????在bean中定义引用类型属性并提供可访问的set方法
public class BookServiceImpl implements BookService{ private BookDao bookDao; public void setBookDao(BookDao bookDao) { this.bookDao = bookDao; } }
- ????配置中使用property标签ref属性注入引用类型对象
<bean id="bookService" class="com.moming.service.impl.BookServiceImpl"> <property name="bookDao" ref="bookDao"/> </bean> <bean id="bookDao" class="com.moming.dao.impl.BookDaoImpl"/>
????setter注入简单类型
- ????在bean中定义引用类型属性并提供可访问的set方法
public class BookDaoImpl implements BookDao { private int connectionNumber; public void setConnectionNumber(int connectionNumber) { this.connectionNumber = connectionNumber; } }
- ????配置中使用property标签value属性注入简单类型数据
<bean id="bookDao" class="com.moming.dao.impl.BookDaoImpl"> <property name="connectionNumber" value="10"/> </bean>
????构造器注入引用类型(了解)
- ????在bean中定义引用类型属性并提供可访问的构造方法
public class BookServiceImpl implements BookService{ private BookDao bookDao; public BookServiceImpl(BookDao bookDao) { this.bookDao = bookDao; } }
- ????配置中使用constructor-arg标签ref属性注入引用类型对象
<bean id="bookService" class="com.moming.service.impl.BookServiceImpl"> <constructor-arg name="bookDao" ref="bookDao"/> </bean> <bean id="bookDao" class="com.moming.dao.impl.BookDaoImpl"/>
????构造器注入简单类型(了解)
- ????在bean中定义引用类型属性并提供可访问的set方法
public class BookDaoImpl implements BookDao { private int connectionNumber; public void setConnectionNumber(int connectionNumber) { this.connectionNumber = connectionNumber; } }
- ????配置中使用constructor-arg标签value属性注入简单类型数据
<bean id="bookDao" class="com.moming.dao.impl.BookDaoImpl"> <constructor-arg name="connectionNumber" value="10"/> </bean>
????构造器注入参数适配(了解)
- ????配置中使用constructor-arg标签type属性设置按形参类型注入
<bean id="bookDao" class="com.moming.dao.impl.BookDaoImpl"> <constructor-arg type="int" value="10"/> <constructor-arg type="java.lang.String" value="mysql"/> </bean>
- ????配置中使用constructor-arg标签index属性设置按形参位置注入
<bean id="bookDao" class="com.moming.dao.impl.BookDaoImpl"> <constructor-arg index="0" value="10"/> <constructor-arg index="1" value="mysql"/> </bean>
????依赖注入方式选择
- ????强制依赖使用构造器进行,使用setter注入有概率不进行注入导致null对象出现
- ????可选依赖使用setter注入进行,灵活性强
- ????Spring框架倡导使用构造器,第三方框架内部大多数采用构造器注入的形式进行数据初始化,相对严谨
- ????如果有必要可以两者同时使用,使用构造器注入完成强制依赖的注入,使用setter注入完成可选依赖的注入
- ????实际开发过程中还要根据实际情况分析,如果受控对象没有提供setter方法就必须使用构造器注入
- ????自己开发的模块推荐使用setter注入
????依赖自动装配
????IOC容器根据bean所依赖的资源在容器中自动查找并注入到bean中的过程称为自动装配
????自动装配方式
- ????按类型(常用)
- ????按名称
- ????按构造方法
- ????不启用自动装配
????配置中使用bean标签autowire属性设置自动装配的类型
<bean id="bookDao" class="com.moming.dao.impl.BookDaoImpl"/> <bean id="bookService" class="com.moming.service.impl.BookServiceImpl" autowire="byType"/>
????依赖自动装配特征
- ????自动装配用于引用类型依赖注入,不能对简单类型进行操作
- ????使用按类型装配时(byType)必须保障容器中相同类型的bean唯一,推荐使用
- ????使用按名称装配时(byName)必须保障容器中具有指定名称的bean,因变量名与配置耦合,不推荐使用
- ????自动装配优先级低于setter注入与构造器注入,同时出现时自动装配配置失效
????集合注入
????注入数组对象
<property name="array"> <array> <value>100</value> <value>200</value> <value>300</value> </array> </property>
????注入List对象(重点)
<property name="list"> <list> <value>java</value> <value>spring</value> <value>DI</value> </list> </property>
????注入Set对象
<property name="set"> <set> <value>java</value> <value>spring</value> <value>DI</value> </set> </property>
????注入Map对象(重点)
<property name="map"> <map> <entry key="张三" value="23"/> <entry key="李四" value="24"/> <entry key="王五" value="25"/> </map> </property>
????注入Properties对象
<property name="properties"> <props> <prop key="zhangsan">23</prop> <prop key="lisi">24</prop> <prop key="wangwu">25</prop> </props> </property>
????说明:property标签表示setter方式注入,构造方式注入constructor-arg标签内部也可以写<array>、<list>、<set>、<map>、<props>标签