高性能IoC(控制反转)容器设计与Aop(面向切面编程)二:我反转了!你反转了吗?(控制反转)

第二部分:设计篇 - IoC 容器架构设计

在第一部分中,我们理解了 IoC 和 AOP 的核心概念。现在,让我们开始设计自己的 IoC 容器。


第3章:IoC 容器核心架构

3.1 整体架构设计

一个完整的 IoC 容器需要以下核心组件:

复制代码
┌─────────────────────────────────────────────────────────────────┐
│                         应用层                                  │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐             │
│  │ @Service    │  │ @Autowired  │  │ @Aspect     │             │
│  │ PlayerSvc   │  │ Repository  │  │ LogAspect   │             │
│  └─────────────┘  └─────────────┘  └─────────────┘             │
└─────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│                        API 层 (common)                          │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐             │
│  │  注解定义   │  │   IoCAPI    │  │   AopAPI    │             │
│  │ @Service    │  │  getBean()  │  │createProxy()│             │
│  │ @Autowired  │  │ register()  │  │ parseAspect │             │
│  └─────────────┘  └─────────────┘  └─────────────┘             │
└─────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│                        核心层 (common)                          │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐             │
│  │BeanFactory  │  │BeanDefinition│ │Interceptor  │             │
│  │ 创建/管理   │  │  Bean元数据  │  │  Chain      │             │
│  │   Bean      │  │             │  │ 拦截器链    │             │
│  └─────────────┘  └─────────────┘  └─────────────┘             │
└─────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│                     运行时层 (runtime)                          │
│                      具体实现                                    │
└─────────────────────────────────────────────────────────────────┘

分层设计的好处

  1. API 层:定义接口和注解,不依赖具体实现
  2. 核心层:实现核心逻辑,平台无关
  3. 运行时层:适配不同平台(Spigot/Forge)

这种分层设计让我们可以:

  • 在不同平台复用核心代码
  • 轻松添加新平台支持
  • 单独测试每一层

3.2 Bean 定义与元数据

什么是 BeanDefinition?

BeanDefinition 是描述一个 Bean 的所有信息的数据结构,包括:

  • Bean 的类型(Class)
  • Bean 的名称
  • 作用域(单例/原型)
  • 是否懒加载
  • 依赖关系
  • 初始化/销毁方法
kotlin 复制代码
/**
 * Bean 定义
 * 描述一个 Bean 的所有元数据
 */
data class BeanDefinition(
    /** Bean 的类型 */
    val beanClass: Class<*>,

    /** Bean 的名称(默认为类名首字母小写) */
    val beanName: String = beanClass.simpleName.replaceFirstChar { it.lowercase() },

    /** 作用域 */
    val scope: BeanScope = BeanScope.SINGLETON,

    /** 是否懒加载 */
    val lazy: Boolean = false,

    /** 依赖的其他 Bean 类型 */
    val dependencies: List<Class<*>> = emptyList(),

    /** 初始化方法名 */
    val initMethod: String? = null,

    /** 销毁方法名 */
    val destroyMethod: String? = null
)

/**
 * Bean 作用域
 */
enum class BeanScope {
    /** 单例:整个容器只有一个实例 */
    SINGLETON,

    /** 原型:每次获取都创建新实例 */
    PROTOTYPE
}

Bean 的生命周期

一个 Bean 从创建到销毁,经历以下阶段:

复制代码
┌─────────────────────────────────────────────────────────────────┐
│                      Bean 生命周期                              │
└─────────────────────────────────────────────────────────────────┘

  1. 实例化                    2. 属性填充                3. 初始化
┌─────────────┐           ┌─────────────┐           ┌─────────────┐
│  创建对象   │ ────────▶ │  注入依赖   │ ────────▶ │ @PostConstr │
│  new Bean() │           │ @Autowired  │           │   uct       │
└─────────────┘           └─────────────┘           └─────────────┘
                                                           │
                                                           ▼
  6. 销毁                     5. 使用中                 4. 就绪
┌─────────────┐           ┌─────────────┐           ┌─────────────┐
│ @PreDestroy │ ◀──────── │  业务调用   │ ◀──────── │  放入容器   │
│  容器关闭   │           │             │           │             │
└─────────────┘           └─────────────┘           └─────────────┘

