关键词:Spring 源码, Bean 定义, XML 配置, 注解配置, 组件扫描, ApplicationContext, 手写框架


写在前面

在前面的文章中,我们已经手写实现了 Spring 的 IoCDIAOP 功能。但是,我们在使用这些功能时发现,代码调用非常繁琐:

// 手动注册 Bean 定义,代码重复且容易出错
GenericBeanDefinition bd = new GenericBeanDefinition();
bd.setBeanClass(ABean.class);
List<Object> args = new ArrayList<>();
args.add("abean01");
args.add(new BeanReference("cbean"));
bd.setConstructorArgumentValues(args);
bf.registerBeanDefinition("abean", bd);

这种方式不仅重复代码多容易出错,而且给使用者带来了很不好的体验。那么 Spring 是如何解决这个问题的呢?

本文将带你实现 Spring 的 Bean 定义配置化功能,支持 XML 配置注解配置 两种方式,让你的手写 Spring 框架更加完善和易用。


目录


一、问题分析与方案设计

1.1 现有问题

回顾之前的手写 Spring 框架,我们在使用时有以下痛点:

// 创建 BeanFactory
DefaultBeanFactory factory = new DefaultBeanFactory();

// 注册 CBean
GenericBeanDefinition cDef = new GenericBeanDefinition();
cDef.setBeanClass(CBean.class);
List<Object> cArgs = new ArrayList<>();
cArgs.add("cbean01");
cDef.setConstructorArgumentValues(cArgs);
factory.registerBeanDefinition("cbean", cDef);

// 注册 ABean,依赖 CBean
GenericBeanDefinition aDef = new GenericBeanDefinition();
aDef.setBeanClass(ABean.class);
List<Object> aArgs = new ArrayList<>();
aArgs.add("abean01");
aArgs.add(new BeanReference("cbean"));  // 依赖引用
aDef.setConstructorArgumentValues(aArgs);
factory.registerBeanDefinition("abean", aDef);

// 获取 Bean
ABean aBean = (ABean) factory.getBean("abean");

问题总结

问题 说明
代码重复 每个 Bean 都需要创建 GenericBeanDefinition
容易出错 BeanReference 容易写错,类型容易不匹配
可读性差 大量 Java 代码淹没业务逻辑
维护困难 修改配置需要修改代码并重新编译

1.2 Spring 的解决方案

Spring 提供了两种优雅的配置方式:

方式一:XML 配置

<?xml version="1.0" encoding="UTF-8"?>
<beans>
    <bean id="abean" class="com.study.spring.samples.ABean">
        <constructor-arg type="String" value="abean01" />
        <constructor-arg ref="cbean" />
    </bean>

    <bean id="cbean" class="com.study.spring.samples.CBean">
        <constructor-arg type="String" value="cbean01" />
    </bean>
</beans>

方式二:注解配置

@Component
public class AController {
    @Autowired
    private Acc acc;
}

@Service
public class UserService {
    @Autowired
    private UserDao userDao;
    
    @PostConstruct
    public void init() {
        // 初始化逻辑
    }
}

1.3 我们要实现的功能

功能清单

  1. XML 配置支持

    • 定义 XML 规范
    • 实现 XML 解析器
    • 完成 Bean 定义注册
  2. 注解配置支持

    • 定义一套注解(@Component@Autowired 等)
    • 实现包扫描
    • 解析注解并注册 Bean 定义
  3. ApplicationContext

    • 使用外观模式封装底层细节
    • 提供统一简洁的使用界面

二、XML 配置方式实现

2.1 XML 规范设计

XML 结构设计

<?xml version="1.0" encoding="UTF-8"?>
<beans>
    <!-- 基本 Bean 定义 -->
    <bean id="userDao" class="com.boge.dao.UserDao" />
    
    <!-- 构造器注入 -->
    <bean id="userService" class="com.boge.service.UserService">
        <constructor-arg ref="userDao" />
    </bean>
    
    <!-- 属性注入 -->
    <bean id="orderService" class="com.boge.service.OrderService">
        <property name="userDao" ref="userDao" />
        <property name="timeout" value="5000" />
    </bean>
    
    <!-- 带参数的构造器 -->
    <bean id="dataSource" class="com.boge.DataSource">
        <constructor-arg type="String" value="jdbc:mysql://localhost:3306/test" />
        <constructor-arg type="String" value="root" />
        <constructor-arg type="String" value="password" />
    </bean>
    
    <!-- Scope 和初始化方法 -->
    <bean id="cache" class="com.boge.Cache" 
          scope="singleton" 
          init-method="init" 
          destroy-method="destroy" />
