Spring中IOC的使用
IOC(Inverse Of Control)控制反转,它是一种思想,作用就是为了消减我们代码之间的耦合性。它的实现方法就是利用了工厂设计模式。把创建对象的代码从具体的类中剥离出来,交给工厂来完成,从而降低了代码之间的依赖关系
在配置IOC时,spring提供了两个方式,我们先使用XML文件的配置方式来做展开,
导入需要的依赖包spring-context
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.1</version>
</dependency>
准备一个Spring的配置文件:beans.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">
</beans>
Spring中的工厂类
BeanFactory是Spring中IOC容器的顶级接口,包含了各种Bean的定义、读取bean配置文档、管理bean的加载、实例化控制bean的生命周期,维护bean之间的依赖关系等功能,其他的容器接口都是它的子类
而我们一般使用的ApplicationContext接口,它作为BeanFactory的派生,除了具有BeanFactory的全部功能外,还有很多重要的功能(国际化、加载多个配置文件、载入多个上下文···等等)。
区别:Bean的创建时间不同:
- BeanFactory:什么时候用到对象,什么时候创建
- ApplicationContext:容器启动后,一次性创建了所有的Bean
用到时创建对象:如果Bean中出现异常,用到Bean时才会发现异常;先创建就可以在容器启动时,发现Bean中有没有问题,(同样当Bean较多时,容器的启动较慢)
ApplicationContext接口中的实现类:
- ClassPathXMLApplicationContext:从类的根路径下加载配置文件,推荐使用
- FileSystemXMLApplicationContext:从磁盘路径下加载配置文件
- AnnotationConfigApplicationContext:从一个配置类中创建容器,(使用纯注解的配置类是会用到)
现在我们先使用xml配置的方式完成一个IOC的配置,然后来详细的分析一下bean管理对象的细节
基于XML的IOC配置
准备一个Bean类
public class UserDaoImpl implements IUserDao {
@Override
public void save() {
System.out.println("向数据库中添加一条用户信息");
}
}
在beans.xml文件中添加配置
<bean id="userDao" class="com.zxy.dao.impl.UserDaoImpl"/>
测试:
@Test
public void test1(){
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
IUserDao userDao = (IUserDao) context.getBean("userDao");
userDao.save();
}
默认情况下,它调用的是类中无参的构造方法,如果是没有无参数构造方法的类则不能创建成功
除了上面的方法之外我们还可以使用静态工厂创建对象,和实例工厂创建对象
静态工厂(factory-method)
public class StaticFactory {
public static IUserDao createUserDao(){
return new UserDaoImpl();
}
}
<bean id="userDao2" class="com.zxy.factory.StaticFactory" factory-method="createUserDao"/>
实例工厂(factory-bean+factory-method)
public class InstanceFactory {
public IUserDao createUserDao(){
return new UserDaoImpl();
}
}
<bean id="instanceFactory" class="com.zxy.factory.InstanceFactory"/>
<bean id="userDao3" factory-bean="instanceFactory" factory-method="createUserDao"/>
几个简单的例子已经写完了,其中springXML配置文件中有一个很重要的标签**<bean/>**,我们来详细的分析一下
Bean标签
作用:配置对象让Spring来创建
常用属性:
- id:给对象在容器中提供一个唯一的标识,用于获取对象
- class:指定类的全限定名,用于反射创建对象
- scope:指定对象的使用范围(作用域)
- singleton:单例模式(默认)
- prototype:多例
- request:web项目中使用,将对象存入request域中
- session:web项目中使用,将对象存入session域中
- init-method:指定类中的初始化方法名,对象初始化时执行
- destroy-method:指定类中的销毁方法名,对象被销毁时执行
getBean方法多种获取Bean的方式
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
//根据id属性获取对象
IUserDao userDao = (IUserDao) context.getBean("userDao");
//根据字节码获取对象
IUserDao userDao2 = context.getBean(IUserDao.class);
//根据bean中的id属性和字节码获取对象(当一个接口有多个实现类时就需要使用这种方式!!)
IUserDao userDao3 = context.getBean("userDao",IUserDao.class);
补充:
Bean对象的生命周期:
- 单例对象:scope=“singleton”
- 一个应用只有一个对象的实例,它的作用范围就是整个应用
- 对象创建:当应用加载创建容器时,对象就被创建了
- 对象存活:只要容器在,对象一直存活
- 对象死亡:当应用卸载,销毁容器时,对象就被销毁
- 多例对象:scope=“prototype”
- 每次访问对象时,都会创建一个新的对象
- 对象创建:当使用对象时,创建对象实例
- 对象存活:对象被使用一直存活
- 对象死亡:当对象长时间不用,就会被java垃圾回收器回收
基于注解的IOC配置
bean标签和注解的对应关系:
@Component(类注解,被注解的类表示交给Spring管理)
- 注解属性value:不写默认为首字母小写的类名,(对应bean标签中的id)
- 该注解压衍生出三个子注解:效果和@Component一样,只不过是为了体现分层的概念
- @Controller,适合用在显示层
- @Service,适合用在业务层
- @Repository,适合用在数据层
@Scope(对应bean标签中的scope属性)
- 注解属性value:不写默认Singleton(单例),还可以设置为prototype(多例)
@PostConstruct(对应bean标签中的init-method)
- 用在方法上,表示类初始化时会执行该方法
@PreDestroy(对应bean标签中的destroy-method)
- 用在方法上,表示类被销毁时会执行该方法
@PostConstruct和@PreDestroy这两个注解是jdk提供的,需要我们添加相关的依赖
<!-- https://mvnrepository.com/artifact/javax.annotation/javax.annotation-api -->
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
在实现类中添加注解:
@Component//表示这个类交给Spring管理
public class UserDaoImpl implements IUserDao {
@PostConstruct//类被初始化时会执行该方法
public void initMethod(){
System.out.println("========init======");
}
@Override
public void save() {
System.out.println("向数据库中添加一条用户信息");
}
@PreDestroy//类被销毁时会执行该方法
public void destroyMethod(){
//根据bean的生命周期,destroy执行的时间也不相同
System.out.println("========destroy======");
}
}
入口我们暂时还是使用beans.xml文件,所以还需要在beans.xml中写一行代码:
<!-- 扫描指定包中的注解,从而完成Spring对它们的管理-->
<context:component-scan base-package="com.zxy"/>
测试:
@Test
public void test1(){
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
IUserDao userDao = (IUserDao) context.getBean("userDao");
userDao.save();
}
DI(依赖注入)是SpringIOC中的一个具体的体现,下一篇Spring中的DI ※