IoC、DI和AOP思想
IoC控制反转思想,强调是程序中将创建bean(主动new 创建对象)的权利反转给第三方
DI依赖注入思想,强调的是bean之间的依赖关系
AOP面向切面思想,功能的横向抽取,主要的实现方式就是proxy
IoC解决了哪些问题
上图代码中,业务层内通过new BookDaoImpl实例化bookDao,由bookDao进行具体的数据操作,当需要将BookDaoImpl换成BookDaoImpl2时,就需要修改业务层的代码,代码的耦合性高,为了解决这个问题,引出了IoC思想,即:程序中将创建bean(主动new 创建对象)的权利反转给第三方(容器)
spring实现了这个第三方(容器),也被称为IoC容器,这个容器内部帮我们创建了对象,IoC容器创建的对象也被称为bean
IoC容器内将serice与dao建立关系就是DI
IoC使用
- 管理什么?(Service与Dao)
- 如何将被管理的对象告知IoC容器?(配置)
- 被管理的对象交给IoC容器,如何获取到IoC容器?(接口
- IoC容器得到后,如何从容器中获取bean?(接口方法)
首先是不使用IoC的代码案例:
java
package org.example;
import org.example.dao.BookDao;
import org.example.service.BookService;
import org.example.service.impl.BookServiceImpl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
BookService bookService = new BookServiceImpl();
bookService.save();
}
}
输出:
book service save ...
book dao save
IoC入门 - 基于XML的IoC
1.pom.xml中配置依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>6.1.12</version>
</dependency>
2.xml中配置bean
applicationContext.xml
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">
<!-- id是bean的名字, class是实现类-->
<bean id="bookDao" class="org.example.dao.impl.BookDaoImpl" />
<bean id="bookService" class="org.example.service.impl.BookServiceImpl" />
</beans>
id是bean的名字, class是bean的实现类
3.使用bean
java
package org.example;
import org.example.dao.BookDao;
import org.example.service.BookService;
import org.example.service.impl.BookServiceImpl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
// 获取IcC容器
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
// 获取bean
// BookDao bookDao = (BookDao) ctx.getBean("bookDao");
// bookDao.save();
BookService bookService = (BookService) ctx.getBean("bookService");
bookService.save();
}
}
DI使用
- 前提是基于IoC管理的bean
- Service中使用new形式创建的Dao对象是否保留?(否)
- Service中需要的Dao对象如何引入到Service中?(提供方法)
- Service与Dao间的关系如何描述?(配置)
DI入门 - 基于XML的DI
setter方法注入
引用类型注入
xml中 使用property标签 + name + ref
java
package org.example.service.impl;
import org.example.dao.BookDao;
import org.example.service.BookService;
public class BookServiceImpl implements BookService {
// 1.删除Service中使用new创建的Dao对象
// private BookDao bookDao = new BookDaoImpl() ;
private BookDao bookDao;
public void save() {
System.out.println("book service save ...");
bookDao.save();
}
// 2.Service中提供set方法创建Dao, 这个set方法是IoC容器调用的,通过xml中配置内容将bookDao传入
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
}
applicationContext.xml
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">
<!-- id是bean的名字, class是实现类-->
<bean id="bookDao" class="org.example.dao.impl.BookDaoImpl" />
<bean id="bookService" class="org.example.service.impl.BookServiceImpl">
<!-- 3.配置Service与Dao的关系-->
<!-- name 表示配置哪一个具体属性-->
<!-- ref 表示参照哪一个bean-->
<property name="bookDao" ref="bookDao"/>
</bean>
</beans>
值类型注入
xml中 使用property标签 + name + value
java
package org.example.service.impl;
import org.example.dao.BookDao;
import org.example.service.BookService;
public class BookServiceImpl implements BookService {
private BookDao bookDao;
private int year;
private String name;
public void save() {
System.out.println("book service save"+name+year);
bookDao.save();
}
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
public void setYear(int year) {
this.year = year;
}
public void setName(String name) {
this.name = name;
}
}
java
<?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 id="bookDao" class="org.example.dao.impl.BookDaoImpl" />
<bean id="bookService" class="org.example.service.impl.BookServiceImpl" scope="prototype">
<!-- 引用类型注入-->
<property name="bookDao" ref="bookDao"/>
<!-- 值类型注入-->
<property name="year" value="2024"/>
<property name="name" value="《java入门》"/>
</bean>
</beans>
构造器注入
引用类型注入
xml中 使用constructor-arg标签 + name + ref name可以换成type或index
java
package org.example.service.impl;
import org.example.dao.BookDao;
import org.example.service.BookService;
public class BookServiceImpl implements BookService {
private BookDao bookDao;
public BookServiceImpl(BookDao bookDao) {
this.bookDao = bookDao;
}
}
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 id="bookDao" class="org.example.dao.impl.BookDaoImpl" />
<bean id="bookService" class="org.example.service.impl.BookServiceImpl" scope="prototype">
<constructor-arg name="bookDao" ref="bookDao"/>
</bean>
</beans>
值类型注入
xml中 使用constructor-arg标签 + name + value name可以换成type或index
java
package org.example.service.impl;
import org.example.dao.BookDao;
import org.example.service.BookService;
public class BookServiceImpl implements BookService {
private int year;
private String name;
public BookServiceImpl(int year, String name) {
this.bookDao = bookDao;
this.year = year;
this.name = name;
}
}
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 id="bookDao" class="org.example.dao.impl.BookDaoImpl" />
<bean id="bookService" class="org.example.service.impl.BookServiceImpl" scope="prototype">
<constructor-arg name="bookDao" ref="bookDao"/>
<constructor-arg name="year" value="2024"/>
<constructor-arg name="name" value="《java入门》"/>
</bean>
</beans>
自动注入
配置中使用bean标签autowire属性设置自动装配的类型
- 自动装配用于引用类型依赖注入,不能对简单类型进行操作
- 使用按类型装配时(byType)必须保障容器中相同类型的bean唯一,推荐使用
- 使用按名称装配时(byName)必须保障容器中具有指定名称的bean,因变量名与配置耦合,不推荐使用
- 自动装配优先级低于setter注入与构造器注入,同时出现时自动装配配置失效
案例
// 当使用自动注入时,会先找到set方法,然后:
// 1. autowire="byType" 时 会在bean中找到符合BookDao类型的bean来注入
// 2. autowire="byName" 时 会在bean中找到符合名字为 bookDao 的bean来注入
补充:依赖注入bean标签常用属性
Bean
bean基础
在Spring框架中,"bean" 是指由Spring IoC(Inversion of Control,控制反转)容器管理的任何对象。Spring IoC容器负责实例化、配置和组装这些bean。简单来说,bean就是应用程序中的一个组件或服务,它是由Spring IoC容器创建并管理的。
以下是关于Spring bean的一些关键点:
- 定义:通常,你通过在Spring配置文件中使用<bean>标签或者使用注解(如@Component, @Service, @Repository, @Controller等)来定义一个bean。
- 生命周期管理:Spring容器不仅创建bean,还管理它们的整个生命周期,包括初始化和销毁阶段。你可以通过实现特定的接口(如InitializingBean和DisposableBean)或使用自定义的初始化和销毁方法来控制这个过程。
- 依赖注入:Spring的一个核心特性是依赖注入(DI, Dependency Injection),它允许你在不直接构造的情况下将一个bean的依赖关系提供给另一个bean。这意味着你不需要在代码中硬编码依赖项,而是可以通过配置让Spring容器自动完成依赖关系的装配。
- 作用域:每个bean都可以指定一个作用域,比如singleton(单例,每个Spring IoC容器只有一个共享的bean实例)、prototype(原型,每次请求都会产生一个新的bean实例)、request、session等。
- 配置方式:bean可以通过XML配置文件、Java配置类或注解来定义。随着Spring的发展,基于注解的配置变得越来越流行,因为它更加简洁且易于维护。
- AOP支持:Spring beans还可以利用Spring AOP(面向切面编程)功能,在运行时动态地添加额外的行为,比如日志记录、事务管理等。
案例
<bean id="bookDao" class="org.example.dao.impl.BookDaoImpl" />
<bean id="bookService" class="org.example.service.impl.BookServiceImpl">
bean的别名
获取bean时,可以通过id获取也可以通过别名获取
案例
<bean id="bookDao" name="dao,dao1" class="org.example.dao.impl.BookDaoImpl" />
<bean id="bookService" class="org.example.service.impl.BookServiceImpl"/>
bean的作用范围
默认获取的bean是单例模式的
案例
<bean id="bookService" class="org.example.service.impl.BookServiceImpl" scope="prototype">
java
package org.example;
import org.example.service.BookService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
// 获取IcC容器
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
// 获取bean
BookService bookService1 = (BookService) ctx.getBean("bookService");
BookService bookService2 = (BookService) ctx.getBean("bookService");
System.out.println(bookService1);
System.out.println(bookService2);
}
}
输出:scope="prototype" 时获取的bean地址不同
org.example.service.impl.BookServiceImpl@6279cee3
org.example.service.impl.BookServiceImpl@4206a205
由于IoC容器管理的bean是默认是单例模式,哪些类适合交给IoC容器?
适合:
- 表现层对象
- 业务层对象
- 数据层对象
- 工具对象
不适合
- 封装实体的域或对象
bean的实例化
无参构造方法实例化bean
bean本质是对象,创建bean使用构造方法完成,且使用的是无参构造方法
静态工厂方法实例化bean
工厂对象方法实例化bean
FactoryBean实例化bean
bean的生命周期
执行生命周期方法一
xml中配置init-mothod 与 destory-mothod
执行生命周期方法二
继承 InitializingBean 与 DisposableBean
手工关闭容器
ConfigurableApplicationcontext接口close()操作
注册关闭钩子,在虚拟机退出前先关闭容器再退出虚拟机
ConfigurableApplicationcontext接口registerShutdownHook()操作