【Spring Framework】IoC容器、依赖注入 + 基于XML && 基于注解 && 基于Java Config配置IoC容器 + Spring与JUnit4整合
概念
- IoC,Inversion of Control,控制反转:将对象的控制权交由第三方统一管理
- DI,Dependency Injection:依赖注入,使用反射技术,是一种IoC的实现
- Spring IoC容器:用于统一创建与管理对象依赖
- XML管理对象(bean):applicationContext.xml
Spring框架使用流程-基于XML配置IoC容器
1. 导入spring坐标
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.18</version>
</dependency>
2. 创建spring配置文件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">
</beans>
3. 实例化对象
- XML管理Bean
- Bean id与name都是设置对象在IoC容器中的唯一标识,两者在同一个配置文件中不允许重复出现,在不同的配置文件中可以重复出现,新对象覆盖旧对象。【推荐使用bean id标识对象】,在没有设置bean id和name时,使用类全称作为bean标识。
基于构造方法创建对象
<!--使用constructor-arg子标签,通过带参构造方法创建对象,类中必须包含该构造方法-->
<bean id="softApple" class="com.EveX.spring.ioc.entity.Apple">
<constructor-arg name="title" value="金帅"></constructor-arg>
<constructor-arg name="color" value="黄色"></constructor-arg>
<constructor-arg name="origin" value="中国"></constructor-arg>
</bean>
基于静态工厂创建对象(少用,了解)
<!--通过静态工厂创建对象-->
<bean id = "sweetApple" class="com.EveX.spring.ioc.factory.AppleFactory" factory-method="creatSweetApple"></bean>
package com.EveX.spring.ioc.factory;
import com.EveX.spring.ioc.entity.Apple;
public class AppleFactory {
public static Apple creatSweetApple() {
Apple sweetApple = new Apple();
sweetApple.setTitle("红富士");
sweetApple.setColor("红色");
sweetApple.setOrigin("欧洲");
return sweetApple;
}
}
基于工厂实例化创建对象(少用,了解)
IoC容器对工厂类进行实例化并调用对应的实例方法创建对象
<!--通过工厂实例化创建对象-->
<bean id = "factoryInstance" class="com.EveX.spring.ioc.factory.AppleFactoryInstance"></bean>
<bean id = "sweetApple" factory-bean="factoryInstance" factory-method="creatSweetApple"></bean>
package com.EveX.spring.ioc.factory;
import com.EveX.spring.ioc.entity.Apple;
public class AppleFactoryInstance {
public Apple creatSweetApple() {
Apple sweetApple = new Apple();
sweetApple.setTitle("红富士");
sweetApple.setColor("绿色");
sweetApple.setOrigin("欧洲");
return sweetApple;
}
}
4. 启动IoC容器
初始化IoC容器并根据XML配置文件实例化对象
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
}
路径表达式
其中,类的根路径是:
5. 从IoC容器中获取Bean
Apple sweetApple = context.getBean("sweetApple", Apple.class);
6. 依赖注入
利用setter实现对象依赖注入
利用setter实现静态数值注入
- 使用property子标签,利用setter实现对象依赖注入
- 类中需要实现属性的get和set方法,IoC容器自动利用反射机制,运行时调用setXXX()方法为属性赋值
<bean id="sweetApple" class="com.EveX.spring.ioc.entity.Apple">
<property name="title" value="红富士"></property>
<property name="color" value="红色"></property>
<property name="origin" value="欧洲"></property>
</bean>
利用setter实现对象注入
- 使用ref子标签注入依赖对象
<bean id = "lily" class="com.EveX.spring.ioc.entity.Child">
<property name="name" value="莉莉"></property>
<property name="apple" ref="sweetApple"></property>
</bean>
利用构造方法实现对象注入
<bean id="andy" class="com.EveX.spring.ioc.entity.Child">
<constructor-arg name="name" value="安迪"></constructor-arg>
<constructor-arg name="apple" ref="softApple"></constructor-arg>
</bean>
注入集合对象
注入List(默认ArrayList)
注入Set(默认LinkedHashSet-数据有序)
注入Map(默认LinkedHashMap-数据有序)
注入 Properties
使用键值对(key-value pairs)的形式来存储数据,但要求key和value都是字符串类型
获取容器内对象
- 使用getBeanDefinitionNames方法获取所有的bean id,然后通过bean id获取每一个bean对象
String[] beanDefinitionNames = context.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
System.out.println(context.getBean(beanDefinitionName));
}
bean scope属性
<bean id="..." class="..." scope="prototype">
- bean scope属性用于决定对象何时被创建与其作用范围
- bean scope会影响容器中对象的数量
- 默认情况下,bean会在IoC容器创建后自动实例化,且全局唯一
- singleton:在IoC容器中,singleton是单例多线程执行,存在线程安全问题
- prototype:多实例,占用更多资源,不存在线程安全问题
bean生命周期
其中,init-method和destroy-method都是bean的一个子字段,保证其对应的方法名和类的方法相对应即可,在生命周期中会进行执行
Spring框架使用流程-基于注解配置IoC容器
四种组件类型注解
- 组件类型注解默认bean id为首字母小写的类名
- 对于不好分类的类,则使用Component注解
初始化IoC容器
- 在IoC容器初始化时,自动扫描四种组件类型注解并完成实例化
XML配置开启组件扫描
- 比XML配置IoC容器多一行
xmlns:context="http://www.springframework.org/schema/context"
<?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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.EveX">
</beans>
两类自动装配注解
- 如果装配注解放在set方法上,则自动按类型/名称对set方法参数进行注入
- 如果放在属性上,IoC容器会自动通过反射技术将属性private修饰符自动改为public,直接进行赋值,赋值完成后再改为pribate,不会执行set方法。
- 不建议使用按类型注入,如果给一个接口按类型装配,那么其所有实现类都是同类型bean,注入过程会出现问题
@Resource
- 设置了name属性,则直接按照name在IoC容器中将bean注入
- 未设置name属性
(1)首先以属性名作为bean name在IoC容器中匹配bean,如果匹配到了则注入
(2)如果未匹配,则按照类型进行匹配(同@Autowired),如果有冲突,加@Primary注解解决
- 建议:设置name属性 || 保证属性名与bean name一致
元数据注解
通知IoC容器初始化时加载属性文件
<context:property-placeholder location="classpath:config.properties"></context:property-placeholder>
@Value
-
新增配置文件
config.properties
-
添加@Value注解
Spring框架使用流程-基于Java Config配置IoC容器
- 使用独立的Java类管理对象与依赖
Java Config核心注解
Java Config对象实例化
- 增加配置类Config.java
(1)添加@Configuration注解,表示当前类是一个配置类,用于替代applicationContext.xml配置文件
(2)添加@Bean注解,Java Config利用方法创建对象,将方法返回的对象放入容器,bean id=方法名
@Configuration
public class Config {
@Bean
public Apple sweetApple() {
return new Apple();
}
}
- 程序入口
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
Java Config 对象依赖注入
将依赖的对象作为参数传入方法中,对象名作为bean id在容器中存在则直接匹配,如果不存在则进行类型匹配
@Configuration
public class Config {
@Bean
public Apple sweetApple() {
return new Apple();
}
@Bean
public Child lily(Apple sweetApple) {
Child child = new Child();
child.setApple(sweetApple);
return child;
}
}
Spring与JUnit4整合
- 添加spring-test(确保和spring-context版本一致)和junit的依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.3.18</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
-
在测试类上添加@RunWith和@ContextConfiguration注解,将Junit4的执行权交由Spring Test,在测试用例执行前自动初始化IoC容器
-
在测试类中加入需要测试的属性
-
写测试方法
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:applicationContext.xml"})
public class SpringTest {
@Resource
private Child andy;
@Test
public void testAndy() {
andy.eat();
}
}