文章目录
- IOC容器
- IOC容器和beans的介绍
- 实例化 Bean
- BeanFactory:
- ApplicationContext
- 容器概述
- 配置元数据
- 实例化容器
- 组合基于xml的配置元数据
- 使用容器
- bean的概述
- 命名bean
- 别名的使用
- 实例化bean
- 构造函数实例化
- 静态工厂实例化
- 实例工厂方法
- bean 在运行时的实际类型
- 依赖
- 依赖注入
IOC容器
IOC容器和beans的介绍
IOC 容器是 Spring 框架的核心部分之一,它负责管理和维护应用程序中的对象(beans)
“Inversion of Control” 指的是将对象的创建、组装和依赖关系的管理权从应用程序代码转移到框架中
实例化 Bean
IOC 容器有两种主要的实现:
BeanFactory:
这是 Spring 最基本的容器,提供了最简单的 bean 容器功能。它延迟初始化 beans,即只有在请求时才会实际创建和初始化 bean。这对于资源消耗较大的 bean 非常有用。
ApplicationContext
这是 BeanFactory 的子接口,提供了更多的功能,如国际化支持、事件传播、AOP 功能等。ApplicationContext 在启动时会预先实例化和初始化 beans,以便在应用程序运行期间能够更快地访问和使用它们
容器概述
高水平概括
配置元数据
XML 配置文件:
<bean id="userService" class="com.example.UserService">
<property name="userRepository" ref="userRepository" />
</bean>
注解
使用 @Component 注解将一个类标记为一个 Spring bean:
@Component
public class UserService {
// ...
}
Java 配置类:
@Configuration
public class AppConfig {
@Bean
public UserService userService() {
return new UserService();
}
}
实例化容器
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.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">
<!-- services -->
<bean id="petStore" class="org.springframework.samples.jpetstore.services.PetStoreServiceImpl">
<property name="accountDao" ref="accountDao"/>
<property name="itemDao" ref="itemDao"/>
<!-- additional collaborators and configuration for this bean go here -->
</bean>
<!-- more bean definitions for services go here -->
</beans>
组合基于xml的配置元数据
模块化配置:
可以将不同的模块分开定义在不同的 XML 文件中。每个模块可以有自己的配置文件,其中定义了与该模块相关的 beans 和依赖关系。然后,在主配置文件中通过 元素引入这些模块的配置文件
所有位置路径都相对于执行导入的定义文件,
<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">
<import resource="services.xml"/>
<import resource="resources/messageSource.xml"/>
前导斜杠会被忽略。然而,考虑到这些路径是相对的,最好不要使用斜杠
<import resource="/resources/themeSource.xml"/>
<!-- Define additional beans or configurations -->
</beans>
Profile 切换:
你可以使用 Spring 的 Profile 功能,在不同的环境或条件下切换配置
<beans profile="development">
<!-- Define beans and configurations for development environment -->
</beans>
<beans profile="production">
<!-- Define beans and configurations for production environment -->
</beans>
使用容器
意味着在 Spring 框架中如何使用容器来管理和组织你的应用程序的组件
- 定义 Beans:
- 获取 Beans:
//1
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
UserService userService = context.getBean(UserService.class);
//2
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");
//petStore是xml文件中的一个id
PetStoreService service = context.getBean("petStore", PetStoreService.class);
List<String> userList = service.getUsernameList();
//3
GenericApplicationContext context = new GenericApplicationContext();
new XmlBeanDefinitionReader(context).loadBeanDefinitions("services.xml", "daos.xml");
context.refresh();
- 依赖注入:Spring 容器负责处理 beans 之间的依赖关系。你可以通过构造函数注入、setter 方法注入或字段注入等方式
- 生命周期管理:
bean的概述
命名bean
确保 bean 的名称是唯一的,以便在容器中准确引用
- xml
Bean 的名称用于在**容器中引用、获取和识别 beans。**可以通过多种方式指定 bean 的名称
id一定是唯一的
<bean id="userService" class="com.example.UserService" />
name 属性可以指定多个名称,使用逗号或分号分隔。
<bean name="userBean,userService" class="com.example.UserService" />
- java:
可以使用 @Component 注解来为 bean 分配一个默认名称,该名称是类名的小写字母开头的形式。
@Component
public class UserService {
// ...
}
使用 Qualifier 注解:
@Autowired
@Qualifier("userService")
private UserService userService;
使用 Java 配置类:
@Configuration
public class AppConfig {
@Bean
public UserService userService() {
return new UserService();
}
}
别名的使用
- xml
<bean id="userService" class="com.example.UserService" />
<alias name="userService" alias="userManagementService" />
引用别名
<bean id="anotherBean" class="com.example.AnotherBean">
<property name="userService" ref="userManagementService" />
</bean>
2.AliasFor
这要求使用 @AliasFor 注解的类和 bean 必须具有相同的注解类型
@AliasFor("userService")
@Component("userManagementService")
public class UserManagementService {
// ...
}
实例化bean
构造函数实例化
通过调用类的构造函数来完成的
你可以使用 <constructor-arg> 元素来指定构造函数的参数值
<bean id="user" class="com.example.User">
<constructor-arg value="John" />
<constructor-arg value="Doe" />
</bean>
静态工厂实例化
public class UserFactory {
private UserFactory() {
// private constructor to prevent direct instantiation
}
public static User createUser(String firstName, String lastName) {
return new User(firstName, lastName);
}
}
指定工厂类
<bean id="user" class="com.example.UserFactory" factory-method="createUser">
这是值
<constructor-arg value="John" />
<constructor-arg value="Doe" />
</bean>
实例工厂方法
public class UserFactory {
public User createUser(String firstName, String lastName) {
return new User(firstName, lastName);
}
}
指定
<bean id="userFactory" class="com.example.UserFactory" />
<bean id="user" factory-bean="userFactory" factory-method="createUser">
<constructor-arg value="John" />
<constructor-arg value="Doe" />
</bean>
bean 在运行时的实际类型
Bean 类型和代理:用bean类型的和代理的类型
getClass() 方法:返回对象的实际运行时类,要注意,如果有代理存在,这个方法返回的可能是代理类的类型。
AopProxyUtils.ultimateTargetClass() 方法:这个方法会遍历代理链,找到最终的目标类。
目的:你可能需要了解对象的实际类型,特别是在处理代理、动态代理、AOP 等情况时。这有助于你更好地理解对象的行为和工作原理
依赖
依赖注入
Spring 框架的核心概念之一,它用于管理和注入对象之间的依赖关系。依赖注入的目的是降低组件之间的耦合度
- 构造函数
@Component
public class UserService {
private UserRepository userRepository;
@Autowired
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
// ...
package examples;
public class ExampleBean {
// Fields omitted
@ConstructorProperties({"years", "ultimateAnswer"})
public ExampleBean(int years, String ultimateAnswer) {
this.years = years;
this.ultimateAnswer = ultimateAnswer;
使用xml
public class ThingOne {
public ThingOne(ThingTwo thingTwo, ThingThree thingThree) {
// ...
}
}
}
<beans>
<bean id="beanOne" class="x.y.ThingOne">
<constructor-arg ref="beanTwo"/>
<constructor-arg ref="beanThree"/>
</bean>
<bean id="beanTwo" class="x.y.ThingTwo"/>
<bean id="beanThree" class="x.y.ThingThree"/>
</beans>
也可以指定类型
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg type="int" value="7500000"/>
<constructor-arg type="java.lang.String" value="42"/>
</bean>
指定index
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg index="0" value="7500000"/>
<constructor-arg index="1" value="42"/>
</bean>
指定名字
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg name="years" value="7500000"/>
<constructor-arg name="ultimateAnswer" value="42"/>
</bean>
- Setter 方法注入
@Component
public class UserService {
private UserRepository userRepository;
@Autowired
public void setUserRepository(UserRepository userRepository) {
this.userRepository = userRepository;
}
// ...
}
setter与constructor
因此对于**强制依赖项使用构造函数**,而对于**可选依赖项使用setter方法**或配置方法是一条很好的经验法则。**注意,在setter方法上使用@Required注释可以使属性成为required依赖项**
- 字段注入
@Component
public class UserService {
@Autowired
private UserRepository userRepository;
// ...
}