3.3 注解设计

我们需要设计一套注解来标记 Bean 和注入点。

Bean 标记注解

kotlin 复制代码
/**
 * 标记一个类为 Service Bean
 * 通常用于业务逻辑层
 */
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
annotation class Service(
    /** Bean 名称,默认为类名首字母小写 */
    val value: String = ""
)

/**
 * 标记一个类为 Component Bean
 * 通用组件标记
 */
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
annotation class Component(
    val value: String = ""
)

/**
 * 标记一个类为 Repository Bean
 * 通常用于数据访问层
 */
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
annotation class Repository(
    val value: String = ""
)

依赖注入注解

kotlin 复制代码
/**
 * 字段注入
 * 标记需要自动注入的字段
 */
@Target(AnnotationTarget.FIELD, AnnotationTarget.VALUE_PARAMETER)
@Retention(AnnotationRetention.RUNTIME)
annotation class Autowired(
    /** 是否必须,如果为 true 且找不到 Bean 则抛异常 */
    val required: Boolean = true
)

/**
 * 构造器注入
 * 标记使用哪个构造器进行依赖注入
 */
@Target(AnnotationTarget.CONSTRUCTOR)
@Retention(AnnotationRetention.RUNTIME)
annotation class Inject

/**
 * 配置值注入
 * 从配置文件注入值
 */
@Target(AnnotationTarget.FIELD, AnnotationTarget.VALUE_PARAMETER)
@Retention(AnnotationRetention.RUNTIME)
annotation class Value(
    /** 配置路径,如 "database.host" */
    val value: String
)

我们的场景只考虑@Autowired,因为我们使用Kotlin,由于Kotlin Object单例类型的存在构造函数注入和配置值注入已经很少使用到

生命周期注解

kotlin 复制代码
/**
 * 初始化回调
 * Bean 创建并注入依赖后调用
 */
@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
annotation class PostConstruct

/**
 * 销毁回调
 * 容器关闭时调用
 */
@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
annotation class PreDestroy

作用域注解

kotlin 复制代码
/**
 * 单例作用域(默认)
 */
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
annotation class Singleton

/**
 * 原型作用域
 * 每次获取都创建新实例
 */
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
annotation class Prototype

/**
 * 懒加载
 * 第一次使用时才创建
 */
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
annotation class Lazy

使用示例

kotlin 复制代码
@Service
@Singleton
class PlayerService(
    @Autowired private val repository: PlayerRepository,
    @Value("game.max-players") private val maxPlayers: Int
) {

    @Autowired
    private lateinit var logger: Logger

    @PostConstruct
    fun init() {
        logger.info("PlayerService 初始化完成,最大玩家数: $maxPlayers")
    }

    @PreDestroy
    fun cleanup() {
        logger.info("PlayerService 正在关闭...")
    }

    fun getPlayer(uuid: String): PlayerData? {
        return repository.findByUUID(uuid)
    }
}

@Repository
@Lazy  // 懒加载,第一次使用时才连接数据库
class PlayerRepository(
    @Autowired private val database: Database
) {
    fun findByUUID(uuid: String): PlayerData? {
        return database.query("SELECT * FROM players WHERE uuid = ?", uuid)
    }
}

第4章:Bean 工厂设计

Bean 工厂是 IoC 容器的核心,负责创建和管理所有的 Bean。

4.1 BeanFactory 接口设计

kotlin 复制代码
/**
 * Bean 工厂接口
 * 负责 Bean 的创建、获取和管理
 */
interface BeanFactory {

    /**
     * 根据类型获取 Bean
     * @param type Bean 的类型
     * @return Bean 实例,如果不存在返回 null
     */
    fun <T> getBean(type: Class<T>): T?

    /**
     * 根据名称和类型获取 Bean
     * @param name Bean 的名称
     * @param type Bean 的类型
     * @return Bean 实例,如果不存在返回 null
     */
    fun <T> getBean(name: String, type: Class<T>): T?

    /**
     * 检查是否包含指定名称的 Bean
     */
    fun containsBean(name: String): Boolean

    /**
     * 检查是否包含指定类型的 Bean
     */
    fun containsBean(type: Class<*>): Boolean

