当前位置: 首页 > news >正文

Spring依赖管理核心技巧与应用

以下内容是 Spring Framework 官方文档中关于依赖管理(Dependency Management)的几个核心章节,主要包括:

  • 1.4.3 Using depends-on
  • 1.4.4 Lazy-initialized Beans
  • 1.4.5 Autowiring Collaborators
  • 1.4.6 Method Injection

下面我将用通俗易懂、结构清晰的方式为你逐段解释这些概念的本质和实际用途,帮助你真正“理解”它们。


✅ 一、depends-on:控制 Bean 的初始化顺序

📌 核心思想:

有时候,某个 Bean 的创建依赖于另一个 Bean 必须先被初始化完成,即使它没有直接引用那个 Bean。比如数据库驱动注册、静态代码块执行等。

这时就可以使用 depends-on 来强制指定依赖关系。

🔧 示例说明:

<bean id="beanOne" class="ExampleBean" depends-on="manager"/>
<bean id="manager" class="ManagerBean" />
  • 虽然 beanOne 没有把 manager 当作属性注入,但 Spring 会确保:
    • 先创建 manager
    • 再创建 beanOne

💡 场景举例:manager 可能是一个负责加载配置或注册 JDBC 驱动的类,它的静态块做了关键操作,所以必须在 beanOne 创建前运行。

🔄 多个依赖怎么写?

<bean id="beanOne" class="ExampleBean" depends-on="manager,accountDao">

支持逗号、空格、分号分隔多个 bean 名称。

⚠️ 特别注意:

  • depends-on 不仅影响 初始化顺序,也影响 销毁顺序
  • 如果 A depends-on B,则:
    • 初始化时:B → A
    • 销毁时:A → B (反向)

这保证了资源安全释放。


✅ 二、lazy-init="true":延迟初始化 Bean

📌 默认行为(饿汉式):

Spring 的 ApplicationContext 在启动时就会预先创建所有 singleton bean(单例 Bean),称为“预实例化”。

优点:尽早发现问题(如配置错误、循环依赖等)。
缺点:启动慢,尤其对一些“重量级但不常用”的 Bean(如缓存服务、大数据处理器)。

🔧 解决方案:懒加载

<bean id="lazy" class="com.something.ExpensiveToCreateBean" lazy-init="true"/>
  • 这个 Bean 不会在容器启动时创建
  • 第一次被请求(getBean 或被其他 Bean 引用)时才创建

❗ 一个重要例外:

如果一个 lazy bean 被一个 非 lazy 的 singleton bean 依赖,那么它仍然会在容器启动时被创建!

因为 Spring 必须满足那个非 lazy bean 的依赖。

🏗️ 全局设置懒加载:

<beans default-lazy-init="true"><!-- 所有 bean 默认都是 lazy -->
</beans>

适合性能敏感的应用,在开发环境可关闭以便快速发现问题。


✅ 三、autowiring:自动装配协作 Bean

📌 是什么?

让 Spring 自动帮你找合适的 Bean 注入到当前 Bean 中,而不用手动写 <property ref="...">

🎯 四种模式对比:

模式说明使用场景
no(默认)不自动装配,必须显式用 <ref>推荐生产环境使用,清晰可控
byName根据属性名匹配 Bean IDsetUserDao(UserDao) → 查找 id=“userDao” 的 Bean
byType根据类型匹配唯一 Bean类型唯一时很方便
constructor构造函数参数按类型自动匹配byType 类似,用于构造器注入

✅ 示例:byName

public class UserService {private UserDao userDao;public void setUserDao(UserDao userDao) { this.userDao = userDao; }
}
<bean id="userService" class="UserService" autowire="byName"/>
<bean id="userDao" class="UserDaoImpl"/> <!-- 名字匹配 -->

→ Spring 自动调用 setUserDao(...)userDao 注入进去。

⚠️ 局限性 & 缺点:

  1. 不能自动装配基本类型(int, String, boolean 等)
  2. 模糊性问题:如果有两个相同类型的 Bean,byType 就会抛异常
    No unique bean of type X found. Expected single matching bean but found 2: bean1, bean2
    
  3. 可读性差:别人看不懂你的 Bean 到底依赖了谁
  4. 工具难以分析:文档生成工具无法提取依赖信息

✅ 如何解决歧义?

方法说明
autowire-candidate="false"排除某个 Bean 被自动装配
primary="true"设为首选 Bean(当多个候选时优先选它)
改用注解方式(@Autowired + @Qualifier)更灵活精确
示例:排除自动装配
<bean id="badDao" class="BadUserDao" autowire-candidate="false"/>

这样即使类型匹配,也不会被选中。

全局限制命名模式:
<beans default-autowire-candidates="*Service,*DAO">

只有名字符合模式的 Bean 才能参与自动装配。


✅ 四、方法注入(Method Injection)——高级技巧

🧩 核心问题:

单例 Bean 如何每次都能获取一个新的原型(prototype)Bean?

常见于:命令模式、工厂模式、事务处理等需要“每次新建对象”的场景。

❌ 普通注入不行!
@Service
public class CommandManager {@Autowiredprivate Command command; // 如果 command 是 prototype,这里只会注入一次!
}

→ 因为 CommandManager 是单例,只初始化一次,command 也就固定了。


✅ 解法一:查找方法注入(Lookup Method Injection)

思路:

让 Spring 动态重写(override)一个方法,让它每次都返回新的 Bean 实例。

实现方式(XML):
<!-- 原型 Bean -->
<bean id="myCommand" class="AsyncCommand" scope="prototype"/><!-- 单例管理器 -->
<bean id="commandManager" class="CommandManager"><lookup-method name="createCommand" bean="myCommand"/>
</bean>

