class->推断构造方法->实例化->对象->属性填充(依赖注入)->初始化->AOP->bean->生存期->销毁
- 实例化:IOC容器会实例化对应的Bean对象
- 属性填充:通过依赖注入实现
- 初始化:Bean类通过实现InitializingBean,在afterPropertiesSet()实现一些自定义的初始化操作。(还可以通过@PostConstruct标注实现自定义初始化方法)
- AOP:如果需要AOP(有对应的切面)会通过动态代理生成代理对象,否则会返回之前实例化的对象
- 生存期
- 销毁:可以在销毁之前通过@PreDestroy自定义销毁方法,最后会调用DisposableBean接口的destroy方法
动态代理
- JDK动态代理:这是Java提供的动态代理技术,可以在运行时创建接口的代理实例。Spring AOP默认采用这种方式,在接口的代理实例中织入代码。
- CGLib动态代理:采用底层的字节码技术,在运行时创建子类代理的实例(通过继承重写有切点的方法,然后执行对应切点实现的方法)。当目标对象不存在接口时,Spring AOP就会采用这种方式,在子类实例中织入代码。
Spring单例bean
默认情况下,Bean在Spring容器中是单例的,我们可以通过@Scope注解修改Bean的作用域。该注解有如下5个取值,它们代表了Bean的5种不同类型的作用域:
类型 | 说明 |
---|---|
singleton | 在Spring容器中仅存在一个实例,即Bean以单例的形式存在。 |
prototype | 每次调用getBean()时,都会执行new操作,返回一个新的实例。 |
request | 每次HTTP请求都会创建一个新的Bean。 |
session | 同一个HTTP Session共享一个Bean,不同的HTTP Session使用不同的Bean。 |
globalSession | 同一个全局的Session共享一个Bean,一般用于Portlet环境。 |
Spring中默认提供的单例是线程安全的吗?
参考答案
不是。
Spring容器本身并没有提供Bean的线程安全策略。如果单例的Bean是一个无状态的Bean,即线程中的操作不会对Bean的成员执行查询以外的操作,那么这个单例的Bean是线程安全的。比如,Controller、Service、DAO这样的组件,通常都是单例且线程安全的。如果单例的Bean是一个有状态的Bean,则可以采用ThreadLocal对状态数据做线程隔离,来保证线程安全。