ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Spring 注入内部 Bean 详解

2026/9/16 8:55:16 拓冰建站 浏览量
Spring 注入内部 Bean 详解 Spring 注入内部 Bean 详解一、什么是内部 Bean内部 BeanInner Bean是指定义在另一个 Bean 内部的 Bean。它不需要单独的id也不能被外部容器直接引用只服务于其所在的宿主 Bean。!-- 外部 Bean --beaniduserServiceclasscom.example.UserServicepropertynameuserDao!-- 内部 Bean没有 id只属于 userService --beanclasscom.example.UserDaoImplpropertynamedataSourcerefdataSource//bean/property/beanUserDaoImpl就是一个内部 Bean。它没有id外部无法通过getBean()获取它。它的生命周期完全绑定在userService上。二、XML 中的内部 Bean2.1 基本用法内部 Bean 通过bean标签嵌套在property或constructor-arg中定义。beanidorderServiceclasscom.example.OrderServicepropertynamepaymentServicebeanclasscom.example.AliPayServicepropertynameappIdvalue2021001/propertynameprivateKeyvaluexxxxx//bean/property/bean特点不需要id属性即使写了也会被忽略不能通过ref引用不能被其他 Bean 引用每次注入时都会创建新实例即使宿主 Bean 是单例2.2 构造器参数中的内部 BeanbeaniduserServiceclasscom.example.UserServiceconstructor-argbeanclasscom.example.UserDaoImpl//constructor-arg/bean2.3 内部 Bean 的匿名性内部 Bean 本质上是一个匿名 Bean。Spring 会为它生成一个内部名称但开发者无法预知也无法引用。它只能被它的宿主 Bean 使用。三、Java 配置中的内部 Bean在 Java 配置中内部 Bean 通常通过Bean方法实现或者直接在方法体内new出对象。3.1 直接 new 对象ConfigurationpublicclassAppConfig{BeanpublicUserServiceuserService(){// 内部 Bean直接 new不注册到容器UserDaouserDaonewUserDaoImpl();returnnewUserService(userDao);}}这种方式创建的对象不是 Spring Bean不受容器管理不享受依赖注入和 AOP 增强。3.2 通过 Bean 方法调用推荐ConfigurationpublicclassAppConfig{BeanpublicUserServiceuserService(){// 调用 userDao() 方法由于 CGLIB 代理返回的是容器中的单例returnnewUserService(userDao());}BeanpublicUserDaouserDao(){returnnewUserDaoImpl();}}Configuration类会被 CGLIB 增强userDao()方法调用返回的是容器中的 Bean而不是新创建的实例。3.3 真正意义上的内部 BeanJava 配置中没有严格意义上的“内部 Bean”。如果希望对象完全私有不被容器管理可以这样写ConfigurationpublicclassAppConfig{BeanpublicUserServiceuserService(){UserDaoImpluserDaonewUserDaoImpl();userDao.setDataSource(dataSource());// 手动注入依赖returnnewUserService(userDao);}BeanpublicDataSourcedataSource(){returnnewHikariDataSource();}}userDao是一个纯 Java 对象不是 Spring Bean但它的依赖dataSource来自容器。四、内部 Bean 与外部 Bean 的对比对比维度内部 Bean外部 Bean定义位置嵌套在宿主 Bean 内部独立定义是否有 id没有匿名有唯一 id是否可被引用不能被其他 Bean 引用可以被任意引用生命周期随宿主 Bean 创建/销毁独立管理作用域与宿主 Bean 绑定可配置多种作用域适用场景仅宿主 Bean 使用的私有依赖多个 Bean 共享的公共依赖五、内部 Bean 的生命周期内部 Bean 的生命周期与宿主 Bean 紧密绑定创建宿主 Bean 被创建时内部 Bean 同时被创建销毁宿主 Bean 被销毁时内部 Bean 同时被销毁作用域内部 Bean 不支持自定义作用域始终与宿主 Bean 同生命周期AOP 代理内部 Bean 可以被 AOP 代理但代理对象无法被外部引用六、内部 Bean 的典型使用场景6.1 私有依赖当某个依赖只被一个 Bean 使用时用内部 Bean 可以避免污染容器。beanidreportServiceclasscom.example.ReportServicepropertynamedataSourcebeanclasscom.example.ReportDataSourcepropertynameurlvaluejdbc:mysql://report-db:3306/report//bean/property/beanReportDataSource只被reportService使用不需要暴露给容器。6.2 多实例配置同一个类需要不同的配置实例时用内部 Bean 可以避免创建多个有 id 的 Bean。beanidemailServiceclasscom.example.EmailServicepropertynamemailSenderbeanclasscom.example.SmtpMailSenderpropertynamehostvaluesmtp.company.com//bean/property/beanbeanidalertServiceclasscom.example.AlertServicepropertynamemailSenderbeanclasscom.example.SmtpMailSenderpropertynamehostvaluesmtp.alert.com//bean/property/bean两个SmtpMailSender实例使用不同的 SMTP 服务器互不干扰。6.3 一次性对象某些对象只在某个 Bean 初始化时使用一次不需要长期存在于容器中。七、内部 Bean 的注意事项1. 内部 Bean 不能使用Autowired内部 Bean 如果是通过 XML 定义的匿名 Bean无法被Autowired注入到其他类中因为它没有可引用的 id。2. 内部 Bean 的id被忽略beaniduserServiceclasscom.example.UserServicepropertynameuserDaobeanidinnerDaoclasscom.example.UserDaoImpl/!-- 这个 id 会被忽略无法通过 getBean(innerDao) 获取 --/property/bean3. 内部 Bean 的循环引用内部 Bean 无法引用外部 Bean因为它没有 id。但外部 Bean 可以引用内部 Bean通过嵌套定义。4. 每次注入创建新实例如果宿主 Bean 是单例内部 Bean 也是单例与宿主绑定。如果宿主 Bean 是 prototype每次创建宿主时都会创建新的内部 Bean 实例。5. Java 配置中 new 出来的对象不是 BeanBeanpublicUserServiceuserService(){UserDaouserDaonewUserDaoImpl();// 这不是 Spring BeanreturnnewUserService(userDao);}这个userDao不受容器管理依赖注入、AOP、生命周期回调都不生效。八、最佳实践优先使用外部 Bean。除非确实只需要宿主 Bean 使用否则尽量定义为外部 Bean。外部 Bean 更灵活可以被测试直接获取也可以被其他 Bean 复用。合理使用 Java 配置。在 Java 配置中通过Bean方法调用获取依赖而不是直接new。这样依赖仍然是 Spring Bean享受容器管理。避免过度嵌套。内部 Bean 嵌套层级过深会导致 XML 难以阅读和维护。如果嵌套超过两层考虑提取为外部 Bean。明确内部 Bean 的定位。内部 Bean 适合“私有、一次性、不共享”的依赖。如果需要复用或测试应该定义为外部 Bean。九、总结维度核心要点定义嵌套在宿主 Bean 内部没有独立 id生命周期与宿主 Bean 绑定同生共死引用不能被外部 Bean 引用只能被宿主使用XML 写法bean嵌套在property或constructor-arg中Java 写法通过Bean方法调用或直接new适用场景私有依赖、多实例配置、一次性对象注意事项无法被Autowired、id 被忽略、每次创建新实例内部 Bean 是 Spring 提供的一种“私有 Bean”机制适合那些不需要暴露给容器、只服务于特定宿主 Bean 的依赖。合理使用内部 Bean可以让容器中的 Bean 定义更清晰避免不必要的 Bean 污染。在 Java 配置为主流的今天内部 Bean 的使用频率已经降低但在一些需要为同一个类创建多个配置实例的场景下它仍然是一个有用的工具。