    /**
     * 获取指定类型的所有 Bean
     * 用于获取某个接口的所有实现
     */
    fun <T> getBeansOfType(type: Class<T>): List<T>

    /**
     * 注册一个 Bean 定义
     */
    fun registerBeanDefinition(definition: BeanDefinition)

    /**
     * 注册一个已存在的实例作为 Bean
     */
    fun registerSingleton(name: String, instance: Any)
}

容器管理器设计

为了方便全局访问,我们设计一个静态的容器管理器,内部维护若干哈希表:

kotlin 复制代码
/**
 * IoC 容器管理器
 * 提供全局访问点
 */
object IoCContainerManager {

    /** Bean 定义注册表 */
    private val beanDefinitions = ConcurrentHashMap<String, BeanDefinition>()

    /** 单例 Bean 缓存 */
    private val singletonBeans = ConcurrentHashMap<String, Any>()

    /** 类型到名称的映射(用于按类型查找) */
    private val typeToNames = ConcurrentHashMap<Class<*>, MutableList<String>>()

    /**
     * 根据类型获取 Bean
     */
    @Suppress("UNCHECKED_CAST")
    fun <T> getBean(type: Class<T>): T? {
        // 1. 先从单例缓存查找
        val names = typeToNames[type] ?: return null
        if (names.isEmpty()) return null

        val name = names.first()
        return singletonBeans[name] as? T ?: createBean(name)
    }

    /**
     * 注册 Bean 定义
     */
    fun registerBeanDefinition(definition: BeanDefinition) {
        val name = definition.beanName
        beanDefinitions[name] = definition

        // 建立类型映射
        typeToNames.getOrPut(definition.beanClass) { mutableListOf() }.add(name)

        // 同时映射所有父类和接口
        registerTypeHierarchy(definition.beanClass, name)
    }

    /**
     * 注册类型层次结构
     */
    private fun registerTypeHierarchy(clazz: Class<*>, beanName: String) {
        // 注册父类
        clazz.superclass?.let { superClass ->
            if (superClass != Any::class.java) {
                typeToNames.getOrPut(superClass) { mutableListOf() }.add(beanName)
                registerTypeHierarchy(superClass, beanName)
            }
        }

        // 注册接口
        for (iface in clazz.interfaces) {
            typeToNames.getOrPut(iface) { mutableListOf() }.add(beanName)
        }
    }

    /**
     * 初始化所有非懒加载的单例 Bean
     */
    fun initializeEagerBeans() {
        for ((name, definition) in beanDefinitions) {
            if (definition.scope == BeanScope.SINGLETON && !definition.lazy) {
                if (!singletonBeans.containsKey(name)) {
                    createBean(name)
                }
            }
        }
    }
}

4.2 Bean 创建流程

Bean 的创建是一个复杂的过程,需要处理依赖注入、生命周期回调等。

kotlin 复制代码
/**
 * 创建 Bean 实例
 */
@Suppress("UNCHECKED_CAST")
private fun <T> createBean(name: String): T? {
    val definition = beanDefinitions[name] ?: return null

    // 1. 检查是否正在创建(循环依赖检测)
    if (beansInCreation.contains(name)) {
        throw BeanCreationException("检测到循环依赖: $name")
    }
    beansInCreation.add(name)

    try {
        // 2. 实例化
        val instance = instantiate(definition)

        // 3. 提前暴露(解决循环依赖)
        if (definition.scope == BeanScope.SINGLETON) {
            earlySingletonBeans[name] = instance
        }

        // 4. 属性填充(依赖注入)
        populateBean(instance, definition)

        // 5. 初始化
        initializeBean(instance, definition)

        // 6. 如果是单例,放入缓存
        if (definition.scope == BeanScope.SINGLETON) {
            singletonBeans[name] = instance
            earlySingletonBeans.remove(name)
        }

        return instance as T
    } finally {
        beansInCreation.remove(name)
    }
}

实例化阶段

kotlin 复制代码
/**
 * 实例化 Bean
 */
