【附录】在spring中BeanDefinition 来源是由哪些?如何理解 BeanDefinition ,他在spring中起到了什么作用?
此文是【Spring 容器详解】的支节点。
什么是BeanDefinition?
概念理解
BeanDefinition是Spring容器中用于描述Bean的元数据对象,它包含了创建Bean实例所需的所有信息。可以把它理解为Bean的"蓝图"或"配方"。
类比理解
如果把Spring容器比作一个工厂,那么:
- BeanDefinition = 产品的设计图纸
- Bean实例 = 根据图纸生产出来的产品
- Spring容器 = 工厂,根据图纸生产产品
BeanDefinition的核心作用
1. 存储Bean的元数据
java
public interface BeanDefinition {
// Bean的类名
void setBeanClassName(String beanClassName);
String getBeanClassName();
// Bean的作用域
void setScope(String scope);
String getScope();
// 是否懒加载
void setLazyInit(boolean lazyInit);
boolean isLazyInit();
// 依赖的Bean
void setDependsOn(String... dependsOn);
String[] getDependsOn();
// 初始化方法
void setInitMethodName(String initMethodName);
String getInitMethodName();
// 销毁方法
void setDestroyMethodName(String destroyMethodName);
String getDestroyMethodName();
// 是否单例
boolean isSingleton();
// 是否原型
boolean isPrototype();
}
2. 指导Bean的创建过程
java
// Spring根据BeanDefinition创建Bean的过程
public Object createBean(String beanName, BeanDefinition beanDefinition) {
// 1. 获取类名
String className = beanDefinition.getBeanClassName();
// 2. 使用反射创建实例
Class<?> clazz = Class.forName(className);
Object bean = clazz.newInstance();
// 3. 设置属性
if (beanDefinition.hasPropertyValues()) {
applyPropertyValues(bean, beanDefinition.getPropertyValues());
}
// 4. 调用初始化方法
if (beanDefinition.getInitMethodName() != null) {
Method initMethod = clazz.getMethod(beanDefinition.getInitMethodName());
initMethod.invoke(bean);
}
return bean;
}
BeanDefinition的来源
1. 注解扫描方式
@Component系列注解
java
// 扫描到@Component注解,创建BeanDefinition
@Component
public class UserService {
// 实现代码
}
// 扫描到@Service注解,创建BeanDefinition
@Service
public class EmailService {
// 实现代码
}
// 扫描到@Repository注解,创建BeanDefinition
@Repository
public class UserDaoImpl implements UserDao {
// 实现代码
}
// 扫描到@Controller注解,创建BeanDefinition
@Controller
public class UserController {
// 实现代码
}
扫描过程:
java
// 1. 扫描器扫描指定包
@ComponentScan("com.example")
public class AppConfig { }
// 2. 发现带有@Component等注解的类
// 3. 为每个类创建BeanDefinition
BeanDefinition userServiceDef = new GenericBeanDefinition();
userServiceDef.setBeanClassName("com.example.UserService");
userServiceDef.setScope("singleton");
userServiceDef.setLazyInit(false);
// 4. 注册到容器
beanDefinitionMap.put("userService", userServiceDef);
@Configuration + @Bean方式
java
@Configuration
public class AppConfig {
@Bean
public UserService userService() {
return new UserService();
}
@Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/test");
dataSource.setUsername("root");
dataSource.setPassword("123456");
return dataSource;
}
@Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
}
@Bean方法解析过程:
java
// 1. 扫描@Configuration类
// 2. 发现@Bean方法
// 3. 为每个@Bean方法创建BeanDefinition
BeanDefinition userServiceDef = new ConfigurationClassBeanDefinition();
userServiceDef.setBeanClassName("com.example.UserService");
userServiceDef.setFactoryMethodName("userService");
userServiceDef.setFactoryBeanName("appConfig");
// 4. 注册到容器
beanDefinitionMap.put("userService", userServiceDef);
2. XML配置方式
传统XML配置
xml
<!-- applicationContext.xml -->
<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 -->
<bean id="userService" class="com.example.UserService">
<property name="userDao" ref="userDao"/>
<property name="emailService" ref="emailService"/>
</bean>
<bean id="userDao" class="com.example.UserDaoImpl">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/test"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
</beans>
XML解析过程:
java
// 1. 解析XML文件
// 2. 为每个<bean>标签创建BeanDefinition
BeanDefinition userServiceDef = new GenericBeanDefinition();
userServiceDef.setBeanClassName("com.example.UserService");
userServiceDef.setScope("singleton");
// 3. 设置属性值
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add("userDao", new RuntimeBeanReference("userDao"));
propertyValues.add("emailService", new RuntimeBeanReference("emailService"));
userServiceDef.setPropertyValues(propertyValues);
// 4. 注册到容器
beanDefinitionMap.put("userService", userServiceDef);
3. 编程方式
手动注册BeanDefinition
java
// 手动创建和注册BeanDefinition
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
// 创建BeanDefinition
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClassName("com.example.UserService");
beanDefinition.setScope("singleton");
beanDefinition.setLazyInit(false);
// 设置属性
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add("userDao", new RuntimeBeanReference("userDao"));
beanDefinition.setPropertyValues(propertyValues);
// 注册BeanDefinition
context.registerBeanDefinition("userService", beanDefinition);
// 刷新容器
context.refresh();
使用BeanDefinitionBuilder
java
// 使用Builder模式创建BeanDefinition
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(UserService.class);
builder.setScope(BeanDefinition.SCOPE_SINGLETON);
builder.addPropertyReference("userDao", "userDao");
builder.addPropertyReference("emailService", "emailService");
BeanDefinition beanDefinition = builder.getBeanDefinition();
context.registerBeanDefinition("userService", beanDefinition);
4. Spring Boot自动配置
@EnableAutoConfiguration
java
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
// Spring Boot自动配置过程:
// 1. 扫描META-INF/spring.factories文件
// 2. 加载AutoConfiguration类
// 3. 根据条件创建BeanDefinition
// 4. 注册到容器
自动配置示例
java
@Configuration
@ConditionalOnClass(DataSource.class)
@EnableConfigurationProperties(DataSourceProperties.class)
public class DataSourceAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public DataSource dataSource(DataSourceProperties properties) {
return properties.initializeDataSourceBuilder().build();
}
}
// 自动配置过程:
// 1. 检查classpath中是否有DataSource类
// 2. 检查容器中是否已有DataSource Bean
// 3. 如果条件满足,创建DataSource的BeanDefinition
// 4. 注册到容器
BeanDefinition的类型
1. GenericBeanDefinition
java
// 通用的BeanDefinition实现
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClassName("com.example.UserService");
beanDefinition.setScope("singleton");
beanDefinition.setLazyInit(false);
2. RootBeanDefinition
java
// 根BeanDefinition,用于父Bean
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(UserService.class);
rootBeanDefinition.setScope("singleton");
3. ChildBeanDefinition
java
// 子BeanDefinition,继承父Bean的配置
ChildBeanDefinition childBeanDefinition = new ChildBeanDefinition("parentBean");
childBeanDefinition.setBeanClassName("com.example.UserServiceImpl");
4. ConfigurationClassBeanDefinition
java
// 用于@Configuration类中的@Bean方法
ConfigurationClassBeanDefinition beanDefinition = new ConfigurationClassBeanDefinition();
beanDefinition.setBeanClassName("com.example.UserService");
beanDefinition.setFactoryMethodName("userService");
beanDefinition.setFactoryBeanName("appConfig");
BeanDefinition在Spring中的作用
1. 指导Bean的创建
java
// Spring根据BeanDefinition创建Bean
public Object createBean(String beanName, BeanDefinition beanDefinition) {
// 1. 获取类名
String className = beanDefinition.getBeanClassName();
// 2. 创建实例
Class<?> clazz = Class.forName(className);
Object bean = clazz.newInstance();
// 3. 设置属性
if (beanDefinition.hasPropertyValues()) {
applyPropertyValues(bean, beanDefinition.getPropertyValues());
}
// 4. 注入依赖
if (beanDefinition.hasPropertyValues()) {
autowireProperties(bean, beanDefinition);
}
// 5. 调用初始化方法
if (beanDefinition.getInitMethodName() != null) {
invokeInitMethod(bean, beanDefinition.getInitMethodName());
}
return bean;
}
2. 管理Bean的生命周期
java
// 根据BeanDefinition管理Bean的生命周期
public class BeanLifecycleManager {
public void manageBeanLifecycle(Object bean, BeanDefinition beanDefinition) {
// 1. 初始化前处理
applyBeanPostProcessorsBeforeInitialization(bean, beanName);
// 2. 调用初始化方法
if (beanDefinition.getInitMethodName() != null) {
invokeInitMethod(bean, beanDefinition.getInitMethodName());
}
// 3. 初始化后处理
applyBeanPostProcessorsAfterInitialization(bean, beanName);
// 4. 注册销毁方法
if (beanDefinition.getDestroyMethodName() != null) {
registerDisposableBean(bean, beanDefinition.getDestroyMethodName());
}
}
}
3. 支持依赖注入
java
// 根据BeanDefinition进行依赖注入
public class DependencyInjectionManager {
public void injectDependencies(Object bean, BeanDefinition beanDefinition) {
// 1. 获取依赖信息
PropertyValues propertyValues = beanDefinition.getPropertyValues();
// 2. 注入属性
for (PropertyValue propertyValue : propertyValues.getPropertyValues()) {
String propertyName = propertyValue.getName();
Object propertyValue = propertyValue.getValue();
// 3. 设置属性值
setPropertyValue(bean, propertyName, propertyValue);
}
}
}
4. 支持AOP
java
// 根据BeanDefinition创建AOP代理
public class AopProxyManager {
public Object createAopProxy(Object bean, BeanDefinition beanDefinition) {
// 1. 检查是否需要AOP
if (shouldCreateProxy(bean, beanDefinition)) {
// 2. 创建代理
return createProxy(bean, beanDefinition);
}
return bean;
}
}
实际应用示例
完整的BeanDefinition使用示例
java
@Configuration
public class AppConfig {
@Bean
public UserService userService(UserDao userDao, EmailService emailService) {
UserService userService = new UserService();
userService.setUserDao(userDao);
userService.setEmailService(emailService);
return userService;
}
@Bean
public UserDao userDao(DataSource dataSource) {
return new UserDaoImpl(dataSource);
}
@Bean
public EmailService emailService() {
return new EmailServiceImpl();
}
@Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/test");
dataSource.setUsername("root");
dataSource.setPassword("123456");
return dataSource;
}
}
// Spring处理过程:
// 1. 扫描@Configuration类
// 2. 为每个@Bean方法创建BeanDefinition
// 3. 分析依赖关系
// 4. 按依赖顺序创建Bean实例
总结
BeanDefinition的来源:
- 注解扫描 - @Component、@Service、@Repository、@Controller
- @Configuration + @Bean - 配置类中的@Bean方法
- XML配置 - 传统的标签配置
- 编程方式 - 手动创建和注册BeanDefinition
- Spring Boot自动配置 - 基于条件的自动配置
BeanDefinition的作用:
- 存储元数据 - 存储Bean的类名、作用域、依赖等信息
- 指导创建 - 指导Spring如何创建Bean实例
- 管理生命周期 - 管理Bean的初始化、销毁等生命周期
- 支持依赖注入 - 提供依赖注入所需的信息
- 支持AOP - 提供AOP代理创建所需的信息
BeanDefinition的重要性:
BeanDefinition是Spring IoC容器的核心概念,它:
- 将Bean的配置信息从代码中分离出来
- 支持多种配置方式(注解、XML、编程)
- 提供了灵活的Bean创建和管理机制
- 是Spring实现依赖注入和AOP的基础
理解BeanDefinition对于深入理解Spring的工作原理非常重要。