嘿,咱们聊聊怎么让程序里的Bean们一起干活吧。其实真系统里很少只有一个Bean在那干巴巴地跑,通常都是一堆Bean互相配合着才把事儿做成。所以这篇文章,主要就是想说说怎么突破那种一个人干所有活的模式,让多个Bean能高效地合作起来。 先来聊聊依赖注入,也就是DI这事儿。说白了,就是以前对象自己得去到处找它需要的东西,现在改让容器帮忙把这些东西塞给它了。具体咋塞呢?有好几种方法:要么把依赖当成构造函数的参数传进去,要么用工厂方法的参数传,或者就是把依赖当成属性通过setter方法塞进去。总之容器在创建Bean的时候帮你搞定所有这些注入的活儿,这就叫控制反转,也就是IoC了。 好处特明显,代码看着更清爽,解耦也做得好。要是写测试代码的时候想Mock某个接口或者抽象类也特别容易。 现在DI主要有两种实现方式。第一种是构造器注入,Spring通常是用多参数的构造函数来干这个事儿。每个参数就是一个依赖项。 有时候参数多了容易分不清顺序咋办?那就有三种办法给你兜底: 1. 直接指定类型(type); 2. 按位置数位置(index); 3. 看参数的名字(name)。 不过得注意编译的时候得带上调试信息才行。 第二种是Setter注入。这种方法先把Bean对象创建出来了,再去调用没参数的构造方法或者静态工厂方法生成实例。 然后就可以通过调用setter方法把依赖给塞进去。 优点是类设计上更灵活,有些依赖可以做成可选项以后方便修改配置;缺点就是得手动判断下依赖是否为空了,还有可能对象没完全初始化好。 这两种方法其实可以混着用啊: 那些必须要用的强制性依赖就用构造器注入; 那些可多可少的可选依赖就用Setter注入; 这是最常见的最佳实践了。 如果碰到那种依赖关系特别复杂的情况——比如静态初始化器或者驱动注册什么的——光靠容器自己判断顺序可能不行。 这时候就得用depends-on这个属性来强行指定Bean之间的初始化顺序了: 给你看个例子: 这一行代码就能一口气指定好多Bean的初始化顺序。 而且还能同时控制初始化期和销毁期两个阶段的双向顺序,这样关闭的时候管理起来也方便。 再来说说延迟初始化的事儿吧。 默认情况下ApplicationContext刚启动的时候就会把所有单例的Bean都预先实例化好。 这样做有个好处是如果有什么错误能马上报错出来比较方便。 但是有的Bean其实只有在特定场景下才会用到提前实例化出来反而浪费资源。 这时候就可以把lazy-init属性设成true: 或者直接在注解上加个@Lazy也能达到同样的效果。 不过要注意一点:如果一个非懒加载的单例Bean依赖了一个懒加载的Bean的话容器还是会在启动阶段就先把它创建出来以满足单例的依赖要求。 如果真想把整个项目都延迟加载可以在标签里设置default-lazy-init="true"。