导航
📖 本讲目标
- 完善 BeanDefinition 的设计
- 实现 Bean 名称生成策略
- 理解 Bean 注册流程
- 实现异常处理机制
🎯 BeanDefinition 完整设计
设计思路
BeanDefinition 是容器管理 Bean 的核心数据结构,它需要存储:
- 基本信息:类类型、Bean 名称
- 作用域信息:singleton 或 prototype
- 生命周期信息:懒加载、初始化方法、销毁方法
- 依赖信息:依赖的其他 Bean
完整实现
更新 src/main/java/com/minispring/beans/factory/config/BeanDefinition.java:
package com.minispring.beans.factory.config;
import java.util.HashSet;
import java.util.Set;
/**
* BeanDefinition 类
* 存储 Bean 的元数据信息,是 IoC 容器管理 Bean 的核心数据结构
*/
public class BeanDefinition {
// Bean 的 Class 类型,用于反射创建实例
private Class<?> beanClass;
// Bean 在容器中的唯一名称
private String beanName;
// Bean 的作用域:singleton(单例)或 prototype(原型)
private String scope = "singleton"; // 默认单例
// 是否懒加载
private boolean lazy = false;
// 是否为主要候选者(当有多个相同类型的 Bean 时优先选择)
private boolean primary = false;
// 依赖的其他 Bean 名称集合
private Set<String> dependsOn = new HashSet<>();
// 初始化方法名称
private String initMethodName;
// 销毁方法名称
private String destroyMethodName;
/**
* 构造函数
*/
public BeanDefinition() {
}
/**
* 构造函数
* @param beanClass Bean 的 Class 类型
*/
public BeanDefinition(Class<?> beanClass) {
this.beanClass = beanClass;
this.beanName = generateDefaultBeanName(beanClass);
}
/**
* 完整构造函数
* @param beanClass Bean 的 Class 类型
* @param beanName Bean 名称
*/
public BeanDefinition(Class<?> beanClass, String beanName) {
this.beanClass = beanClass;
this.beanName = beanName;
}
/**
* 生成默认的 Bean 名称(类名首字母小写)
* @param clazz Class 类型
* @return Bean 名称
*/
private String generateDefaultBeanName(Class<?> clazz) {
String simpleName = clazz.getSimpleName();
return Character.toLowerCase(simpleName.charAt(0)) + simpleName.substring(1);
}
// ==================== Getter 和 Setter 方法 ====================
public Class<?> getBeanClass() {
return beanClass;
}
public void setBeanClass(Class<?> beanClass) {
this.beanClass = beanClass;
}
public String getBeanName() {
return beanName;
}
public void setBeanName(String beanName) {
this.beanName = beanName;
}
public String getScope() {
return scope;
}
public void setScope(String scope) {
this.scope = scope;
}
/**
* 判断是否为单例模式
* @return true 表示单例
*/
public boolean isSingleton() {
return "singleton".equals(scope);
}
/**
* 判断是否为原型模式
* @return true 表示原型
*/
public boolean isPrototype() {
return "prototype".equals(scope);
}
public boolean isLazy() {
return lazy;
}
public void setLazy(boolean lazy) {
this.lazy = lazy;
}
public boolean isPrimary() {
return primary;
}
public void setPrimary(boolean primary) {
this.primary = primary;
}
public Set<String> getDependsOn() {
return dependsOn;
}
public void setDependsOn(Set<String> dependsOn) {
this.dependsOn = dependsOn;
}
/**
* 添加依赖的 Bean 名称
* @param beanName 依赖的 Bean 名称
*/
public void addDependsOn(String beanName) {
this.dependsOn.add(beanName);
}
public String getInitMethodName() {
return initMethodName;
}
public void setInitMethodName(String initMethodName) {
this.initMethodName = initMethodName;
}
public String getDestroyMethodName() {
return destroyMethodName;
}
public void setDestroyMethodName(String destroyMethodName) {
this.destroyMethodName = destroyMethodName;
}
@Override
public String toString() {
return "BeanDefinition{" +
"beanClass=" + beanClass.getName() +
", beanName='" + beanName + ''' +
", scope='" + scope + ''' +
", lazy=" + lazy +
", primary=" + primary +
'}';
}
}
🏷️ Bean 名称生成策略
默认命名规则
Spring 框架的默认 Bean 命名规则:
- 如果类名以大写字母开头,将首字母转为小写
- 例如:
UserService→userService - 例如:
OrderRepository→orderRepository
实现细节
private String generateDefaultBeanName(Class<?> clazz) {
String simpleName = clazz.getSimpleName();
if (simpleName == null || simpleName.isEmpty()) {
throw new IllegalArgumentException("类名不能为空");
}
// 首字母转小写
char firstChar = simpleName.charAt(0);
if (Character.isLowerCase(firstChar)) {
return simpleName; // 已经是小写开头
}
return Character.toLowerCase(firstChar) + simpleName.substring(1);
}
特殊情况处理
- 连续大写字母:
XMLParser→XMLParser(保持原样) - 单个字母:
A→a - 空类名:抛出异常
⚠️ 异常处理机制
异常类设计
创建异常类层次结构:
1. BeansException(基础异常)
package com.minispring.beans.factory;
/**
* Bean 操作相关的通用异常基类
*/
public class BeansException extends RuntimeException {
public BeansException(String message) {
super(message);
}
public BeansException(String message, Throwable cause) {
super(message, cause);
}
}
2. NoSuchBeanDefinitionException
package com.minispring.beans.factory;
/**
* 当容器中找不到指定名称或类型的 Bean 时抛出此异常
*/
public class NoSuchBeanDefinitionException extends BeansException {
public NoSuchBeanDefinitionException(String beanName) {
super("找不到 Bean: " + beanName);
}
public NoSuchBeanDefinitionException(Class<?> beanType) {
super("找不到类型为 " + beanType.getName() + " 的 Bean");
}
}
3. BeanNotOfRequiredTypeException
package com.minispring.beans.factory;
/**
* 当 Bean 的类型与期望的类型不匹配时抛出此异常
*/
public class BeanNotOfRequiredTypeException extends BeansException {
private final String beanName;
private final Class<?> requiredType;
private final Class<?> actualType;
public BeanNotOfRequiredTypeException(String beanName, Class<?> requiredType, Class<?> actualType) {
super("Bean '" + beanName + "' 的类型不匹配: 期望类型 " + requiredType.getName() +
", 实际类型 " + actualType.getName());
this.beanName = beanName;
this.requiredType = requiredType;
this.actualType = actualType;
}
// Getters...
}
4. NoUniqueBeanDefinitionException
package com.minispring.beans.factory;
/**
* 当容器中存在多个相同类型的 Bean 且无法确定使用哪一个时抛出此异常
*/
public class NoUniqueBeanDefinitionException extends BeansException {
private final Class<?> beanType;
private final int foundBeansCount;
public NoUniqueBeanDefinitionException(Class<?> beanType, int foundBeansCount) {
super("找到 " + foundBeansCount + " 个类型为 " + beanType.getName() +
" 的 Bean,无法确定使用哪一个");
this.beanType = beanType;
this.foundBeansCount = foundBeansCount;
}
// Getters...
}
更新 ApplicationContext 使用异常
@Override
public Object getBean(String beanName) throws Exception {
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
if (beanDefinition == null) {
throw new NoSuchBeanDefinitionException(beanName);
}
// ...
}
@Override
public <T> T getBean(String beanName, Class<T> requiredType) throws Exception {
Object bean = getBean(beanName);
if (requiredType != null && !requiredType.isInstance(bean)) {
throw new BeanNotOfRequiredTypeException(beanName, requiredType, bean.getClass());
}
return (T) bean;
}
🔄 Bean 注册流程
注册方法
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) {
// 1. 参数校验
if (beanName == null || beanName.isEmpty()) {
throw new IllegalArgumentException("Bean 名称不能为空");
}
if (beanDefinition == null) {
throw new IllegalArgumentException("BeanDefinition 不能为空");
}
// 2. 检查是否已存在
if (beanDefinitionMap.containsKey(beanName)) {
throw new RuntimeException("Bean 名称重复: " + beanName);
}
// 3. 注册
beanDefinitionMap.put(beanName, beanDefinition);
System.out.println("注册 Bean: " + beanName + " [scope=" +
beanDefinition.getScope() + "]");
}
注册时机
Bean 的注册可以在以下时机进行:
- 手动注册:通过
registerBeanDefinition方法 - 自动扫描:通过组件扫描器(后续实现)
- 配置类:通过 @Configuration 类(不在本教程范围)
🧪 测试示例
package com.minispring.demo;
import com.minispring.beans.factory.config.BeanDefinition;
import com.minispring.beans.factory.NoSuchBeanDefinitionException;
import com.minispring.context.ApplicationContext;
public class BeanDefinitionTest {
public static void main(String[] args) throws Exception {
ApplicationContext context = new ApplicationContext();
// 创建 BeanDefinition
BeanDefinition bd = new BeanDefinition();
bd.setBeanClass(String.class);
bd.setBeanName("testBean");
bd.setScope("singleton");
bd.setLazy(false);
// 注册
context.registerBeanDefinition("testBean", bd);
// 测试获取
Object bean = context.getBean("testBean");
System.out.println("Bean: " + bean);
// 测试异常
try {
context.getBean("nonExistentBean");
} catch (NoSuchBeanDefinitionException e) {
System.out.println("正确捕获异常: " + e.getMessage());
}
}
}
📝 本讲总结
本讲我们完成了:
- ✅ 完善了 BeanDefinition 的完整设计
- ✅ 实现了 Bean 名称生成策略
- ✅ 创建了异常处理机制
- ✅ 实现了 Bean 注册流程
- ✅ 添加了 Bean 的元数据属性(lazy、primary、dependsOn 等)
🎯 关键点回顾
- BeanDefinition:存储 Bean 的所有元数据信息
- 命名策略:首字母小写的默认命名规则
- 异常体系:完善的异常类层次结构
- 注册机制:通过 Map 存储 BeanDefinition
🚀 下一讲预告
在下一讲中,我们将实现 依赖注入 – 字段注入,包括:
- @Autowired 注解实现
- 反射机制应用
- 按类型自动匹配
- 循环依赖检测
准备好了吗?让我们继续 第 04 讲:依赖注入 – 字段注入!
思考题:
- BeanDefinition 为什么要存储这么多信息?
- 为什么使用 Set 存储 dependsOn?
- 异常类为什么要设计成层次结构?