private fun instantiate(definition: BeanDefinition): Any {
    val clazz = definition.beanClass

    // 检查是否是 Kotlin object
    if (IoCAPI.get().isKotlinObject(clazz)) {
	// 通过反射获取实例
        return IoCAPI.get().getKotlinInstance(clazz)
            ?: throw BeanCreationException("无法获取 Kotlin object 实例: ${clazz.name}")
    }

    // 查找构造器
    val constructor = findConstructor(clazz)

    // 解析构造器参数
    val args = resolveConstructorArgs(constructor)

    // 通过反射创建实例
    return if (args.isEmpty()) {
        IoCAPI.get().createInstance(clazz)
    } else {
        IoCAPI.get().createInstanceWithArgs(clazz, *args.toTypedArray())
    }
}

/**
 * 查找合适的构造器
 * 优先级:@Inject 标记的 > 参数最多的 > 无参构造器
 */
private fun findConstructor(clazz: Class<*>): Constructor<*> {
    // 1. 查找 @Inject 标记的构造器
    val injectConstructor = IoCAPI.get().getConstructorWithAnnotation(clazz, Inject::class.java)
    if (injectConstructor != null) return injectConstructor

    // 2. 查找参数最多的构造器(Kotlin 主构造器通常参数最多)
    val primaryConstructor = IoCAPI.get().getPrimaryConstructor(clazz)
    if (primaryConstructor != null) return primaryConstructor

    // 3. 使用无参构造器
    return clazz.getDeclaredConstructor()
}

/**
 * 解析构造器参数
 */
private fun resolveConstructorArgs(constructor: Constructor<*>): List<Any?> {
    return constructor.parameters.map { param ->
        // 检查 @Value 注解
        val valueAnnotation = param.getAnnotation(Value::class.java)
        if (valueAnnotation != null) {
            return@map resolveValue(valueAnnotation.value, param.type)
        }

        // 检查 @Autowired 注解
        val autowired = param.getAnnotation(Autowired::class.java)
        val required = autowired?.required ?: true

        // 按类型查找 Bean
        val bean = getBean(param.type)
        if (bean == null && required) {
            throw BeanCreationException("无法解析构造器参数: ${param.type.name}")
        }
        bean
    }
}

属性填充阶段

kotlin 复制代码
/**
 * 填充 Bean 属性(字段注入)
 */
private fun populateBean(instance: Any, definition: BeanDefinition) {
    val clazz = definition.beanClass

    // 获取所有 @Autowired 字段
    val autowiredFields = IoCAPI.get().getFieldsWithAnnotation(clazz, Autowired::class.java)
    for (field in autowiredFields) {
        val annotation = field.getAnnotation(Autowired::class.java)
        val required = annotation?.required ?: true

        // 按类型查找 Bean
        val bean = getBean(field.type)
        if (bean == null && required) {
            throw BeanCreationException("无法注入字段 ${field.name}: 找不到类型 ${field.type.name} 的 Bean")
        }

        if (bean != null) {
            IoCAPI.get().setField(instance, field.name, bean)
        }
    }

    // 获取所有 @Value 字段
    val valueFields = IoCAPI.get().getFieldsWithAnnotation(clazz, Value::class.java)
    for (field in valueFields) {
        val annotation = field.getAnnotation(Value::class.java)
        val value = resolveValue(annotation.value, field.type)
        IoCAPI.get().setField(instance, field.name, value)
    }
}

初始化阶段

kotlin 复制代码
/**
 * 初始化 Bean
 */
private fun initializeBean(instance: Any, definition: BeanDefinition) {
    val clazz = definition.beanClass

    // 调用 @PostConstruct 方法
    val postConstructMethods = IoCAPI.get().getMethodsWithAnnotation(clazz, PostConstruct::class.java)
    for (method in postConstructMethods) {
        IoCAPI.get().invokeMethod(instance, method.name)
    }

    // 调用自定义初始化方法
    definition.initMethod?.let { methodName ->
        IoCAPI.get().invokeMethod(instance, methodName)
    }
}

4.3 循环依赖处理

循环依赖是 IoC 容器必须处理的问题。

什么是循环依赖?

kotlin 复制代码
@Service
class ServiceA(
    @Autowired private val serviceB: ServiceB  // A 依赖 B
)

@Service
class ServiceB(
    @Autowired private val serviceA: ServiceA  // B 依赖 A
)

