1. BeanFactory和ApplicationContext有什么区别
- BeanFactory是各种bean集合的工厂类,BeanFactory包含了各种bean的定义,以便在接收到客户端请求时将对应的bean实例化。
BeanFactory还包含了bean生命周期的控制。
- ApplicationContext和Bean factory一样具有bean定义、关联根据请求分发bean的功能,但是ApplicationContext在此基础上
- 还提供了其他功能,如支持国际化文本消息、统一资源文件读取方式等。
2. Spring Bean的生命周期
Spring框架的核心特征之一是IOC容器,他管理着应用程序中对象的创建、配置和管理。Spring Bean是被Spring IOC容器管理的对象。
Bean的生命周期是指从Bean的创建到销毁的整个过程。
1. 创建Bean实例
2. 设置Bean属性
- Spring会通过反射设置Bean的属性值,这些属性可以是从其他Bean注入的,或者是在配置文件中指定的值。
- Spring使用@Autowired,@Inject,@Value等注解来自动装配Bean属性。
3. 依赖注入后的处理
- Spring会调用Bean的postProcessBeforeInitialization方法来进一步处理Bean。
- 如果Bean实现了InitializingBean接口,Spring会调用afterPropertiesSet()方法。
- 如果Bean类中带有@PostConstruct注解的方法,Spring也会调用该方法。
- 这些步骤用于执行任何必要的初始化操作。
4. 初始化
- 如果Bean定义中包含了初始化方法(例如init-method属性),Spring也会调用该方法。
5. Bean处于活动状态
6. 销毁Bean
- 当Spring容器关闭时,如果Bean实现了DisposableBean接口,Spring会调用destory方法。
- 如果Bean定义中包含了销毁方法,Spring会调用该方法。
- 如果Bean类中定义了带有@PreDestroy注解的方法,Spring也会调用该方法
3. Spring IOC如何实现
1. 配置元数据:首先需要定义一个配置元数据,这是Spring IOC容器用来创建和配置Bean的基础。
2. 创建容器:Spring提供了两个主要的容器实现。
- BeanFactory:这是一个底层的接口,提供了Bean工厂的基本功能
- ApplicationContext:这是一个更高级的接口
3. 解析配置:当容器启动时,他会解析配置元数据并创建一个内部的数据结构来存储这些信息。
4. Bean实例化:Bean的实例化过程如下
- 根据Bean定义中指定的构造器创建Bean实例。
- 如果Bean定义中指定了依赖,Spring会通过构造器注入、setter注入或者其他注入方式来注入依赖。
- Spring使用BeanPostProcessor接口来允许开发者在Bean实例化前后进行额外的处理。
5. 初始化:Bean实例化后,Spring调用Bean的初始化方法,通常发生在实现了InitializingBean接口的afterPropertiesSet方法
或通过@PostConstruct注解的方法。
6. Bean的使用
7. 销毁
4. Spring AOP实现原理
Spring AOP是一种编程范式,他允许将横切关注点从业务逻辑中分离出来。在Spring框架中,AOP主要通过代理模式来实现。
Spring AOP实现原理如下:
1. 配置切点:定义哪些连结点应该被通知,通常使用切点表达式来指定方法签名。
2. 创建代理:根据目标对象的类型选择适当的代理对象。
JDK动态代理:如果目标对象至少实现了一个接口,则Spring AOP会使用JDK动态代理。
CGLIB动态代理:如果目标对象没有实现接口,Spring AOP会使用CGLIB创建一个子类来代理。
3. 处理方法调用:当客户端代码调用目标对象的方法时,实际上是调用了代理对象。
4. 拦截方法调用:代理对象拦截方法调用,并决定是否需要调用通知。
5. 调用通知:根据配置调用相应的通知。
6. 继续执行:通知完成后,代理对象将调用目标对象的方法。
7. 返回结果:目标方法执行完毕后,代理对象返回结果给客户端代码。
示例:
创建简单的服务类
public class SimpleService {
public void doSomething() {
System.out.println("Doing something...");
}
}
创建切面类
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class LoggingAspect {
// 第一步:配置切点
@Before("execution(* com.example.SimpleService.doSomething(..))")
public void logBefore(JoinPoint joinPoint) {
System.out.println("Executing: " + joinPoint.getSignature().getName());
}
}
注册Bean和切面
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator;
@Configuration
public class AppConfig {
@Bean
public SimpleService simpleService() {
return new SimpleService();
}
//第五步:拦截调用通知
@Bean
public LoggingAspect loggingAspect() {
return new LoggingAspect();
}
// 第二步:创建代理
@Bean
public AnnotationAwareAspectJAutoProxyCreator aspectJAutoProxyCreator() {
return new AnnotationAwareAspectJAutoProxyCreator();
}
}
使用服务
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class App {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
SimpleService simpleService = context.getBean(SimpleService.class);
//第三步:服务调用
simpleService.doSomething();
}
}
5. Spring事务实现方式
Spring框架提供了对事务管理的支持,使得开发者可以容易的控制事务的开始、提交和回滚。
Spring事务管理有两种主要实现方式:编程式事务管理、声明式事务管理。
1. 编程式事务管理:开发者显示的控制事务的开始、提交和回滚。这种方式适用于那些需要对事务有更细粒度控制的场景。
示例:
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
public class UserService {
private PlatformTransactionManager transactionManager;
public UserService(DataSourceTransactionManager transactionManager) {
this.transactionManager = transactionManager;
}
public void createUser(User user) {
TransactionDefinition def = new DefaultTransactionDefinition();
TransactionStatus status = transactionManager.getTransaction(def);
try {
// 执行数据库操作
saveUser(user);
saveUserLog(user); // 假设这是一个记录用户操作日志的方法
transactionManager.commit(status);
} catch (Exception e) {
transactionManager.rollback(status);
throw e;
}
}
private void saveUser(User user) {
// 执行保存用户的数据库操作
}
private void saveUserLog(User user) {
// 执行保存用户操作日志的数据库操作
}
}
2. 注解声明式事务管理
在Spring中,声明式事务管理通常通过@Transactional注解来实现。
6. Spring事务底层原理
Spring事务主要基于数据库事务和AOP机制来实现的。核心步骤如下
1. 创建代理对象
当Spring容器检测到某个Bean的方法使用了@Transactional注解,Spring会为这个Bean创建一个代理对象,
这个代理对象会拦截所有对原始Bean方法的调用,并在调用前后执行事务相关的逻辑。
2. 事务的开启和连接处理
- 开启事务:当代理对象拦截到一个被@Transactional注解的方法时,Spring首先判断当前是否已经存在一
个事务,如果不存在,会根据配置的事务管理器(DataSourceTransactionalManager)来开启一个新的事务。
- 连接处理:事务管理器会创建一个数据库连接,并将这个连接的autocommit属性设置为false,
以禁用自动提交。
3. 业务逻辑执行
在事务上下文中,代理对象会调用原始Bean的方法执行实际的业务逻辑。这些业务逻辑可能包括多个数据库操作。
4. 提交或者回滚事务
- 提交事务:如果业务逻辑执行成功且没有抛出异常,那么代理对象会在方法返回前调用事务管理器的commit
方法,提交事务并释放数据库连接。
- 回滚事务:如果业务逻辑执行过程中抛出了异常,那么 *代理对象会捕获这个异常,并调用事务管理器的
rollback方法。
5. 事务传播行为
Spring还提供了事务的传播行为,允许开发者控制事务的边界和行为。例如,PROPAGATION_REQUIRED表示
当前方法必须运行在事务中,如果当前存在事务,就加入该事务,否则创建一个新的事务。
6. 隔离级别
事务的隔离级别也是Spring事务管理的一个方面。他定义了事务间的可见性和干扰程度。Spring支持数据
库的四种标准隔离级别(读未提交、读已提交、可重复读、串行化)。并允许开发者在@Transactional注解
中指定所需的隔离级别。
7. 底层实现
Spring事务的实现依赖于数据库的事务机制,真正的数据库层的事务提交和回滚是通过数据库
的日志来实现的。Spring事务管理器只是作为一个中间层,负责协调和管理这些事务。
总结:
Spring事务底层原理是一个基于AOP和数据库事务机制的高效过程,他通过代理对象拦截方法调用,在事务上下文中执行业务逻辑,并在适当的时候提交或者回滚事务。同时,Spring还提供了丰富的事务传播行为和隔离级别选项,以满足不同场景下的需求
。
7. Spring事务的传播行为
Spring事务的传播行为在Spring框架中是一个重要的概念,他定义了当一个事务方法被另一个事务方法调用时,事务应该如何进行。Spring提供了七种事务传播行为。
(1).PROPAGATION_REQUIRED(默认行为)
a. 如果当前存在事务,则加入该事务;否则,创建 一个新的事务。
b. 方法A调用方法B,如果A在事务中,B也将在A的事务中运行;如果A不在事务中,则B开启一个新的事务。
(2).PROPAGATION_REQUIRES_NEW
a. 总是开启一个新的事务
b. 方法A调用方法B,无论A是否在事务中,B都将开启一个新的、与A无关的事务。
(3).PROPAGATION_SUPPORTS
a. 如果当前存在事务,则加入该事务;否则,以非事务的方式继续运行。
(4).PROPAGATION_MANDATORY
a. 如果当前存在事务,则加入该事务;否则,抛出异常。
(5).PROPAGATION_NOT_SUPPORTED
a. 以非事务的方式运行,如果当前存在事务,则把事务挂起。
(6).PROPAGATION_NEVER
a. 以非事务的方式运行,如果当前存在事务,则抛出异常。
(7).PROPAGATION_NESTED
a. 如果当前存在事务,则在嵌套事务中运行。嵌套事务可以保存为保存点,允许他回滚到保存点,而不影响外部事务。
b. 方法A调用方法B,如果A在事务中,B将在A的嵌套事务中运行。如果B失败并回滚,他将回滚到嵌套事务的起始点,而不影响A的部分。
8. SpringMVC运行流程
- SpringMVC 将所有的请求都提交给DispatcherServlet,他会委托应用系统的其他模块负责对请求进行真正的处理工作。
- DispatcherServlet查询一个或者多个HandlerMapping,找到处理请求的Controller。
- DispatcherServlet将请求提交到目标Controller。
- Controller进行业务逻辑处理后,返回一个ModelAndView。
- DispatcherServlet查询一个或者多个ViewResolver视图解析器,找到ModelAndView对象指定的视图对象。
- 视图对象负责渲染返回给客户端。
9. SpringMVC启动流程
SpringMVC的启动是一个负责但是有序的过程,主要涉及Tomcat的启动、Spring容器的创建和初始化、以及DispatcherServlet的初始化与配置。以下是SpringMVC启动流程的详细步骤:
1. Tomcat启动
Tomcat作为web容器,首先启动并读取web.xml文件,在web.xml文件中,
会配置SpringMVC的前端控制器DispatcherServlet。
2. 解析web.xml文件
Tomcat解析文件时,会识别到DispatcherServlet的配置,通常包括Servlet名称、类名以及初始化参数。
3. 创建DispatcherServlet对象
根据web.xml中的配置,Tomcat会创建DispatcherServlet实例。
4. 初始化DispatcherServlet
调用DispatcherServlet的init()方法,该方法会进一步执行SpringMVC的初始化逻辑。
5. 初始化Spring容器
在DispatcherServlet的init()方法中,会创建一个Spring容器(WebApplicationContext),
并加载SpringMVC的配置文件。其中定义了Spring MVC的Bean和配置信息。
6. 注册并初始化组件
DispatcherServlet会注册并初始化多个关键组件,包括
a. HandlerMapping: 负责将请求映射到相应的处理器上。
b. HandlerAdapter: 负责将请求适配到相应的处理器上。由于处理器可能有多种类型
(如实现了Controller接口的Bean、实现了HttpRequestHandler接口的Bean、
带有@RequestMapping注解的方法等),因此需要不同的HandlerAdapter来处理不同类型的处理器。
c. ViewResolver: 负责将处理器返回的ModelAndView对象渲染成具体的视图。
d. 其他组件:如MultipartResolver、LocaleResolver等。
7. 监听器和事件
在Spring容器启动过程中,会注册一个ContextRefreshListener监听器,当Spring容器创建完成时,
会发布一个ContextRefreshEvent事件,该事件会被ContextRefreshListener捕获并处理,进而执
行DispatcherServlet的initStrategies()方法,完成上述组件的初始化。
8. 处理Http请求
初始化完成后,DispatcherServlet会监听HTTP请求,当有请求到达时,会根据请求的路径和类型,
通过HandlerMapping找到对应的处理器(Controller),然后通过HandlerAdapter调用处理器的
方法处理请求,处理完成后,将结果封装成ModelAndView对象,并交给ViewResolver进行渲染,
最终生成响应返回给客户端。
总结:SpringMVC的启动流程是一个从Tomcat启动到DispatcherServlet初始化,再到Spring容器创建和
组件注册的过程。这个过程中涉及多个关键组件的初始化和配置,以确保Spring MVC能够正确处理HTTP请求并
返回响应。
10. Spring的单例实现原理
Spring对Bean的实例创建是采用单例注册表的方式进行实现的,而这个注册表的缓存是ConcurrentHashMap对象。