</beans>

XML 元素说明

元素 属性 说明
<beans> - 根元素,包含所有 Bean 定义
<bean> id Bean 的唯一标识
<bean> class Bean 的全限定类名
<bean> scope 作用域(singleton/prototype)
<bean> init-method 初始化方法名
<bean> destroy-method 销毁方法名
<constructor-arg> value 构造参数值(直接值)
<constructor-arg> ref 构造参数引用(Bean 依赖)
<constructor-arg> type 参数类型
<property> name 属性名
<property> value 属性值
<property> ref 属性引用

2.2 XML 解析器实现

解析流程

读取 XML 文件
    │
    ▼
解析 DOM 树
    │
    ▼
遍历 <bean> 元素
    │
    ├── 提取 id、class、scope 等属性
    │
    ├── 解析 <constructor-arg> 元素
    │   └── 创建构造参数列表
    │
    ├── 解析 <property> 元素
    │   └── 创建属性值列表
    │
    └── 创建 BeanDefinition 并注册

XMLBeanDefinitionReader 实现

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

/**
 * XML Bean 定义读取器
 */
public class XmlBeanDefinitionReader {
    
    private BeanDefinitionRegistry registry;  // Bean 定义注册中心
    
    public XmlBeanDefinitionReader(BeanDefinitionRegistry registry) {
        this.registry = registry;
    }
    
    /**
     * 加载 XML 配置文件
     * @param location XML 文件路径
     */
    public void loadBeanDefinitions(String location) throws Exception {
        // 1. 加载 XML 文件
        InputStream is = this.getClass().getClassLoader().getResourceAsStream(location);
        if (is == null) {
            throw new RuntimeException("找不到配置文件: " + location);
        }
        
        // 2. 解析 XML
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        Document doc = builder.parse(is);
        
        // 3. 解析 <bean> 元素
        Element root = doc.getDocumentElement();
        NodeList beanNodes = root.getElementsByTagName("bean");
        
        for (int i = 0; i < beanNodes.getLength(); i++) {
            Node beanNode = beanNodes.item(i);
            if (beanNode instanceof Element) {
                parseBeanElement((Element) beanNode);
            }
        }
    }
    
    /**
     * 解析 <bean> 元素
     */
    private void parseBeanElement(Element beanElement) throws Exception {
        // 1. 获取基本属性
        String beanName = beanElement.getAttribute("id");
        String className = beanElement.getAttribute("class");
        String scope = beanElement.getAttribute("scope");
        String initMethod = beanElement.getAttribute("init-method");
        String destroyMethod = beanElement.getAttribute("destroy-method");
        
        // 2. 创建 BeanDefinition
        GenericBeanDefinition bd = new GenericBeanDefinition();
        bd.setBeanClass(Class.forName(className));
        
        // 3. 设置 Scope
        if (!scope.isEmpty()) {
            bd.setScope(scope);
        }
        
        // 4. 设置初始化和销毁方法
        if (!initMethod.isEmpty()) {
            bd.setInitMethodName(initMethod);
        }
        if (!destroyMethod.isEmpty()) {
            bd.setDestroyMethodName(destroyMethod);
        }
        
        // 5. 解析构造参数
        parseConstructorArgs(beanElement, bd);
        
        // 6. 解析属性
        parseProperties(beanElement, bd);
        
        // 7. 注册 Bean 定义
        registry.registerBeanDefinition(beanName, bd);
    }
    
    /**
     * 解析构造参数
     */
    private void parseConstructorArgs(Element beanElement, GenericBeanDefinition bd) {
        NodeList argNodes = beanElement.getElementsByTagName("constructor-arg");
        List<Object> args = new ArrayList<>();
        
        for (int i = 0; i < argNodes.getLength(); i++) {
            Element argElement = (Element) argNodes.item(i);
            Object value = parseValue(argElement);
            args.add(value);
        }
        
        if (!args.isEmpty()) {
            bd.setConstructorArgumentValues(args);
        }
    }
    