创建 A 时需要 B,创建 B 时又需要 A,形成死循环。

三级缓存解决方案

Spring 使用三级缓存来解决循环依赖,我们采用简化版的两级缓存:

kotlin 复制代码
object IoCContainerManager {

    /** 一级缓存:完全初始化的单例 Bean */
    private val singletonBeans = ConcurrentHashMap<String, Any>()

    /** 二级缓存:提前暴露的 Bean(已实例化但未完成初始化) */
    private val earlySingletonBeans = ConcurrentHashMap<String, Any>()

    /** 正在创建中的 Bean 名称集合 */
    private val beansInCreation = ConcurrentHashSet<String>()

    /**
     * 获取 Bean(支持循环依赖)
     */
    fun <T> getBean(name: String): T? {
        // 1. 先从一级缓存获取
        singletonBeans[name]?.let { return it as T }

        // 2. 再从二级缓存获取(解决循环依赖)
        earlySingletonBeans[name]?.let { return it as T }

        // 3. 创建新的 Bean
        return createBean(name)
    }
}

循环依赖解决流程

复制代码
创建 ServiceA:
    1. 标记 A 正在创建
    2. 实例化 A(new ServiceA(),此时 serviceB 为 null)
    3. 将 A 放入二级缓存(提前暴露)
    4. 填充属性:需要 ServiceB
        │
        └──▶ 创建 ServiceB:
                1. 标记 B 正在创建
                2. 实例化 B
                3. 将 B 放入二级缓存
                4. 填充属性:需要 ServiceA
                    │
                    └──▶ 从二级缓存获取 A(提前暴露的实例)✓

                5. 初始化 B
                6. B 放入一级缓存,从二级缓存移除
                7. 返回 B
            │
        ◀──┘
    5. 将 B 注入到 A
    6. 初始化 A
    7. A 放入一级缓存,从二级缓存移除

注意:构造函数循环依赖无法解决!但在我们的场景这个不需要

kotlin 复制代码
// 这种情况无法解决,因为实例化 A 就需要 B
@Service
class ServiceA(private val serviceB: ServiceB)

@Service
class ServiceB(private val serviceA: ServiceA)

解决方案:将其中一个改为字段注入:

kotlin 复制代码
@Service
class ServiceA(private val serviceB: ServiceB)

@Service
class ServiceB {
    @Autowired
    private lateinit var serviceA: ServiceA  // 改为字段注入
}

第5章:注解扫描器设计

IoC 容器需要自动发现和注册 Bean,这就需要一个注解扫描器。

5.1 类扫描机制

类扫描器需要从不同来源加载类:

复制代码
┌─────────────────────────────────────────────────────────────────┐
│                        类扫描来源                               │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐             │
│  │  JAR 文件   │  │  文件系统   │  │  外部插件   │             │
│  │ (生产环境)  │  │ (开发环境)  │  │ (扩展支持)  │             │
│  └──────┬──────┘  └──────┬──────┘  └──────┬──────┘             │
│         │                │                │                     │
│         └────────────────┼────────────────┘                     │
│                          ▼                                      │
│                  ┌───────────────┐                              │
│                  │  ClassScanner │                              │
│                  │   统一接口    │                              │
│                  └───────┬───────┘                              │
│                          │                                      │
│                          ▼                                      │
│                  ┌───────────────┐                              │
│                  │ List<Class<?>>│                              │
│                  │   扫描结果    │                              │
│                  └───────────────┘                              │
└─────────────────────────────────────────────────────────────────┘

类扫描器实现

kotlin 复制代码
/**
 * 类扫描器
 * 从 JAR 文件或文件系统扫描类
 */
object ClassScanner {

