常见问题单例和多例Spring默认Bean是单例的 。因为绝大多数Bean其实是“无状态的”,比如Controller、Service、Repository 。所以多个线程去使用同一个Bean不会造成什么问题 。本着节约成本的理念,使用单例Bean比较好 。
但是有时候我们可能会需要一个“有状态”的类,它内部又依赖其它Bean 。比如一个Context或者一个Processor之类的 。对于这种有状态有依赖其它Bean的类,有两种设计思路:
- 不给Spring管理,如果要用到其它Bean,使用上面的applicationContext来直接获取Bean 。
- 给Spring管理,做成多例Bean,每次都新建一个
所以要在单例Bean中使用多例Bean,不能使用一般的自动注入 。Spring提供了@Lookup注解来帮我们做这个事 。它是方法级别的注解 。
// 定义一个多例Bean@Component@Scope("prototype")public class PrototypeBean {public void say() {System.out.println("say something...");}}@Componentpublic class SingletonBean {public void print() {// 单例Bean中用多例BeanPrototypeBean bean = methodInject();System.out.println("Bean SingletonBean's HashCode " + bean.hashCode());}@Lookuppublic PrototypeBean methodInject() {return null;}}复制代码
需要注意的是,用@Lookup修饰的方法,不能是private的 。可以是包访问权限、protected或public的 。这里推荐写成public的,这样在单元测试的时候比较方便mock 。循环依赖循环依赖其实很好理解,就是A依赖B,而B又依赖A 。这样就形成了循环依赖 。那Spring是如何解决循环依赖的呢?
聪明你的肯定能够马上想到,如果两个Bean都是使用构造器注入,那是不能解决循环依赖的,一旦有循环依赖只能报错 。而如果是属性注入或者方法注入,那可以先初始化两个Bean,然后分别延迟注入进去 。这样就可以解决循环依赖的问题 。
这也是为什么我们推荐使用构造器注入 。循环依赖不是一个好设计,构造器注入可以提早发现这种循环依赖 。Spring使用了一个叫做三级缓存的东西来解决循环依赖,具体的实现细节本文不做讨论,感兴趣的读者可以自己去找找相关的文章 。
给不给Spring管理?又回到上面那个单例和多例的问题 。如果一个类是多例的,那它一般是有状态的,我们有必要把它交给Spring管理吗?或者说,有必要交给IoC容器管理吗?
在回答这个问题之前,我们先假设一下,如果不给IoC容器管理,会怎样?我们从三个角度来考虑:
- 这个类依不依赖其它Bean
- 这个类是不是单例的
如果这个类依赖其它Bean,那推荐交给IoC容器管理,不然还得使用上面的那种applicationContext的getBean方法来获取依赖的Bean,这就与IoC框架耦合了,不太划算 。
关于作者我是Yasin,一个有颜有料又有趣的程序员 。
微信公众号:编了个程
个人网站:yasinshaw.com
推荐阅读
- 饮食|关于维生素是否能帮助你减肥,这些真相你知道吗?
- spring框架之AOP面向切面编程
- 关于下一代智能手机的谈论 人工智能和云赋予手机完全个性化
- 看电视的利与弊
- 中国关于美人鱼的传说
- 韩信关于他与刘邦之间不同点的描述
- 交换机配置指南半分钟即可掌握关于SSL配置的内容
- 曹丕把曹彰杀了吗
- 关于人性的恶经典名句有哪些?
- 一文让你读懂JAVA.IO、字符编码、URL和Spring.Resource