目录
Spring 如何解决 bean 的循环依赖?
Spring中引入三级缓存是为了解决循环依赖问题。循环依赖是指在创建bean的过程中,存在两个或多个bean相互依赖的情况,形成一个闭环。这样的情况下,如果没有合适的机制来解决循环依赖,会导致bean的创建陷入死循环,最终导致应用程序无法启动或抛出异常。
三级缓存是Spring用来处理循环依赖的特殊机制,其原理如下:
-
第一级缓存(singletonObjects):当Spring创建一个bean时,会先检查是否有其它的实例正在创建中(即是否在第二级缓存
earlySingletonObjects
中),如果是,则返回尚未填充属性的实例。如果没有,则创建一个"空壳"(即一个空的bean实例),将其放入第一级缓存singletonObjects
中,并继续创建bean的其他依赖。 -
第二级缓存(earlySingletonObjects):当创建bean时,如果发现依赖的其他bean正在创建中(即已经在第一级缓存
singletonObjects
中),则将正在创建的bean放入第二级缓存earlySingletonObjects
中,作为一个尚未填充属性的实例。 -
第三级缓存(singletonFactories):当创建bean时,如果发现依赖的其他bean还未创建完成(即还没有放入第一级缓存
singletonObjects
中),则将创建bean所需的ObjectFactory放入第三级缓存singletonFactories
中。
通过这三级缓存的机制,Spring能够在创建bean的过程中解决循环依赖问题。当遇到循环依赖时,Spring会提前暴露正在创建的bean对象,然后继续创建其他依赖的bean,最终再回过头来填充这些“空壳”,从而解决了循环依赖的问题。
需要注意的是,三级缓存主要用于解决单例作用域的bean的循环依赖问题,对于原型作用域的bean,Spring无法解决循环依赖。
什么是 AOP?Spring 如何实现的?
AOP(面向切面编程)是一种编程范式,它是面向对象编程(OOP)的一种补充。AOP旨在通过将横切关注点(例如日志记录、安全性、事务管理等)从应用程序的核心业务逻辑中分离出来,从而提高代码的模块化性和可维护性。
在传统的面向对象编程中,一个类通常负责一个特定的功能,而横切关注点则散布在各个类的方法中。这样导致了横切关注点代码的重复和散乱,不利于代码的维护和扩展。AOP的目标是将这些横切关注点从各个类中剥离出来,并通过特殊的方式将它们应用到需要的地方,从而使代码更加简洁和易于维护。
Spring框架提供了一种实现AOP的机制,它通过动态代理和切面(Aspect)来实现AOP的功能。在Spring中,AOP的实现方式主要有两种:
-
基于代理的AOP: 这是Spring默认的AOP实现方式。它使用JDK动态代理或CGLIB动态代理来创建代理对象,然后将代理对象织入到目标对象中,从而实现横切关注点的功能。
-
基于字节码的AOP: 这是Spring的另一种AOP实现方式,它使用AspectJ来进行字节码织入,可以在更细粒度上实现AOP功能。但需要注意的是,使用AspectJ需要额外配置,并且相对于基于代理的AOP来说,更复杂一些。
Spring AOP通过定义切点(Pointcut)和通知(Advice)来实现横切关注点的织入。切点定义了在哪些连接点(Joinpoint)上应用通知,通知定义了横切关注点具体要做的事情,包括前置通知、后置通知、环绕通知等。
总的来说,Spring的AOP机制能够让我们将横切关注点从业务逻辑中分离出来,让代码更加清晰、简洁和易于维护。
BeanFactory 和 ApplicationContext 有什么区别?
BeanFactory和ApplicationContext都是Spring框架中用来管理Bean的容器,它们之间有以下区别:
-
加载时机: BeanFactory是Spring的基础接口,它是延迟加载的,即只有在第一次获取Bean时才会进行Bean的实例化和依赖注入。而ApplicationContext是BeanFactory的子接口,它在容器启动时就进行了Bean的实例化和依赖注入,因此ApplicationContext会更早地加载Bean。
-
功能扩展: ApplicationContext相比BeanFactory提供了更多的功能扩展。例如,ApplicationContext支持国际化消息处理、事件发布和监听、资源访问等功能,而BeanFactory不支持这些功能。
-
自动装配: ApplicationContext支持自动装配功能,它可以根据特定的规则自动将Bean注入到依赖的地方,减少了手动配置的工作。而BeanFactory不支持自动装配,需要手动配置依赖关系。
-
AOP: ApplicationContext支持AOP(面向切面编程)功能,可以方便地实现横切关注点的处理。而BeanFactory不直接支持AOP,需要使用第三方库或配置AspectJ来实现。
-
Web应用: 如果是在Web应用中使用,ApplicationContext还可以自动识别并注册Web应用的相关Bean,例如处理请求的控制器等。
总体来说,BeanFactory是Spring容器的基础接口,它提供了基本的Bean管理功能,适用于简单的应用场景。而ApplicationContext是BeanFactory的扩展,提供了更多的功能和特性,适用于更复杂的应用场景,尤其是Web应用。因此,在实际应用中,通常会优先选择使用ApplicationContext。
介绍一下 Spring bean 的生命周期
Spring中的Bean生命周期包括以下几个阶段:
-
实例化(Instantiation): Spring容器首先会根据配置信息或注解创建Bean的实例。在这个阶段,Spring会调用Bean的构造方法来创建对象。
-
属性赋值(Population): 在实例化后,Spring会通过依赖注入(DI)或属性注入的方式将配置的属性值注入到Bean中。这是Bean属性被填充的阶段。
-
初始化(Initialization): 在属性赋值完成后,Spring会调用Bean的初始化方法。这个初始化方法可以是通过实现InitializingBean接口的
afterPropertiesSet()
方法,也可以是通过配置文件中指定的init-method
属性来调用自定义的初始化方法。 -
销毁(Destruction): 当容器不再需要该Bean时,它会调用Bean的销毁方法来清理资源。这个销毁方法可以是通过实现DisposableBean接口的
destroy()
方法,也可以是通过配置文件中指定的destroy-method
属性来调用自定义的销毁方法。
整个Bean的生命周期可以用以下流程表示:
创建对象 -> 设置属性 -> 初始化对象 -> 销毁对象
需要注意的是,对于单例(Singleton)作用域的Bean,默认情况下Spring容器在启动时就会实例化并初始化所有的单例Bean,并在容器关闭时销毁这些单例Bean。而对于原型(Prototype)作用域的Bean,Spring容器在获取Bean时才会实例化和初始化,并不负责销毁原型Bean,需要手动管理。
此外,Spring还支持Bean的后置处理器(BeanPostProcessor),这是另外一个重要的生命周期阶段。Bean后置处理器允许在Bean的初始化前后对Bean进行一些自定义的处理。常见的应用场景包括AOP、属性加密解密、增加额外的逻辑等。
Spring 的隔离级别
在Spring事务管理中,可以设置不同的隔离级别来控制并发事务的相互影响程度。Spring定义了五种标准的隔离级别,分别为:
-
DEFAULT(默认): 使用底层数据库的默认隔离级别。通常为数据库的默认隔离级别。
-
READ_UNCOMMITTED(读取未提交): 允许一个事务读取其他事务尚未提交的数据。这种隔离级别下存在脏读、不可重复读和幻读问题。
-
READ_COMMITTED(读取已提交): 保证一个事务只能读取已经提交的数据。解决了脏读问题,但可能出现不可重复读和幻读问题。
-
REPEATABLE_READ(可重复读): 保证一个事务在多次读取同样数据时,读取到的数据是一致的。解决了脏读和不可重复读问题,但可能出现幻读问题。
-
SERIALIZABLE(串行化): 最高的隔离级别,确保每个事务都完全看不到其他事务的操作。避免了脏读、不可重复读和幻读问题,但性能较差。
这些隔离级别是根据数据库的隔离级别定义的,不同的数据库支持的隔离级别可能有所不同。在Spring中,可以通过在事务注解(@Transactional)或XML配置中设置isolation
属性来指定隔离级别。例如:
@Transactional(isolation = Isolation.READ_COMMITTED)
public void someTransactionalMethod() {
// 事务处理逻辑
}
需要根据具体业务场景选择合适的隔离级别。较高的隔离级别可以提供更高的数据一致性,但可能会影响性能。较低的隔离级别可能提高性能,但可能会引入数据不一致的问题。在设置隔离级别时,需要权衡事务的数据一致性和性能需求。
Spring 框架用到了哪些设计模式?并举出典型例子
Spring框架使用了多种设计模式来实现其功能和特性。以下是Spring框架中常用的设计模式及其典型例子:
-
单例模式(Singleton Pattern): Spring容器默认采用单例模式管理Bean,保证一个Bean只有一个实例。例如,通过
@Component
或<bean>
标签定义的Bean都默认为单例模式。 -
工厂模式(Factory Pattern): Spring使用工厂模式来创建Bean实例。在配置文件或注解中定义Bean时,可以通过FactoryBean接口或
@Bean
注解的方法来自定义Bean的创建逻辑。 -
代理模式(Proxy Pattern): Spring AOP(面向切面编程)功能使用了代理模式。通过动态代理技术,Spring在运行时生成代理对象,并在代理对象中织入横切关注点的逻辑,实现横切关注点的功能。
-
观察者模式(Observer Pattern): Spring的事件(Event)机制使用了观察者模式。当一个事件发生时,注册的监听器(观察者)会收到通知并执行相应的操作。
-
模板方法模式(Template Method Pattern): Spring的JdbcTemplate使用了模板方法模式。JdbcTemplate提供了一组模板方法,将数据库访问的通用操作封装起来,而具体的数据库操作由子类实现。
-
策略模式(Strategy Pattern): Spring的DispatcherServlet使用了策略模式。DispatcherServlet根据请求的URL选择不同的处理策略(Controller)来处理请求。
-
装饰者模式(Decorator Pattern): Spring的装饰者模式在AOP中应用广泛。通过AOP的切面(Aspect)来对原始对象进行装饰,添加额外的功能,而无需修改原始对象的代码。
-
适配器模式(Adapter Pattern): Spring的适配器模式在处理请求时使用。例如,HandlerAdapter是Spring MVC框架用于调用不同类型Controller处理请求的适配器。
-
模型-视图-控制器模式(Model-View-Controller Pattern): Spring MVC框架采用了MVC设计模式,将应用程序分为模型(Model)、视图(View)和控制器(Controller)三层,实现了业务逻辑和视图的分离。
以上仅列举了一部分在Spring框架中使用的设计模式,Spring借助这些设计模式实现了强大的功能和灵活的扩展性。