    /**
     * 扫描指定包下的所有类
     *
     * @param mainClass 主类(用于获取 ClassLoader)
     * @param packagePrefix 包前缀
     * @return 扫描到的类列表
     */
    fun scan(mainClass: Class<*>, packagePrefix: String): List<Class<*>> {
        val classes = mutableListOf<Class<*>>()
        val packageDirName = packagePrefix.replace('.', '/')

        try {
            val dirs = mainClass.classLoader.getResources(packageDirName)

            while (dirs.hasMoreElements()) {
                val url = dirs.nextElement()

                when (url.protocol) {
                    "file" -> {
                        // 从文件系统扫描(开发环境)
                        val filePath = URLDecoder.decode(url.file, "UTF-8")
                        scanDirectory(packagePrefix, filePath, classes, mainClass.classLoader)
                    }
                    "jar" -> {
                        // 从 JAR 文件扫描(生产环境)
                        scanJar(url, packagePrefix, packageDirName, classes, mainClass.classLoader)
                    }
                }
            }
        } catch (e: IOException) {
            logger.error("扫描类时发生错误", e)
        }

        return classes
    }

    /**
     * 从 JAR 文件扫描类
     */
    private fun scanJar(
        url: URL,
        packagePrefix: String,
        packageDirName: String,
        classes: MutableList<Class<*>>,
        classLoader: ClassLoader
    ) {
        val jar = (url.openConnection() as JarURLConnection).jarFile
        val entries = jar.entries()

        while (entries.hasMoreElements()) {
            val entry = entries.nextElement()
            val name = entry.name

            // 检查是否在目标包下
            if (name.startsWith(packageDirName) &&
                name.endsWith(".class") &&
                !entry.isDirectory
            ) {
                // 转换为类名
                val className = name
                    .substring(0, name.length - 6)
                    .replace('/', '.')

                // 跳过内部类
                if (className.contains("$")) continue

                // 加载类
                tryLoadClass(className, classLoader, classes)
            }
        }
    }

    /**
     * 从文件系统扫描类
     */
    private fun scanDirectory(
        packageName: String,
        packagePath: String,
        classes: MutableList<Class<*>>,
        classLoader: ClassLoader
    ) {
        val dir = File(packagePath)
        if (!dir.exists() || !dir.isDirectory) return

        dir.listFiles()?.forEach { file ->
            if (file.isDirectory) {
                // 递归扫描子目录
                scanDirectory(
                    "$packageName.${file.name}",
                    file.absolutePath,
                    classes,
                    classLoader
                )
            } else if (file.name.endsWith(".class")) {
                // 加载类文件
                val className = "$packageName.${file.name.dropLast(6)}"
                if (!className.contains("$")) {
                    tryLoadClass(className, classLoader, classes)
                }
            }
        }
    }

    /**
     * 尝试加载类
     */
    private fun tryLoadClass(
        className: String,
        classLoader: ClassLoader,
        classes: MutableList<Class<*>>
    ) {
        try {
            // 使用 initialize=false 避免触发静态初始化
            val clazz = Class.forName(className, false, classLoader)
            classes.add(clazz)
        } catch (e: ClassNotFoundException) {
            // 忽略
        } catch (e: NoClassDefFoundError) {
            // 忽略(依赖缺失)
        } catch (e: LinkageError) {
            // 忽略(类加载冲突)
        }
    }
}

5.2 注解处理器设计

扫描到类之后,需要根据注解进行不同的处理。我们设计一个灵活的注解处理器系统。

注解处理器接口

kotlin 复制代码
/**
 * 注解处理器接口
 * 处理特定注解标记的类
 */
interface AnnotationHandler<A : Annotation> {

    /** 处理的注解类型 */
    val annotationClass: Class<A>

    /**
     * 处理带有该注解的类
     *
     * @param clazz 被注解的类
     * @param annotation 注解实例
     * @param instance 类的实例(如果已创建)
     */
    fun handle(clazz: Class<*>, annotation: A, instance: Any?)
}

内置处理器实现

kotlin 复制代码
/**
 * @Service 注解处理器
 */
class ServiceAnnotationHandler : AnnotationHandler<Service> {

    override val annotationClass = Service::class.java

    override fun handle(clazz: Class<*>, annotation: Service, instance: Any?) {
        // 创建 Bean 定义
        val beanName = annotation.value.ifEmpty {
            clazz.simpleName.replaceFirstChar { it.lowercase() }
        }

        val definition = BeanDefinition(
            beanClass = clazz,
            beanName = beanName,
            scope = determinScope(clazz),
            lazy = clazz.isAnnotationPresent(Lazy::class.java)
        )

        // 注册到容器
        IoCContainerManager.registerBeanDefinition(definition)
    }