Java 类要定义抽象方法:

public abstract class CommandManager {public Object process() {Command cmd = createCommand(); // 实际由 Spring 动态实现return cmd.execute();}protected abstract Command createCommand(); // 抽象方法,Spring 来覆盖
}

Spring 会在运行时通过 CGLIB 生成子类,覆盖 createCommand(),使其每次返回 myCommand 的新实例。

Kotlin 注意事项:

Kotlin 默认类和方法是 final 的,CGLIB 无法继承。你需要:

  • 使用 open 关键字
  • 或者启用 kotlin-spring 插件自动打开类

✅ 解法二:@Lookup 注解(更现代)

@Component
public abstract class CommandManager {@Lookupprotected abstract Command createCommand();public void run() {Command cmd = createCommand(); // 每次都是新实例cmd.execute();}
}

也可以指定名字:

@Lookup("myCommand")
protected abstract Command createCommand();

✅ 推荐使用这种方式,比 XML 更简洁。


✅ 解法三:ObjectFactory / Provider(推荐替代方案)

比起 @Lookup,更推荐使用:

方式1:ObjectFactory<T>
@Service
public class CommandManager {@Autowiredprivate ObjectFactory<Command> commandFactory;public void run() {Command cmd = commandFactory.getObject(); // 每次拿新实例cmd.execute();}
}
方式2:JSR-330 的 Provider<T>
@Autowired
private Provider<Command> commandProvider;public void run() {Command cmd = commandProvider.get(); // 每次 new 一个
}

✅ 优势:

  • 不需要抽象类
  • 不依赖 CGLIB
  • 更容易测试
  • 更符合函数式编程风格

✅ 方法替换(Arbitrary Method Replacement)——几乎不用

这是 Spring 提供的一个冷门功能:可以完全替换一个方法的实现。

示例:

你想把 MyValueCalculator.computeValue(String) 方法替换成别的逻辑。

<bean id="myCalc" class="MyValueCalculator"><replaced-method name="computeValue" replacer="myReplacer"><arg-type>String</arg-type></replaced-method>
</bean><bean id="myReplacer" class="ReplacementComputeValue"/>

ReplacementComputeValue 实现 MethodReplacer 接口,提供新的逻辑。

⚠️ 实际上很少用,因为可以用 AOP 或策略模式更好解决。


✅ 总结:一张表帮你理清重点

特性作用使用建议
depends-on控制初始化/销毁顺序用于静态初始化依赖(如驱动注册)
lazy-init="true"延迟创建 Bean用于重量级、不常用的 Bean
autowire="byType"自动按类型注入开发阶段可用,生产建议显式配置
@Lookup / <lookup-method>单例中获取原型实例替代方案:ObjectFactoryProvider
autowire-candidate="false"排除自动装配候选配合 primary="true" 解决歧义
Method Replacement替换方法实现几乎不用,可用 AOP 替代

✅ 最佳实践建议

  1. 不要滥用 autowiring,尤其是大型项目,显式配置更清晰。
  2. 尽量避免 depends-on,良好的设计应减少这种隐式依赖。
  3. 延迟初始化谨慎使用,除非明确知道会影响启动性能。
  4. 获取 prototype bean 时,优先使用 ObjectFactory<T>Provider<T>,而不是 @Lookup
  5. 多利用 @Primary@Qualifier 来解决自动装配冲突。

如果你正在学习 Spring IOC,这几个知识点属于“进阶内容”,掌握后你会明白:

“原来 Spring 是如何巧妙解决单例与原型协作的问题的。”

如果你想结合 Java 注解方式进一步理解,我可以补充基于 @Configuration@Bean@Autowired 的等价写法。

是否需要?欢迎继续提问!

http://www.dtcms.com/a/525763.html

相关文章:

  • java面试:有了解过消息队列mq吗,详细讲解一下
  • 建设校园网站公司怎么介绍自己的优势
  • 第十四届蓝桥杯大赛软件赛国赛Java大学C组(部分)
  • 2025年--Lc211- 557. 反转字符串中的单词 III--Java版
  • 网站建设售后服务承诺网站做多久才有流量
  • 网站外包制作工程建设报道
  • 【u-boot】u-boot启动文件start.S剖析(ARM64)
  • 【JUnit实战3_11】第六章:关于测试的质量(下)
  • 最新选题-基于Spark的二氧化碳排放量数据分析系统设计
  • 438.找到字符串中所有字母异位词
  • 鞍山手机网站设计广东省室内设计公司排名
  • 适合seo优化的网站制作网站鼠标特效
  • 【无标题】叽叽喳喳
  • 多线程六脉神剑第四剑:读写锁 (ReaderWriterLockSlim)
  • 网站设关键字wordpress搭建问答系统
  • 泉州高端网站建设微信h5免费制作网站模板下载
  • 第13章-人员管理
  • Maya Python入门:属性连接connectAttr()、创建节点createNode()
  • Java学习之旅第三季-17:Lambda表达式
  • 企业电子商务网站建设和一般建设网站收费标准
  • 【深度学习】深度学习核心:优化与正则化超详细笔记
  • 南昌做网站哪个好如何做好网站推广工作
  • 网站网速慢网站正在建设中_敬请期待
  • 影刀:自动化测试网页应用
  • 做彩票网站要什么接口只放一个图片做网站
  • git重写历史
  • 免费下载app软件网站寻找网站建设公司
  • 动易手机网站外贸商城源码
  • 简述网站建设流程中的各个步骤wordpress破解主题商务
  • 2025年--Lc213-2000. 反转单词前缀-Java版