    /**
     * 解析属性
     */
    private void parseProperties(Element beanElement, GenericBeanDefinition bd) {
        NodeList propNodes = beanElement.getElementsByTagName("property");
        List<PropertyValue> propertyValues = new ArrayList<>();
        
        for (int i = 0; i < propNodes.getLength(); i++) {
            Element propElement = (Element) propNodes.item(i);
            String propName = propElement.getAttribute("name");
            Object value = parseValue(propElement);
            propertyValues.add(new PropertyValue(propName, value));
        }
        
        if (!propertyValues.isEmpty()) {
            bd.setPropertyValues(propertyValues);
        }
    }
    
    /**
     * 解析值(value 或 ref)
     */
    private Object parseValue(Element element) {
        String value = element.getAttribute("value");
        String ref = element.getAttribute("ref");
        String type = element.getAttribute("type");
        
        if (!ref.isEmpty()) {
            // Bean 引用
            return new BeanReference(ref);
        } else if (!value.isEmpty()) {
            // 直接值,可能需要类型转换
            return convertValue(value, type);
        }
        
        return null;
    }
    
    /**
     * 类型转换
     */
    private Object convertValue(String value, String type) {
        if (type.isEmpty() || "String".equals(type)) {
            return value;
        } else if ("int".equals(type) || "Integer".equals(type)) {
            return Integer.parseInt(value);
        } else if ("long".equals(type) || "Long".equals(type)) {
            return Long.parseLong(value);
        } else if ("boolean".equals(type) || "Boolean".equals(type)) {
            return Boolean.parseBoolean(value);
        } else if ("double".equals(type) || "Double".equals(type)) {
            return Double.parseDouble(value);
        }
        return value;
    }
}

2.3 与 BeanFactory 集成

使用示例

public class XmlConfigTest {
    
    public static void main(String[] args) throws Exception {
        // 1. 创建 BeanFactory
        DefaultBeanFactory factory = new DefaultBeanFactory();
        
        // 2. 创建 XML 读取器
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
        
        // 3. 加载 XML 配置
        reader.loadBeanDefinitions("application-context.xml");
        
        // 4. 获取 Bean 并使用
        UserService userService = (UserService) factory.getBean("userService");
        userService.save(new User("张三"));
    }
}

XML 配置文件(application-context.xml):

<?xml version="1.0" encoding="UTF-8"?>
<beans>
    <!-- Dao 层 -->
    <bean id="userDao" class="com.boge.dao.UserDaoImpl" />
    
    <!-- Service 层 -->
    <bean id="userService" class="com.boge.service.UserServiceImpl">
        <constructor-arg ref="userDao" />
    </bean>
    
    <!-- 带属性的 Bean -->
    <bean id="config" class="com.boge.Config">
        <property name="appName" value="MyApplication" />
        <property name="maxConnections" value="100" />
        <property name="timeout" value="5000" />
    </bean>
</beans>

三、注解配置方式实现

3.1 注解体系设计

需要定义的注解清单

注解 作用 目标
@Component 标识类为 Bean
@Service 标识服务层 Bean
@Repository 标识数据层 Bean
@Controller 标识控制层 Bean
@Scope 设置作用域
@Primary 设置主要 Bean
@Bean 工厂方法 方法
@PostConstruct 初始化方法 方法
@PreDestroy 销毁方法 方法
@Autowired 自动注入(构造器、属性) 构造器、字段
@Value 注入直接值 字段
@Qualifier 指定 Bean 名称 字段、参数

注解定义

import java.lang.annotation.*;

/**
 * 组件注解,标识类需要被 Spring 管理
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Component {
    String value() default "";  // Bean 名称,默认类名首字母小写
}

/**
 * 服务层注解
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Component
public @interface Service {
    String value() default "";
}

/**
 * 数据访问层注解
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Component
public @interface Repository {
    String value() default "";
}

/**
 * 作用域注解
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Scope {
    String value() default "singleton";  // singleton 或 prototype
}

/**
 * 主要 Bean 注解
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Primary {
}

/**
 * 自动注入注解
 */
@Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Autowired {
    boolean required() default true;
}

/**
 * 值注入注解
 */
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface Value {
    String value();
}

/**
 * 初始化方法注解
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface PostConstruct {
}

/**
 * 销毁方法注解
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface PreDestroy {
}

/**
 * 工厂方法注解
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Bean {
    String value() default "";
}

/**
 * 限定符注解
 */
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface Qualifier {
    String value();
}

3.2 组件扫描实现

扫描流程

指定扫描包路径
    │
    ▼
递归扫描包目录
    │
    ├── 找到所有 .class 文件
    │
    ├── 加载 Class 对象
    │
    ├── 判断是否有 @Component 注解
    │
    ├── 解析类上的其他注解
    │
    ├── 解析方法上的注解
    │
    ├── 解析字段上的注解
    │
    └── 注册 Bean 定义

ClassPathBeanDefinitionScanner 实现

import java.io.File;
import java.net.URL;
import java.util.HashSet;
import java.util.Set;

/**
 * 类路径 Bean 定义扫描器
 */
public class ClassPathBeanDefinitionScanner {
    
    private BeanDefinitionRegistry registry;
    
    public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry) {
        this.registry = registry;
    }
    
    /**
     * 扫描指定包
     * @param basePackages 基础包路径
     */
    public void scan(String... basePackages) throws Exception {
        if (basePackages == null || basePackages.length == 0) {
            return;
        }
        
        for (String basePackage : basePackages) {
            // 1. 递归扫描包目录下的 .class 文件
            Set<File> classFiles = doScan(basePackage);
            
            // 2. 加载 Class 并解析注解,注册 Bean 定义
            readAndRegisterBeanDefinition(classFiles, basePackage);
        }
    }
    
    /**
     * 递归扫描 .class 文件
     */
    private Set<File> doScan(String basePackage) {
        Set<File> classFiles = new HashSet<>();
        
        // 将包路径转换为文件路径
        String path = basePackage.replace(".", "/");
        URL url = this.getClass().getClassLoader().getResource(path);
        
        if (url != null) {
            File dir = new File(url.getFile());
            if (dir.exists()) {
                scanDirectory(dir, classFiles);
            }
        }
        
        return classFiles;
    }
    
    /**
     * 递归扫描目录
     */
    private void scanDirectory(File dir, Set<File> classFiles) {
        File[] files = dir.listFiles();
        if (files == null) return;
        
        for (File file : files) {
            if (file.isDirectory()) {
                scanDirectory(file, classFiles);
            } else if (file.getName().endsWith(".class")) {
                classFiles.add(file);
            }
        }
    }
    
    /**
     * 读取并注册 Bean 定义
     */
    private void readAndRegisterBeanDefinition(Set<File> classFiles, String basePackage) 
            throws BeanDefinitionRegistException {
        
        for (File classFile : classFiles) {
            String className = getClassNameFromFile(classFile, basePackage);
            
            try {
                // 加载类
                Class<?> clazz = this.getClass().getClassLoader().loadClass(className);
                
                // 检查是否有 @Component 或其派生注解
                Component component = clazz.getAnnotation(Component.class);
                if (component == null) {
                    // 检查其他派生注解
                    component = checkComponentMetaAnnotation(clazz);
                }
                
                if (component != null) {
                    // 生成 Bean 名称
                    String beanName = component.value();
                    if (beanName.isEmpty()) {
                        beanName = generateBeanName(clazz);
                    }
                    
                    // 创建 BeanDefinition
                    GenericBeanDefinition bd = new GenericBeanDefinition();
                    bd.setBeanClass(clazz);
                    
                    // 解析类级别的注解
                    parseClassAnnotations(clazz, bd);
                    
                    // 解析构造器
                    parseConstructor(clazz, bd);
                    
                    // 解析方法(初始化、销毁、工厂方法)
                    parseMethods(clazz, bd, beanName);
                    
                    // 解析字段(属性注入)
                    parseFields(clazz, bd);
                    
                    // 注册 Bean 定义
                    registry.registerBeanDefinition(beanName, bd);
                    
                    // 注册 @Bean 方法定义的 Bean
                    registerBeanMethods(clazz, bd);
                }
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
    }
    
    /**
     * 检查元注解
     */
    private Component checkComponentMetaAnnotation(Class<?> clazz) {
        // 检查 @Service
        Service service = clazz.getAnnotation(Service.class);
        if (service != null) {
            return new Component() {
                @Override
                public String value() { return service.value(); }
                @Override
                public Class<? extends Annotation> annotationType() { return Component.class; }
            };
        }
        
        // 检查 @Repository
        Repository repository = clazz.getAnnotation(Repository.class);
        if (repository != null) {
            return new Component() {
                @Override
                public String value() { return repository.value(); }
                @Override
                public Class<? extends Annotation> annotationType() { return Component.class; }
            };
        }
        
        // 检查 @Controller
        Controller controller = clazz.getAnnotation(Controller.class);
        if (controller != null) {
            return new Component() {
                @Override
                public String value() { return controller.value(); }
                @Override
                public Class<? extends Annotation> annotationType() { return Component.class; }
            };
        }
        
        return null;
    }
    
    /**
     * 从文件获取类名
     */
    private String getClassNameFromFile(File classFile, String basePackage) {
        String fileName = classFile.getAbsolutePath();
        String className = fileName.substring(fileName.indexOf(basePackage.replace(".", File.separator)))
                                    .replace(File.separator, ".")
                                    .replace(".class", "");
        return className;
    }
    
    /**
     * 生成 Bean 名称(类名首字母小写)
     */
    private String generateBeanName(Class<?> clazz) {
        String className = clazz.getSimpleName();
        return className.substring(0, 1).toLowerCase() + className.substring(1);
    }
    
    /**
     * 解析类级别注解
     */
    private void parseClassAnnotations(Class<?> clazz, GenericBeanDefinition bd) {
        // 解析 @Scope
        Scope scope = clazz.getAnnotation(Scope.class);
        if (scope != null) {
            bd.setScope(scope.value());
        }
        
        // 解析 @Primary
        Primary primary = clazz.getAnnotation(Primary.class);
        if (primary != null) {
            bd.setPrimary(true);
        }
    }
    
    /**
     * 解析构造器
     */
    private void parseConstructor(Class<?> clazz, GenericBeanDefinition bd) {
        // 查找带有 @Autowired 的构造器
        for (Constructor<?> constructor : clazz.getDeclaredConstructors()) {
            Autowired autowired = constructor.getAnnotation(Autowired.class);
            if (autowired != null) {
                // 使用这个构造器
                bd.setConstructor(constructor);
                
                // 解析参数
                List<Object> args = new ArrayList<>();
                for (Parameter param : constructor.getParameters()) {
                    Object arg = resolveParameter(param);
                    args.add(arg);
                }
                bd.setConstructorArgumentValues(args);
                break;
            }
        }
    }
    
    /**
     * 解析参数
     */
    private Object resolveParameter(Parameter param) {
        // 解析 @Value
        Value value = param.getAnnotation(Value.class);
        if (value != null) {
            return value.value();
        }
        
        // 解析 @Qualifier
        Qualifier qualifier = param.getAnnotation(Qualifier.class);
        if (qualifier != null) {
            return new BeanReference(qualifier.value());
        }
        
        // 默认按类型引用
        return new BeanReference(param.getType());
    }
    
    /**
     * 解析方法
     */
    private void parseMethods(Class<?> clazz, GenericBeanDefinition bd, String beanName) {
        for (Method method : clazz.getDeclaredMethods()) {
            // 初始化方法
            if (method.isAnnotationPresent(PostConstruct.class)) {
                bd.setInitMethodName(method.getName());
            }
            
            // 销毁方法
            if (method.isAnnotationPresent(PreDestroy.class)) {
                bd.setDestroyMethodName(method.getName());
            }
        }
    }
    
    /**
     * 解析字段
     */
    private void parseFields(Class<?> clazz, GenericBeanDefinition bd) {
        List<PropertyValue> propertyValues = new ArrayList<>();
        
        for (Field field : clazz.getDeclaredFields()) {
            Autowired autowired = field.getAnnotation(Autowired.class);
            Value value = field.getAnnotation(Value.class);
            
            if (autowired != null || value != null) {
                String fieldName = field.getName();
                Object fieldValue;
                
                if (value != null) {
                    // @Value 注入直接值
                    fieldValue = value.value();
                } else {
                    // @Autowired 注入 Bean
                    Qualifier qualifier = field.getAnnotation(Qualifier.class);
                    if (qualifier != null) {
                        fieldValue = new BeanReference(qualifier.value());
                    } else {
                        fieldValue = new BeanReference(field.getType());
                    }
                }
                
                propertyValues.add(new PropertyValue(fieldName, fieldValue));
            }
        }
        
        if (!propertyValues.isEmpty()) {
            bd.setPropertyValues(propertyValues);
        }
    }
    
    /**
     * 注册 @Bean 方法定义的 Bean
     */
    private void registerBeanMethods(Class<?> clazz, GenericBeanDefinition configBd) {
        for (Method method : clazz.getDeclaredMethods()) {
            Bean bean = method.getAnnotation(Bean.class);
            if (bean != null) {
                String beanName = bean.value();
                if (beanName.isEmpty()) {
                    beanName = method.getName();
                }
                
                GenericBeanDefinition bd = new GenericBeanDefinition();
                bd.setFactoryBeanName(configBd.getBeanClass().getName());
                bd.setFactoryMethodName(method.getName());
                bd.setBeanClass(method.getReturnType());
                
                // 解析工厂方法参数
                List<Object> args = new ArrayList<>();
                for (Parameter param : method.getParameters()) {
                    Object arg = resolveParameter(param);
                    args.add(arg);
                }
                bd.setConstructorArgumentValues(args);
                
                registry.registerBeanDefinition(beanName, bd);
            }
        }
    }
}

3.3 注解解析与注册

使用注解的示例代码

// ==================== Dao 层 ====================
@Repository
public class UserDao {
    
    public User findById(Long id) {
        // 查询数据库
        return new User(id, "张三");
    }
}

// ==================== Service 层 ====================
@Service
public class UserService {
    
    @Autowired
    private UserDao userDao;
    
    @Value("${app.name}")
    private String appName;
    
    @PostConstruct
    public void init() {
        System.out.println("UserService 初始化,应用名称:" + appName);
    }
    
    public User getUser(Long id) {
        return userDao.findById(id);
    }
}

// ==================== 配置类 ====================
@Component
public class AppConfig {
    
    @Bean
    public DataSource dataSource() {
        DataSource ds = new DataSource();
        ds.setUrl("jdbc:mysql://localhost:3306/test");
        ds.setUsername("root");
        ds.setPassword("123456");
        return ds;
    }
    
    @Bean
    public SqlSessionFactory sqlSessionFactory(@Autowired DataSource dataSource) {
        return new SqlSessionFactory(dataSource);
    }
}

// ==================== 测试 ====================
public class AnnotationTest {
    public static void main(String[] args) throws Exception {
        DefaultBeanFactory factory = new DefaultBeanFactory();
        
        // 创建扫描器
        ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(factory);
        
        // 扫描指定包
        scanner.scan("com.boge");
        
        // 获取并使用 Bean
        UserService userService = (UserService) factory.getBean("userService");
        User user = userService.getUser(1L);
        System.out.println(user);
    }
}

四、ApplicationContext 外观模式

虽然我们已经实现了 XML 和注解配置,但用户的使用体验还可以进一步简化。我们可以使用外观模式(Facade Pattern)为框架定义一个更简单统一的使用界面。

ApplicationContext 接口

/**
 * 应用上下文
 * 提供统一简洁的 Bean 访问接口
 */
public interface ApplicationContext extends BeanFactory {
    
    /**
     * 刷新上下文
     */
    void refresh() throws Exception;
    
    /**
     * 获取所有 Bean 定义名称
     */
    String[] getBeanDefinitionNames();
    
    /**
     * 获取 Bean 数量
     */
    int getBeanDefinitionCount();
}

ClassPathXmlApplicationContext 实现

/**
 * 类路径 XML 应用上下文
 */
public class ClassPathXmlApplicationContext implements ApplicationContext {
    
    private DefaultBeanFactory beanFactory;
    private String[] configLocations;
    
    public ClassPathXmlApplicationContext(String... configLocations) throws Exception {
        this.configLocations = configLocations;
        refresh();
    }
    
    @Override
    public void refresh() throws Exception {
        // 1. 创建 BeanFactory
        beanFactory = new DefaultBeanFactory();
        
        // 2. 加载 Bean 定义
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
        for (String location : configLocations) {
            reader.loadBeanDefinitions(location);
        }
        
        // 3. 初始化所有单例 Bean
        beanFactory.preInstantiateSingletons();
    }
    
    @Override
    public Object getBean(String beanName) throws Exception {
        return beanFactory.getBean(beanName);
    }
    
    @Override
    public <T> T getBean(String beanName, Class<T> requiredType) throws Exception {
        return beanFactory.getBean(beanName, requiredType);
    }
    
    @Override
    public String[] getBeanDefinitionNames() {
        return beanFactory.getBeanDefinitionNames();
    }
    
    @Override
    public int getBeanDefinitionCount() {
        return beanFactory.getBeanDefinitionCount();
    }
}

AnnotationConfigApplicationContext 实现

/**
 * 注解配置应用上下文
 */
public class AnnotationConfigApplicationContext implements ApplicationContext {
    
    private DefaultBeanFactory beanFactory;
    private String[] basePackages;
    
    public AnnotationConfigApplicationContext(String... basePackages) throws Exception {
        this.basePackages = basePackages;
        refresh();
    }
    
    @Override
    public void refresh() throws Exception {
        // 1. 创建 BeanFactory
        beanFactory = new DefaultBeanFactory();
        
        // 2. 扫描并注册 Bean 定义
        ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(beanFactory);
        scanner.scan(basePackages);
        
        // 3. 注册 AOP 处理器
        beanFactory.registerBeanPostProcessor(new AopBeanPostProcessor(beanFactory));
        
        // 4. 初始化所有单例 Bean
        beanFactory.preInstantiateSingletons();
    }
    
    @Override
    public Object getBean(String beanName) throws Exception {
        return beanFactory.getBean(beanName);
    }
    
    @Override
    public <T> T getBean(String beanName, Class<T> requiredType) throws Exception {
        return beanFactory.getBean(beanName, requiredType);
    }
    
    @Override
    public String[] getBeanDefinitionNames() {
        return beanFactory.getBeanDefinitionNames();
    }
    
    @Override
    public int getBeanDefinitionCount() {
        return beanFactory.getBeanDefinitionCount();
    }
}

使用对比

改进前(繁琐):

// 创建工厂
DefaultBeanFactory factory = new DefaultBeanFactory();

// 创建读取器
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
reader.loadBeanDefinitions("application-context.xml");

// 获取 Bean
UserService userService = (UserService) factory.getBean("userService");

改进后(简洁):

// XML 方式
ApplicationContext ctx = new ClassPathXmlApplicationContext("application-context.xml");
UserService userService = ctx.getBean("userService", UserService.class);

// 注解方式
ApplicationContext ctx = new AnnotationConfigApplicationContext("com.boge");
UserService userService = ctx.getBean("userService", UserService.class);

五、完整实现与测试

完整类图

┌─────────────────────────────────────────────────────────────────────┐
│                         ApplicationContext                           │
│  + getBean(String): Object                                          │
│  + refresh(): void                                                  │
└──────┬──────────────────────────────────────────────────────────────┘
       │
       ├── ClassPathXmlApplicationContext
       │      - configLocations: String[]
       │      - beanFactory: DefaultBeanFactory
       │      + refresh(): void
       │
       └── AnnotationConfigApplicationContext
              - basePackages: String[]
              - beanFactory: DefaultBeanFactory
              + refresh(): void

┌─────────────────────────────────────────────────────────────────────┐
│                      XmlBeanDefinitionReader                         │
│  - registry: BeanDefinitionRegistry                                 │
│  + loadBeanDefinitions(String): void                                │
│  - parseBeanElement(Element): void                                  │
└─────────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────────┐
│                   ClassPathBeanDefinitionScanner                     │
│  - registry: BeanDefinitionRegistry                                 │
│  + scan(String...): void                                            │
│  - doScan(String): Set<File>                                        │
│  - parseClassAnnotations(Class, BeanDefinition): void               │
└─────────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────────┐
│                         注解体系                                     │
│                                                                     │
│  @Component  @Service  @Repository  @Controller                     │
│       │                                                             │
│       ├── @Scope                                                    │
│       ├── @Primary                                                  │
│       ├── @Autowired                                                │
│       ├── @Value                                                    │
│       ├── @PostConstruct                                            │
│       └── @PreDestroy                                               │
└─────────────────────────────────────────────────────────────────────┘

测试用例

public class BeanConfigTest {
    
    @Test
    public void testXmlConfig() throws Exception {
        // 使用 XML 配置
        ApplicationContext ctx = new ClassPathXmlApplicationContext(
            "application-context.xml"
        );
        
        UserService userService = ctx.getBean("userService", UserService.class);
        assertNotNull(userService);
        
        User user = userService.getUser(1L);
        assertNotNull(user);
        assertEquals("张三", user.getName());
    }
    
    @Test
    public void testAnnotationConfig() throws Exception {
        // 使用注解配置
        ApplicationContext ctx = new AnnotationConfigApplicationContext(
            "com.boge"
        );
        
        // 验证扫描到的 Bean
        String[] beanNames = ctx.getBeanDefinitionNames();
        for (String name : beanNames) {
            System.out.println("Bean: " + name);
        }
        
        UserService userService = ctx.getBean("userService", UserService.class);
        assertNotNull(userService);
        
        // 验证依赖注入
        assertNotNull(userService.getUserDao());
    }
    
    @Test
    public void testFactoryMethod() throws Exception {
        ApplicationContext ctx = new AnnotationConfigApplicationContext(
            "com.boge"
        );
        
        // 测试 @Bean 方法
        DataSource dataSource = ctx.getBean("dataSource", DataSource.class);
        assertNotNull(dataSource);
        assertEquals("jdbc:mysql://localhost:3306/test", dataSource.getUrl());
    }
}

六、总结

核心知识点回顾

1. XML 配置方式

  • 定义 XML 规范(<bean><constructor-arg><property> 等)
  • 实现 XmlBeanDefinitionReader 解析 XML
  • 支持构造器注入和属性注入
  • 支持类型转换

2. 注解配置方式

  • 定义注解体系(@Component@Autowired@Value 等)
  • 实现 ClassPathBeanDefinitionScanner 包扫描
  • 解析类、方法、字段上的注解
  • 支持 @Bean 工厂方法

3. ApplicationContext

  • 外观模式封装底层细节
  • ClassPathXmlApplicationContext 用于 XML 配置
  • AnnotationConfigApplicationContext 用于注解配置
  • 提供统一简洁的使用接口

与 Spring 源码的对比

功能 手写实现 Spring 源码
XML 解析 XmlBeanDefinitionReader XmlBeanDefinitionReader
注解扫描 ClassPathBeanDefinitionScanner ClassPathBeanDefinitionScanner
上下文 ApplicationContext ApplicationContext
XML 上下文 ClassPathXmlApplicationContext ClassPathXmlApplicationContext
注解上下文 AnnotationConfigApplicationContext AnnotationConfigApplicationContext
注解定义 自定义注解 @Component@Autowired
类型转换 简单实现 TypeConverterPropertyEditor

学习建议

  1. 动手实践:自己实现一遍 XML 解析和注解扫描
  2. 阅读源码:与 Spring 源码对比,学习处理细节
  3. 思考问题
    • XML 和注解配置各有什么优缺点?
    • 如何处理循环依赖的 Bean 定义注册?
    • 如何支持占位符(如 ${jdbc.url})?
  4. 扩展练习
    • 实现 @Profile 环境切换
    • 实现 @Conditional 条件装配
    • 支持 import 导入其他配置文件

相关资源

  • Spring Core 文档:https://docs.spring.io/spring-framework/docs/current/reference/html/core.html
  • Spring 源码:https://github.com/spring-projects/spring-framework

如果本文对你有帮助,欢迎点赞、收藏、关注!如有疑问,欢迎在评论区留言讨论。

关键词:Spring 源码, Bean 定义, XML 配置, 注解配置, 组件扫描, ApplicationContext, 手写框架, IoC 容器


本文是手写 Spring 框架系列第四篇,实现了 Bean 定义配置化功能。敬请期待后续文章…

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