    private fun determinScope(clazz: Class<*>): BeanScope {
        return when {
            clazz.isAnnotationPresent(Prototype::class.java) -> BeanScope.PROTOTYPE
            else -> BeanScope.SINGLETON
        }
    }
}

/**
 * @Aspect 注解处理器
 */
class AspectAnnotationHandler : AnnotationHandler<Aspect> {

    override val annotationClass = Aspect::class.java

    override fun handle(clazz: Class<*>, annotation: Aspect, instance: Any?) {
        // 获取或创建切面实例
        val aspectInstance = instance ?: IoCAPI.get().getKotlinInstance(clazz)
            ?: IoCAPI.get().createInstance(clazz)

        // 解析切面,生成拦截器
        val interceptors = AopAPI.get().parseAspect(clazz, aspectInstance)

        // 注册拦截器
        AopManager.registerInterceptors(interceptors)
    }
}

DSL 风格的处理器注册

为了让注册更加灵活,我们设计了 DSL 风格的 注解扫描 API:

kotlin 复制代码
/**
 * 注解扫描构建器
 */
class AnnotationScanBuilder {

    private val handlers = mutableListOf<AnnotationHandler<*>>()
    private val classHandlers = mutableListOf<(Class<*>) -> Unit>()
    private val instanceHandlers = mutableListOf<(Class<*>, Any) -> Unit>()

    /**
     * 注册类级别的注解处理器
     */
    inline fun <reified A : Annotation> onClass(
        crossinline handler: (Class<*>, A) -> Unit
    ) {
        handlers.add(object : AnnotationHandler<A> {
            override val annotationClass = A::class.java
            override fun handle(clazz: Class<*>, annotation: A, instance: Any?) {
                handler(clazz, annotation)
            }
        })
    }

    /**
     * 注册实例级别的注解处理器
     */
    inline fun <reified A : Annotation> onInstance(
        crossinline handler: (Any, A) -> Unit
    ) {
        instanceHandlers.add { clazz, instance ->
            clazz.getAnnotation(A::class.java)?.let { annotation ->
                handler(instance, annotation)
            }
        }
    }

    /**
     * 注册方法级别的注解处理器
     */
    inline fun <reified A : Annotation> onMethod(
        crossinline handler: (Any, Method, A) -> Unit
    ) {
        instanceHandlers.add { clazz, instance ->
            for (method in clazz.declaredMethods) {
                method.getAnnotation(A::class.java)?.let { annotation ->
                    handler(instance, method, annotation)
                }
            }
        }
    }

    /**
     * 注册字段级别的注解处理器
     */
    inline fun <reified A : Annotation> onField(
        crossinline handler: (Any, Field, A) -> Unit
    ) {
        instanceHandlers.add { clazz, instance ->
            for (field in clazz.declaredFields) {
                field.getAnnotation(A::class.java)?.let { annotation ->
                    handler(instance, field, annotation)
                }
            }
        }
    }

    internal fun build(): AnnotationScanConfig {
        return AnnotationScanConfig(handlers, classHandlers, instanceHandlers)
    }
}

使用示例

kotlin 复制代码
// 注册自定义注解处理器
IoCAPI.get().registerAnnotationHandlers {

    // 处理 @Service 注解的类
    onClass<Service> { clazz, annotation ->
        val beanName = annotation.value.ifEmpty { clazz.simpleName.lowercase() }
        IoCContainerManager.registerBeanDefinition(
            BeanDefinition(clazz, beanName)
        )
    }

    // 处理 @Aspect 注解的类
    onClass<Aspect> { clazz, annotation ->
        val instance = IoCAPI.get().getKotlinInstance(clazz)
        if (instance != null) {
            val interceptors = AopAPI.get().parseAspect(clazz, instance)
            AopManager.registerInterceptors(interceptors)
        }
    }

    // 处理 @PostConstruct 注解的方法
    onMethod<PostConstruct> { instance, method, _ ->
        method.invoke(instance)
    }

    // 处理 @Autowired 注解的字段
    onField<Autowired> { instance, field, annotation ->
        val bean = IoCContainerManager.getBean(field.type)
        if (bean != null) {
            field.isAccessible = true
            field.set(instance, bean)
        } else if (annotation.required) {
            throw BeanCreationException("无法注入字段: ${field.name}")
        }
    }
}

