IOC-控制反转
- 概念:指的是将对象的创建权交给 Spring 去创建
- 作用:通过Spring创建对象可实现依赖注入
- 创建对象的方式:
- 无参构造
- 有参构造
- 工厂模式
- Bean:在 Spring 中,被 Spring 容器所管理的对象称之为”Bean”对象。一个 Spring 的 Bean 对象 可以是任何形式的 POJO
Spring IOC 容器类型
Spring提供了两种IOC容器,分别为BeanFactory和ApplicationContext
BeanFactory
BeanFactory是基础类型的IOC容器
它由 org.springframework.beans.facytory.BeanFactory 接口定义,并提供了完整的 IoC 服务支持。简单来说,BeanFactory 就是一个管理 Bean 的工厂,它主要负责初始化各种 Bean,并调用它们的生命周期方法
ApplicationContext
ApplicationContext 是 BeanFactory 的子接口,也被称为应用上下文。该接口的全路径 为 org.springframework.context.ApplicationContext,它不仅提供了 BeanFactory 的所有功能, 还添加了对国际化、资源访问、事件传播等方面的良好支持
- ApplicationContext 接口有两个常用的实现类
ClassPathXmlApplicationContext类
//该 类 从 类 路 径 ClassPath 中 寻 找 指 定 的 XML 配 置 文 件 , 找 到 并 装 载 完 成 ApplicationContext 的实例化工作
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(String configLocation);
//FileconfigLocation 参数用于指定 Spring 配置文件的名称和位置
FileSystemXmlApplicationContext类
//该类从指定的文件系统路径中寻找指定的 XML 配置文件,找到并装载完成 ApplicationContext 的实例化工作
ApplicationContext applicationContext = new FileSystemXmlApplicationContext(String configLocation)
区别:在读取 Spring 的配置文件时, FileSystemXmlApplicationContext 不再从类路径中读取配置文件,而是通过参数指定配置文 件的位置,它可以获取类路径之外的资源,如“F:/workspaces/applicationContext.xml”
简单范例
添加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 10
http://www.springframework.org/schema/beans/spring-beans.xsd"> </beans>
通过 IOC 容器管理 Bean 对象
- 创建接口及其实现类
public interface UsersService { void addUsers(); }
public class UsersServiceImpl implements UsersService {
@Override
public void addUsers() {
System.out.println("UsersService addUsers ......");
}
}
- 修改配置文件,在Spring配置文件下,添加:
<bean id="usersService" class="com.lanh.service.impl.UsersServiceImpl"/> </beans>
- 获取IOC容器中的对象
public class UsersServiceTest { public static void main(String[] args) {
//启动 Spring IOC 容器
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
//从 IOC 容器中获取
UsersService usersService = (UsersService) applicationContext.getBean("usersService"); usersService.addUsers(); }
创建 Bean 对象的三种方式
通过构造方法创建Bean对象
public class UsersServiceImpl implements UsersService{
public UsersServiceImpl(){
System.out.println("Init");
}
@Override
public void addUsers(){
System.out.println("UsersService addUsers");
}
}
通过静态工厂方法创建对象
- 创建静态工厂方法
public class ObjectFactory {
public static UsersService getInstance(){
return new UsersServiceImpl();
}
}
- 修改配置文件
<!--通过静态工厂方法实例化对象-->
<bean id="usersService" class="com.lanh.factory.ObjectFactory" factory-method="getInstance"/> </beans>
factory-method必须是静态方法
- 创建测试类
public class Test{
public static void main(String[] args){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml")
UsersService usersService = (UsersService)applicationContext.getBean("usersService");
usersService.addUsers();
}
}
通过动态工厂方法创建对象
- 创建动态工厂方法
public class DynamicObjectFactory{
public UsersService getInstance(){
return new UsersServiceImpl();
}
}
- 修改配置类
<!--通过动态工厂方法实例化对象-->
<bean id="dynamicObjectFactory" class="com.lanh.factory.DynamicObjectFactory"/>
<bean id="usersService" factory-bean="dynamicObjectFactory" factory-method="getInstance"/>
- 创建测试类
public class DynamicFactoryTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
UsersService usersService = (UsersService) applicationContext.getBean("usersService");
usersService.addUsers();
}
}
三种方法的区别
- 第一种:通过默认的无参构造方法创建,本质是将类交给Spring自带的工厂BeanFactory管理,由Spring自带的工厂模式帮我们维护和创建这个类
- 第二种:通过静态工厂创建,其本质是将类交给我们自己的静态工厂管理,Spring仅仅是帮助我们调用静态方法创建实例的方法,
- 第三种:通过实例工厂创建,本质就是把创建实例的工厂类交由Spring管理,同时将调用工厂类的方法创建实例的这个过程也交由Spring管理
获取Bean对象的方式
通过id或name获取Bean对象
applicationContext.getBean(id|name);
- 配置文件
<bean id="usersService" name="name1,name2,name3" class="com.lanh.service.impl.UsersServiceImpl"/>
- 获取bean对象
UsersService usersService = (UsersService) applicationContext.getBean("name2");
getBean中可填usersService.name1,name2,name3均可得到Bean对象
通过类型获取Bean对象
applicationContext.getBean(Class class)
通过类型来或取 Bean 时,要求类型必须是唯一的
- 获取bean对象
//通过类型获取 Bean 对象
UsersService usersService = applicationContext.getBean(UsersServiceImpl.class);
usersService.addUsers();
通过 id 或 name获取Bean对象
在 SpringIOC 容器中,通过类型获取对象时,如果同一类型存在多个对象,我们可以使 用 id 或 name 来识别需要获取的对象
- 方式一
UsersService usersService = applicationContext.getBean("name1",UsersServiceImpl.class);
usersService.addUsers();
- 方式二
//获取 Spring IOC 容器中所有的 Bean 对象的 ID
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for(String name: beanDefinitionNames){
System.out.println(name);
}
UsersService usersService = applicationContext.getBean(beanDefinitionNames[0],UsersServiceImpl.class);
usersService.addUsers();
SpringIOC容器创建对象的策略
Bean的作用域
作用域:作用域限定了 Spring Bean 的作用范围,在 Spring 配置文件定义 Bean 时,通过 声明 scope 配置项,可以灵活定义 Bean 的作用范围
scope的值:
- singleton
- prototype
singleton
singleton 为 scope 属性的默认值。当 scope 属性的值为 singleton 时,Spring IOC 容器启 动时会立即实例化一次 Bean 对象,并一直被 Spring IOC 容器所缓存,所以生命周期较长。
特点:
- Spring IOC容器启动时会创建Bean对象
- 每次调用getBean都返回Spring容器中唯一一个对象
prototype
当 scope 属性的值为 prototype 时,每次调用调用 getBean 方法时都会返回一个新的 Bean 对象,Spring IOC 容器并不会缓存该对象,所以就不再负责管理它的生命周期
特点:
- Spring IOC容器启动时不会创建Bean对象
- 每次调用getBean都会创建一个新Bean对象
实例化对象策略
Spring IOC 容器在启动时默认的会将在配置文件中所配置的所有 Bean 对象立即进行实 例化,并保存在 IOC 容器中。我们可以通过<bean>标签 lazy-init 属性的实现延迟实例化对象
注意:lazy-init="false"只对 scope 属性为 singleton 才有效,如果 scope 属性为 pototype, 无论 lazy-init 的属性值是什么,都只在通过 getbean 时进行实例化
- 立即创建:
lazy-init=“false”(默认)
在SpringIOC容器启动时会实例化配置文件中的所有Bean对象 - 延迟创建
lazy-init=“true”
当调用getBean方法时创建对象
DI-依赖注入
- 概念:依赖注入是指在 Spring IOC 容器创建对象的过程中,将所 依赖的对象通过配置进行注入。我们可以通过依赖注入的方式来降低对象间的耦合度。
在软件工程中,对象之间的耦合度就是对象之间的依赖性。对象之间的耦合越高,维护 成本越高,因此对象的设计应使对象之间的耦合越小越好
类的关系
继承 实现 依赖 关联 聚合 组合
依赖关系
- 依赖关系:是一种使用的关系, 即一个类的实现需要另一个类的协助, 所以要尽量 不使用双向的互相依赖
- 代码表现:局部变量、方法的参数或者对静态方法的调用
- 箭头及指向:带箭头的虚线,指向被使用者
聚合
- 聚合关系:是整体与部分的关系.如车和轮胎是整体和部分的关系. 聚合关系是关联关系的一种,是强的关联关系;关联和聚合在语法上无法区分,必须考察具体的逻辑关系。
- 代码体现:成员变量
- 箭头及指向:带空心菱形的实心线,菱形指向整体
关系强度
继承 = 实现 > 组合 > 聚合 > 关联 > 依赖
开闭原则
定义
OCP (Open Close Principle): 软件本身应该是可扩展的,而不可修改的。也就是,对扩 展开放,对修改封闭的
开闭原则优点
- 易扩展。开闭原则的定义就要求对扩展开放。
- 易维护。软件开发中,对现有代码的修改是一件很有风险的事情,符合开闭原则的设计 在扩展时无需修改现有代码,规避了这个风险,大大提交了可维护性。
高内聚、低耦合
- 高内聚是指相关度比较高的部分尽可能的集中,不要分散。
- 低耦合就是说两个相关的模块尽可以能把依赖的部分降低到最小,不要产生强依赖。
依赖注入的方式
在使用依赖注入时,如果注入的是 Bean 对象,那么要求注入的 Bean 对象与被注入的 Bean 对象都需要 Spring IOC 容器来实例化
通过Set方法注入
需要为注入的成员变量提供Set方法
Bean对象
private UsersDao usersDao;
public UsersDao getUsersDao() {
return usersDao;
}
public void setUsersDao(UsersDao usersDao) {
this.usersDao = usersDao;
}
配置文件
<bean id="usersService" name="name1,name2,name3" class="com.lanh.service.impl.UsersServiceImpl">
<property name="usersDao">
<ref bean="usersDaoMybatis"/>
</property>
<!-- <property name="usersDao" ref="usersDaoMybatis"/>-->
</bean>
通过构造方式注入
Bean对象中需要提供有参的构造方法
Bean对象
private UsersDao usersDao;
public UsersServiceImpl(UsersDao usersDao){
this.usersDao = usersDao;
}
配置文件
<bean id="usersService" name="name1,name2,name3" class="com.lanh.service.impl.UsersServiceImpl">
<!-- name:根据参数名称识别参数 index:根据参数的位置来识别参数 type:根据参数的类型识别参数 -->
<constructor-arg name="usersDao">
<ref bean="usersDaoMybatis"/>
</constructor-arg>
<!-- <constructor-arg name="usersDao" ref="usersDaoMybatis"/>-->
</bean>
自动注入
自动注入的方式有两种,一种是全局配置自动注入,另一种是局部配置自动注入。
无论全局配置或局部单独配置,都有 5 个值可以选择:
- no:当 autowire 设置为 no 的时候,Spring 就不会进行自动注入。
- byName:在 Spring 容器中查找 id 与属性名相同的 bean,并进行注入。需要提供 set 方 法。
- byType:在 Spring 容器中查找类型与属性名的类型相同的 bean,并进行注入。需要提21
供 set 方法。
constructor:仍旧是使用 byName 方式,只不过注入的时候,使用构造方式进行注入。
default:全局配置的 default 相当于 no,局部的 default 表示使用全局配置设置
局部自动注入
通过 bean 标签中的 autowire 属性配置自动注入。
有效范围:仅针对当前 bean 标签生效
<bean id="usersDaoMybatis" class="com.lanh.dao.impl.UsersDaoMybatisImpl"/>
<bean id="usersService" name="name1,name2,name3" class="com.lanh.service.impl.UsersServiceImpl" autowire="byType"> </bean>
全局自动注入
通过 beans 标签中的 default-autowire 属性配置自动注入。
有效范围:配置文件中的所有 bean 标签都生效
<?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" default-autowire="byName">
依赖注入的数据类型
注入Bean对象
- 方式一
<property name="FieldName">
<ref bean="BeanID"/>
</property>
- 方式二
<property name="FieldName" ref="BeanID"/>
注入基本数据类型和字符串
- 方式一
<property name="FieldName">
<value>content</value>
</property>
-方式二
<property name="FieldName" value="Content"/>
注入List
<property name="FieldName" >
<list>
<value/>或者<bean/>或者<ref/>......
</list>
</property>
注入Set
<property name="FieldName" >
<set>
<value/>或者<bean/>或者<ref/>......
</set>
</property>
注入Map
- 方式一
<property name="FieldName" >
<map>
<entry key="KeyName" value="Content"/>
<!-- 如果是对象 则: -->
<!-- <entry key="KeyName" value-ref="BeanID"/> -->
</map>
</property>