5.3 外部类注册机制

有时候,我们需要将外部的类也纳入 IoC 容器管理。

为什么需要外部类注册?

复制代码
┌─────────────────────────────────────────────────────────────────┐
│                      主项目 (Behemiron)                         │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │                    IoC 容器                              │   │
│  │  ┌─────────┐  ┌─────────┐  ┌─────────┐                  │   │
│  │  │ServiceA │  │ServiceB │  │ServiceC │                  │   │
│  │  └─────────┘  └─────────┘  └─────────┘                  │   │
│  └─────────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────────┘
                              ▲
                              │ 想要使用 IoC 容器
                              │
┌─────────────────────────────────────────────────────────────────┐
│                    外部插件 (MyPlugin)                          │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐             │
│  │ @Service    │  │ @Autowired  │  │ @Cacheable  │             │
│  │ MyService   │  │ ServiceA   │  │ getData()   │             │
│  └─────────────┘  └─────────────┘  └─────────────┘             │
│                                                                 │
│  这些类也想被 IoC 容器管理!                                    │
└─────────────────────────────────────────────────────────────────┘

外部提供者注册 API

kotlin 复制代码
/**
 * 外部提供者信息
 */
data class ExternalProvider(
    val providerClass: Class<*>,
    val packagePrefix: String?
) {
    /**
     * 获取有效的包前缀
     */
    fun getEffectivePackagePrefix(): String {
        if (packagePrefix != null) return packagePrefix
        val parts = providerClass.`package`?.name?.split(".") ?: return ""
        return if (parts.size >= 2) "${parts[0]}.${parts[1]}" else parts.joinToString(".")
    }
}

// IoCAPI 中的注册方法
object IoCAPI {
    companion object {
        private val externalProviders = mutableListOf<ExternalProvider>()

        /**
         * 注册外部提供者
         *
         * 必须在 onInitialized 回调中调用!
         */
        fun registerExternalProvider(providerClass: Class<*>, packagePrefix: String? = null) {
            externalProviders.add(ExternalProvider(providerClass, packagePrefix))
        }
    }
}

正确的注册时机

外部插件必须在 IoC 容器初始化之前注册,使用 onInitialized 回调:

kotlin 复制代码
// 外部插件的集成代码
object MyPluginIntegration {

    init {
        // 在 Kotlin object 的 init 块中注册
        // 这会在类加载时执行,早于 IoC 容器初始化
        IoCAPI.onInitialized {
            // 注册插件作为外部提供者
            IoCAPI.registerExternalProvider(
                providerClass = MyPlugin::class.java,
                packagePrefix = "com.example.myplugin"
            )
        }
    }
}

// Java 版本
public class MyPluginIntegration {
    static {
        IoCAPI.onInitialized(() -> {
            IoCAPI.registerExternalProvider(MyPlugin.class, "com.example.myplugin");
        });
    }
}

扫描流程

复制代码
IoC 容器初始化流程:

1. 触发 onInitialized 回调
   └── 外部插件注册 ExternalProvider

2. 扫描内部类
   └── 主项目的所有类

3. 扫描外部提供者
   └── 遍历 externalProviders
       └── ClassScanner.scanProvider(provider)
           └── 返回外部插件的所有类

4. 合并所有类
   └── internalClasses + externalClasses

5. 处理注解
   └── 对每个类执行注解处理器

6. 初始化 Bean
   └── 创建所有非懒加载的单例

5.4 本章小结

在本章中,我们设计了:

  1. 类扫描器:从 JAR 文件和文件系统扫描类
  2. 注解处理器:灵活的注解处理机制,支持 DSL 风格注册
  3. 外部类注册:允许外部插件/模组接入 IoC 容器

关键设计决策:

设计点 决策 原因
扫描时机 启动时一次性扫描 避免运行时开销
类加载 initialize=false 避免触发静态初始化
外部注册 回调机制 确保在扫描前完成注册
处理器注册 DSL 风格 代码简洁,易于扩展
游客

全部评论 (0)

暂无评论,快来抢沙发吧~