Spring 是一个轻量级的 Java 开发框架,它通过控制反转(IoC)和面向切面编程(AOP)等核心技术,为企业级应用提供了全面的解决方案。它整合了事务管理、Web 开发、数据访问等功能模块,具有模块化、非侵入性等特点。
控制反转与依赖注入:IoC,将对象的创建和依赖关系的管理从代码中移除,转由 Spring 容器负责。DI:IoC 的具体实现方式,通过构造器、Setter 方法或字段注入,将依赖对象传递给目标对象。
面向切面编程:Spring AOP 通过代理或字节码增强技术,将日志、事务等横切关注点模块化,定义切面(Aspect)、通知(Advice)、切入点(Pointcut)等概念,在不修改原有业务逻辑的前提下增强功能,实现了业务代码与系统服务的解耦,提升了代码的复用性和可维护性。
MVC分层框架:MVC 分层框架将应用分为 Model(数据与业务)、View(界面展示)、Controller(逻辑调度)三层,通过职责分离提升代码复用性与可维护性,广泛应用于 Spring MVC 等框架,是企业级开发的经典架构模式。
事务管理:Spring 提供声明式事务管理,通过 @Transactional 注解和 AOP 机制,在方法层面定义事务边界,支持传播行为(如 REQUIRED)和隔离级别配置,确保数据操作的原子性和一致性,使事务管理代码与业务逻辑分离,简化了企业级应用的数据持久化操作。
传播行为
传播行为 | 英文原名 | 核心特性 | 典型使用场景 |
---|---|---|---|
REQUIRED | 必须参与事务 | 若无事务则新建,有则加入 | 核心业务操作(如订单创建、资金转账) |
SUPPORTS | 支持事务 | 存在事务时加入,否则非事务执行 | 只读查询操作(提升性能) |
MANDATORY | 强制事务 | 必须在已有事务中执行,无则抛异常 | 依赖事务上下文的底层操作 |
REQUIRES_NEW | 新建事务 | 挂起当前事务,新建独立事务执行 | 异步任务 / 日志记录(避免主事务影响) |
NOT_SUPPORTED | 不支持事务 | 挂起当前事务,以非事务方式执行 | 缓存更新 / 非关键数据操作 |
NEVER | 禁止事务 | 若存在事务则抛异常 | 纯计算逻辑(无数据持久化需求) |
NESTED | 嵌套事务 | 基于保存点实现子事务,外层回滚影响内层,内层回滚不影响外层 | 分阶段操作(如支付前库存校验) |
隔离级别
隔离级别 | 脏读允许 | 不可重复读允许 | 幻读允许 | 数据库默认场景 | 性能消耗 |
---|---|---|---|---|---|
READ_UNCOMMITTED | 是 | 是 | 是 | 极少使用(数据一致性要求极低) | 最低 |
READ_COMMITTED | 否 | 是 | 是 | Oracle 默认级别(读多写少场景) | 较低 |
REPEATABLE_READ | 否 | 否 | 是 | MySQL 默认级别(默认推荐) | 中等 |
SERIALIZABLE | 否 | 否 | 否 | 金融 / 交易场景(强一致性要求) | 最高 |
DEFAULT | 由数据库决定 | 由数据库决定 | 由数据库决定 | MySQL→REPEATABLE_READ Oracle→READ_COMMITTED | 依赖数据库 |
概念 | 核心思想 | 解决的问题 | 实现方式 | 典型应用场景 |
---|---|---|---|---|
IoC | 控制反转:将对象的创建和依赖关系的管理从代码转移到容器,由容器控制对象生命周期。 | 传统代码中对象硬编码依赖导致的耦合度高、可测试性差问题。 | 依赖查找(DL)、依赖注入(DI)。 | Spring 容器通过ApplicationContext 管理 Bean 的生命周期。 |
DI | 依赖注入:IoC 的具体实现方式,通过构造器、Setter 或字段注入依赖对象。 | 组件间依赖关系的手动管理繁琐,且依赖具体实现而非接口。 | 构造器注入、Setter 注入、注解注入(如@Autowired )。 |
服务层注入数据访问层组件:public UserService(UserRepository userRepository) {...} 。 |
AOP | 面向切面编程:将横切关注点(如日志、事务)模块化,通过代理或字节码增强织入目标代码。 | 业务逻辑与系统服务(如日志、安全)耦合导致代码冗余、可维护性差。 | 静态代理(编译时增强)、动态代理(运行时增强,如 JDK 动态代理、CGLIB)、字节码编织(如 AspectJ)、切面配置。 | 统一日志记录、事务管理、权限校验等。 |
Spring IoC 的核心是将对象的创建与依赖管理从程序代码中剥离,交由容器统一管控。开发者无需手动 new 对象,只需通过注解或配置描述依赖关系,容器会在运行时自动构建对象图并注入依赖。这种方式实现了对象间的松耦合,使代码更易测试和维护,例如服务层可直接通过@Autowired
获取 DAO 实例,而无需关心其具体创建过程,是 Spring 框架简化开发的基础机制。
Spring AOP 通过分离 “业务逻辑” 与 “横切关注点”(如日志、事务),将重复逻辑封装为独立切面,利用动态代理、CGLIB代理等技术在运行时将切面逻辑织入目标方法。开发者通过@Aspect
定义切面,用@Pointcut
指定作用范围,@Before/@After
等注解控制逻辑执行时机,避免在业务代码中硬编码重复逻辑。例如在服务方法调用前后自动记录日志,既保证业务代码纯净,又实现了逻辑复用,是提升代码可维护性的关键技术。
JDK动态代理和CGLIB代理讲一下
JDK动态代理
JDK 动态代理是 Java 原生提供的基于接口的代理机制,通过java.lang.reflect.Proxy
和InvocationHandler
在运行时动态生成代理类字节码。代理对象实现与目标对象相同的接口,方法调用通过反射转发至InvocationHandler
处理,从而实现对目标方法的增强。其优势在于无需额外依赖、符合面向接口编程原则,是 Spring AOP 的默认选择(当目标对象实现接口时),但只能代理接口方法,无法处理未实现接口的类。
具体执行流程:代理对象的方法调用会先跳转至InvocationHandler
的invoke
方法,再通过反射调用目标对象的实际方法
CGLIB代理
CGLIB 是基于继承的代理机制,通过 ASM 字节码库在运行时生成目标类的子类作为代理。代理类重写父类方法,并在调用时通过MethodInterceptor
拦截,直接调用父类方法而非反射,因此性能略高。CGLIB 无需目标类实现接口,可代理未实现接口的类,但无法代理final
类或方法,适用于 Spring AOP 中未实现接口的 Bean(如 Controller),是 JDK 动态代理的补充方案。
具体执行流程: 代理对象的方法调用会先进入MethodInterceptor
的intercept
方法,再通过MethodProxy.invokeSuper
直接调用目标类的原始方法
概念以及思想在前几点已总结
术语 | 定义 | 示例 |
---|---|---|
切面(Aspect) | 封装横切逻辑的类,包含切点和通知的定义。 | @Aspect 注解标注的类,如 LogAspect 。 |
切点(Pointcut) | 定义横切逻辑作用的目标方法,通过表达式匹配方法签名。切点是连接点的一部分。 | execution(* com.service.*Service.*(..)) 匹配所有 Service 类的方法。 |
通知(Advice) | 横切逻辑的具体实现,分为 5 种类型,定义何时、如何增强目标方法。 | @Before 前置通知:在目标方法前执行日志记录。 |
连接点(Joinpoint) | 程序执行过程中的特定点(如方法调用、异常抛出),Spring AOP 仅支持方法调用。 | 调用 UserService.save() 方法时的连接点。 |
目标对象(Target Object) | 被代理的原始对象,即被增强的业务对象。 | UserService 实例。 |
AOP 代理(Proxy) | 由 Spring 生成的代理对象,用于拦截方法调用并应用切面逻辑。 | 通过 JDK 或 CGLIB 生成的代理对象,如 UserServiceProxy 。 |
通知类型
@Before
(前置通知):目标方法执行前调用。@After
(后置通知):目标方法正常执行完毕后调用(无论是否有返回值)。@AfterReturning
(返回后通知):目标方法成功返回后调用,可获取返回值。@AfterThrowing
(异常通知):目标方法抛出异常后调用,可获取异常信息。@Around
(环绕通知):包裹目标方法,可在方法前后执行逻辑,甚至控制方法是否执行(最强大的通知类型)。通知类型执行顺序
Ioc核心实现技术
AOP核心实现技术
Spring AOP的实现依赖于动态代理技术。动态代理是在运行时动态生成代理对象,而不是在编译时。它允
许开发者在运行时指定要代理的接口和行为,从而实现在不修改源码的情况下增强方法的功能。
Spring AOP支持两种动态代理:
基于JDK的动态代理:使用java.lang.reflect.Proxy类和java.lang.reflect…InvocationHandler接口实现。这
种方式需要代理的类实现一个或多个接口。
**基于CGLIB的动态代理:**当被代理的类没有实现接口时,Spring会使用CGLIB.库生成一个被代理类的子
类作为代理。CGLIB(Code Generation Library)是一个第三方代码生成库,通过继承方式实现代理。
UserService
若依赖UserRepository
,无需在UserService
中手动 newUserRepository
,而是通过@Autowired
让容器将UserRepository
实例注入,实现对象间依赖关系的解耦。@Component
等注解让容器负责,体现了 “被动接受控制” 的反转逻辑,最终降低代码耦合度。构造器注入:保证对象初始化时依赖已就绪
// 构造器注入示例
class UserService {
private final UserDao userDao;
// 通过构造器接收依赖对象(final修饰确保不可变)
public UserService(UserDao userDao) {
this.userDao = userDao;
}
}
Setter注入:灵活性高,但依赖可能未完全初始化
class UserService {
private UserDao userDao;
// 通过setter方法注入依赖(非必需时可设为null)
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}
字段注入:代码简洁但隐藏依赖关系,不推荐生产代码
// 字段注入示例(以Spring框架为例)
class UserService {
@Autowired // Spring注解实现字段注入
private UserDao userDao; // 直接声明依赖字段
}
动态代理与静态代理的核心区别在于代理类的创建时机和灵活性:静态代理在编译期手动编写代理类,需与目标类实现相同接口或继承目标类,每个目标类对应独立代理类,扩展性较差;动态代理则在运行时通过反射(如 JDK 代理)或字节码生成技术(如 CGLIB)动态生成代理类,无需手动编写,可通过统一处理器处理多个目标类,适用于 AOP 等需要灵活增强的场景,相比静态代理更具扩展性与无侵入性。
循环依赖在spring中有三种情况:
第一种:通过构造方法进行依赖注入时产生的循环依赖问题。
第二种:通过setter方法进行依赖注入且是在多例(原型)模式下产生的循环依赖问题。
第三种:通过setter方法进行依赖注入且是在单例模式下产生的循环依赖问题
只有第三种被解决了,详细方案步骤如下:
以 A→B→A 循环为例的详细流程
步骤 1:创建 A(暴露工厂到二级缓存)
1. 实例化 A(半成品,未填充依赖)
2. 将 A 的 ObjectFactory 放入二级缓存:
singletonFactories.put("a", () -> getEarlyBeanReference("a", mbd, a));
3. 开始填充 A 的依赖(发现需要 B)
步骤 2:创建 B(触发对 A 的循环依赖)
4. 实例化 B(半成品)
5. 将 B 的 ObjectFactory 放入二级缓存
6. 开始填充 B 的依赖(发现需要 A)
7. 调用 getSingleton("a") 查找 A:
- 一级缓存无 A
- 三级缓存无 A(早期引用尚未生成)
- 二级缓存有 A 的 ObjectFactory → 调用工厂生成早期引用 earlyA
- 将 earlyA 放入三级缓存 earlySingletonObjects
- 从二级缓存移除 A 的 ObjectFactory
8. 将 earlyA 注入 B
9. 完成 B 的初始化,将 B 放入一级缓存
步骤 3:继续完成 A 的初始化
10. B 已在一级缓存,将 B 注入 A
11. 完成 A 的初始化
12. 将 A 从三级缓存移至一级缓存
注解 | 作用 | 示例场景 |
---|---|---|
@Component |
声明一个组件(Bean),自动被组件扫描发现 | 通用组件类 |
@Repository |
声明数据访问层组件(DAO),提供持久层异常转换 | 数据库访问类 |
@Service |
声明业务逻辑层组件(Service) | 业务处理类 |
@Controller |
声明 Web 控制器组件(MVC) | Spring MVC 控制器 |
@RestController |
@Controller + @ResponseBody 的组合,返回 JSON 数据 |
RESTful API 接口 |
@Configuration |
声明配置类,替代 XML 配置文件 | 替代 applicationContext.xml |
@Bean |
在配置类中声明一个 Bean,替代 XML 中的 标签 |
自定义 Bean 创建逻辑 |
@Autowired |
自动注入依赖(按类型匹配) | 字段、构造器、setter 方法 |
@Qualifier |
配合@Autowired ,按名称指定注入的 Bean |
解决多实现类的歧义 |
@Resource |
JSR-250 标准注解,按名称注入依赖(等价于@Autowired +@Qualifier ) |
替代@Autowired |
@Value |
注入外部配置属性(如application.properties 中的值) |
配置文件参数注入 |
@Scope |
指定 Bean 的作用域(如singleton 、prototype ) |
多例 Bean 配置 |
@Lazy |
延迟初始化 Bean(仅在首次使用时创建) | 资源消耗大的 Bean |
同一个类中方法内部调用:
场景:在类的内部使用this.
调用被@Transactional
注解的方法。
原因:Spring 事务基于 AOP 代理实现,必须通过代理对象调用方法才能触发事务拦截。若使用this.
直接调用(如this.method()
),会绕过代理对象,导致事务不生效。
@Service
public class UserService {
public void saveUser() {
this.saveUserWithTransaction(); // 内部调用绕过代理,事务失效
}
@Transactional
public void saveUserWithTransaction() {
// 数据库操作
}
}
事务在非公开方法中失效:
场景:@Transactional
注解应用在非public
修饰的方法上(如默认访问修饰符、private
)。
原因:Spring 框架的设计限制 —— 源码中会跳过非public
方法的事务拦截(TransactionAttributeSource
接口明确要求仅处理public
方法)。
@Service
public class OrderService {
@Transactional
void updateOrder() { // 非public方法,事务不生效
// 数据库操作
}
}
事务传播属性设置不当:
场景:@Transactional
的propagation
属性配置错误,导致方法脱离事务管理。
原因:不同传播属性决定了事务的行为,例如:
Propagation.NOT_SUPPORTED
:挂起当前事务,在非事务环境中执行;Propagation.NEVER
:禁止事务,若存在事务则抛出异常。@Service
public class AccountService {
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void transferMoney() {
// 即使调用方有事务,当前方法也会在非事务环境中执行
}
}
异常类型不匹配:
场景:未正确处理异常类型,导致事务无法回滚(需注意:此场景可能被误认为 “事务失效”,但实际事务已生效,只是未触发回滚)。
原因:
RuntimeException
或Error
类型的异常;Exception
),事务会正常提交。@Service
public class TransactionService {
@Transactional
public void process() {
try {
// 数据库操作
throw new Exception("自定义检查异常"); // 非RuntimeException,默认不回滚
} catch (Exception e) {
// 捕获异常且不抛出,事务正常提交
}
}
}
多数据源场景下事务管理器错误:
场景:在多数据源环境中,不同数据源的操作未被同一事务管理器管理。
原因:单数据源时事务管理器自动生效,但多数据源需手动指定transactionManager
。若未配置,跨数据源操作无法统一回滚(属于分布式事务问题)。
在 Spring 中使用this
调用事务方法时,事务会失效。这是因为 Spring 事务基于 AOP 代理实现,而this
引用指向的是目标对象本身,而非代理对象,导致 AOP 拦截器无法介入。
@Autowired
)。BeanNameAware.setBeanName()
:注入 Bean 名称。BeanFactoryAware.setBeanFactory()
:注入 BeanFactory。ApplicationContextAware.setApplicationContext()
:注入应用上下文。BeanPostProcessor.postProcessBeforeInitialization()
方法被调用(全局处理)。InitializingBean.afterPropertiesSet()
@PostConstruct
注解方法init-method
BeanPostProcessor.postProcessAfterInitialization()
方法被调用(全局处理)。DisposableBean.destroy()
@PreDestroy
注解方法destroy-method
初始化方法顺序
BeanPostProcessor.postProcessBeforeInitialization
(全局前置)→ @PostConstruct
→ InitializingBean
→ init-method
(优先级从高到低)→ BeanPostProcessor.postProcessAfterInitialization
(全局后置)。
销毁方法顺序
@PreDestroy
→ DisposableBean
→ destroy-method
(优先级从高到低)。
Spring 中的 Bean 默认都是单例的。每个Bean的实例只会被创建一次,并且会被存储在Spring容器的缓存中,以便在后续的请求中重复使用。这种单例模式可以提高应用程序的性能和内存效率。但是,Spring也支持将Bean设置为多例模式,即每次请求都会创建一个新的Bean实例。要将Bean设置为多例模式,可以在Bean定义中通过设置scope属性为"prototype"来实现。
生命周期阶段 | 单例(Singleton) | 原型(Prototype) |
---|---|---|
实例创建时机 | 容器启动时(默认)或第一次被请求时(懒加载模式)创建唯一实例。 | 每次被请求时(如getBean() 调用或注入时)创建新实例。 |
实例数量 | 整个容器中仅存在 1 个实例,所有引用指向同一对象。 | 每次请求对应 1 个新实例,多次请求生成多个独立对象。 |
属性注入与初始化 | 容器负责完成属性注入(如@Autowired )、BeanNameAware 等接口回调、@PostConstruct 初始化方法等,仅执行一次。 |
容器同样负责属性注入和初始化操作,但每次创建新实例时都会重新执行(每次实例独立处理)。 |
容器管理范围 | 从创建到销毁全程由容器管理,生命周期与容器绑定。 | 容器仅负责创建和初始化,后续生命周期(如销毁)不由容器管理,需用户自行处理。 |
销毁阶段 | 容器关闭时触发销毁逻辑(如DisposableBean 接口的destroy() 、@PreDestroy 方法)。 |
容器不触发销毁逻辑,即使实现DisposableBean 或配置destroy-method 也不会执行。 |
与容器的生命周期绑定 | 完全绑定:容器启动则创建,容器关闭则销毁。 | 不绑定:实例创建后与容器脱离关系,容器关闭不影响已创建的原型实例。 |
适用场景 | 无状态组件(如 Service、Repository),复用实例以减少资源消耗。 | 有状态组件(如保存请求上下文的对象),避免多线程共享状态导致的安全问题。 |
作用域 | 生命周期管理 | 实例数量 | 线程安全性 | 典型应用场景 |
---|---|---|---|---|
Singleton | 容器管理(创建与销毁) | 每个容器 1 个实例 | 需手动处理共享状态 | 无状态服务、工具类 |
Prototype | 用户管理(仅创建) | 每次请求 1 个新实例 | 天然安全(不共享) | 有状态组件、非线程安全对象 |
Request | HTTP 请求生命周期 | 每个请求 1 个实例 | 单线程环境 | 请求参数处理器、请求级缓存 |
Session | HTTP 会话生命周期 | 每个会话 1 个实例 | 会话内单线程 | 购物车、用户会话状态 |
Application | ServletContext 生命周期 | 每个应用 1 个实例 | 需线程安全 | 全局配置、应用级统计 |
WebSocket | WebSocket 会话生命周期 | 每个 WebSocket 会话 1 个实例 | 会话内单线程 | WebSocket 消息处理器 |
BeanPostProcessor
(全局拦截),实现BeanPostProcessor
接口,重写postProcessBeforeInitialization
(初始化前)和postProcessAfterInitialization
(初始化后)PropertySourcesPlaceholderConfigurer
。SqlSessionFactoryBean
即采用此模式,适合封装第三方组件。web.xml
配置,实现细粒度的 MVC 定制。@ControllerAdvice
定义全局处理器,结合@ExceptionHandler
统一处理 Controller 层抛出的异常,返回规范化的错误响应。@Bean
方法自定义 Bean 的创建和初始化过程,支持依赖注入和条件加载。ImportSelector
可基于条件返回需导入的类名数组,常用于自动配置。分层 | 核心职责 | 具体内容 | 特点 |
---|---|---|---|
Model(模型) | 管理应用数据和业务逻辑,是数据处理和业务决策的核心 | - 数据:实体类(如 User、Order)、临时计算数据(如统计结果) - 业务逻辑:数据验证(如手机号格式校验)、业务规则(如订单金额计算)、数据持久化(如数据库 CRUD) | 与 View、Controller 完全解耦,独立于界面和交互逻辑,稳定性高 |
View(视图) | 展示数据并与用户交互,是用户直接感知的界面 | - 数据展示:将 Model 传递的数据可视化(如网页表格、APP 列表) - 用户输入:接收用户操作(如表单提交、按钮点击)并传递给 Controller | 只关注 “如何展示”,不处理业务逻辑,可灵活替换(如从网页改为小程序界面) |
Controller(控制器) | 作为 Model 与 View 的桥梁,接收请求、协调业务处理并返回结果 | - 接收请求:获取 View 传递的用户输入(如表单参数、URL 参数) - 调度逻辑:调用 Model 层处理业务(如调用 Service 方法) - 响应处理:将 Model 处理结果传递给 View,决定展示哪个界面 | 不处理业务逻辑,仅负责 “调度”,降低 View 与 Model 的直接耦合 |
三层通过交互流程协作:用户操作 View → Controller 接收请求 → 调用 Model 处理业务 → Model 返回结果 → Controller 选择 View 展示结果。
对比维度 | HandlerMapping(处理器映射器) | HandlerAdapter(处理器适配器) |
---|---|---|
核心功能 | 根据请求信息(URL、HTTP 方法、请求头等),找到处理请求的Handler(如@Controller 中的方法、接口实现类等),并封装拦截器链。 |
根据 Handler 的类型,适配并执行 Handler,处理参数绑定、数据转换、返回值处理等细节,统一调用逻辑。 |
处理阶段 | 位于请求处理的早期阶段,在DispatcherServlet 接收请求后首先被调用。 |
位于HandlerMapping 之后,在确定 Handler 后执行,负责调用 Handler 并返回结果。 |
输入信息 | HTTP 请求对象(HttpServletRequest ),包含 URL、参数、请求方法等。 |
Handler 对象(如具体方法或接口实现类)、HTTP 请求 / 响应对象。 |
输出结果 | HandlerExecutionChain (包含匹配的 Handler 和拦截器链)。 |
ModelAndView (视图与模型数据)或直接写入响应体(如@ResponseBody 标注的返回值)。 |
关键作用 | 解决 “找谁处理请求” 的问题,实现请求到处理逻辑的映射。 | 解决 “如何处理请求” 的问题,屏蔽不同 Handler 类型的调用差异,统一执行流程。 |
常见实现类 | RequestMappingHandlerMapping (处理注解式 Handler,如@RequestMapping 方法)、BeanNameUrlHandlerMapping (根据 Bean 名映射 URL)。 |
RequestMappingHandlerAdapter (适配注解式 Handler)、SimpleControllerHandlerAdapter (适配Controller 接口实现类)。 |
设计意图 | 通过灵活的映射规则(如注解、配置),支持多样化的请求路由需求。 | 通过适配器模式,兼容不同类型的 Handler(注解式、接口式等),让DispatcherServlet 无需关心具体调用方式。 |
示例场景 | 当请求GET /users/1 时,找到UserController 中@GetMapping("/users/{id}") 标注的getUser 方法。 |
调用getUser 方法时,自动将 URL 中的id=1 转换为Long 类型参数,执行方法后将返回的视图名封装为ModelAndView 。 |
java -jar
一键启动,无需额外配置服务器。spring-boot-starter-web
),自动管理依赖版本,避免版本兼容问题。它通过预设合理默认值和标准化项目结构,让开发者用最少的配置快速启动项目,同时保留灵活扩展的能力。
**自动化配置:**Spring Boot 提供了大量的自动化配置,通过分析项目的依赖和环境,自动配置应用程序的行为。开发者无需显式地配置每个细节,大部分常用的配置都已经预设好了。例如,引入spring-boot-starter-web后,Spring Boot会自动配置内嵌Tomcat和Spring MVC,无需手动编写XML。
**默认配置:**Spring Boot 为诸多方面提供大量默认配置,如连接数据库、设置 Web 服务器、处理日志等。开发人员无需手动配置这些常见内容,框架已做好决策。例如,默认的日志配置可让应用程序快速输出日志信息,无需开发者额外繁琐配置日志级别、输出格式与位置等。
**约定的项目结构:**Spring Boot 提倡特定项目结构,通常主应用程序类(含 main 方法)置于根包,控制器类、服务类、数据访问类等分别放在相应子包,如com.example.demo.controller放控制器类,com.example.demo.service放服务类等。此约定使团队成员更易理解项目结构与组织,新成员加入项目时能快速定位各功能代码位置,提升协作效率。
SpringBoot自动装配是基于约定大于配置的理念,通过@SpringBootApplication
注解中的@EnableAutoConfiguration
触发,扫描META-INF/spring.factories
中定义的自动配置类,利用条件注解(如@ConditionalOnClass
)判断是否满足配置条件,自动向Spring容器注册如数据源、MVC组件等Bean,同时允许用户通过自定义配置覆盖默认配置,从而显著减少Spring应用的样板代码,提升开发效率。
对比项 | 过滤器(Filter) | 拦截器(Interceptor) |
---|---|---|
规范 / 框架 | Servlet 规范(容器层) | Spring MVC 框架(应用层) |
执行时机 | 在 Servlet 之前 / 之后 | 在 Controller 之前 / 之后、视图渲染前后 |
依赖注入 | 不支持(Filter 由 Servlet 容器管理) | 支持(Interceptor 由 Spring 容器管理) |
拦截范围 | 所有请求(如静态资源、Servlet 请求) | 仅拦截 Spring MVC 处理的请求(不包括静态资源) |
性能 | 更高(直接由 Servlet 容器调用) | 略低(需要经过 Spring MVC 的 DispatchServlet) |
使用场景 | 全局请求处理(如编码、日志、跨域) | 业务相关拦截(如登录校验、权限控制) |
过滤器(Filter)是 Servlet 规范中的组件,由 Servlet 容器管理,可拦截所有类型请求(包括静态资源、HTTP 请求等),在请求进入 Servlet 前或响应返回客户端前执行,支持全局处理(如编码设置、跨域处理),需通过 FilterRegistrationBean 或 @WebFilter 注册,不支持依赖注入,适用于容器级别的通用请求处理
拦截器(Interceptor)是 Spring MVC 框架的组件,由 Spring 容器管理,仅拦截 Spring MVC 处理的请求(不包括静态资源),在 Controller 调用前后、视图渲染前后执行,支持依赖注入(如注入 Service),通过 WebMvcConfigurer 注册,可针对特定 URL 进行细粒度控制(如登录校验、请求耗时统计),适用于业务相关的拦截逻辑。
Mybatis 在处理 #{} 时,会创建预编译的 SQL 语句,将 SQL 中的 #{} 替换为 ? 号,在执行 SQL 时会为预编译 SQL 中的占位符(?)赋值,调用 PreparedStatement 的 set 方法来赋值,预编译的 SQL 语句执行效率高,并且可以防止SQL 注入,提供更高的安全性,适合传递参数值。
Mybatis 在处理 ${} 时,只是创建普通的 SQL 语句,然后在执行 SQL 语句时 MyBatis 将参数直接拼入到 SQL 里,不能防止 SQL 注入,因为参数直接拼接到 SQL 语句中,如果参数未经过验证、过滤,可能会导致安全问题。
CRUD操作:MybatisPlus通过继承BaseMapper接口,提供了一系列内置的快捷方法,使得CRUD操作更加简单,无需编写重复的SQL语句。
**代码生成器:**MybatisPlus提供了代码生成器功能,可以根据数据库表结构自动生成实体类、Mapper接口以及XML映射文件,减少了手动编写的工作量。
**通用方法封装:**MybatisPlus封装了许多常用的方法,如条件构造器、排序、分页查询等,简化了开发过程,提高了开发效率。
分页插件:MybatisPlus内置了分页插件,支持各种数据库的分页查询,开发者可以轻松实现分页功能,而在传统的MyBatis中,需要开发者自己手动实现分页逻辑
服务熔断(Circuit Breaker)是分布式系统中的一种容错机制,用于防止级联故障和雪崩效应。当依赖的服务出现问题(如响应超时、频繁错误)时,熔断机制会暂时切断对该服务的调用,直接返回降级结果,避免资源浪费和故障扩散。
服务降级是分布式系统应对压力和故障的 “主动防御机制”,通过牺牲局部非核心功能,保障整体系统的稳定性和核心业务的可用性。它与服务熔断相辅相成(熔断常触发降级),共同构成微服务架构中的容错体系,是高可用系统设计的重要组成部分。
1. 轮询算法
2. 加权轮询算法
3. 随机算法
4. 加权随机算法
5. 最少连接数算法
6. 加权最少连接数算法
7.IP哈希算法
8. URL 哈希算法
9. 最小响应时间算法
10.一致性哈希算法
基于用户标识的哈希映射(结合一致性哈希优化):首先为每个用户分配唯一标识(如用户 ID、登录 Token、IP 地址等),对该标识进行哈希计算后,通过一致性哈希算法映射到服务器集群。一致性哈希会将服务器节点分布在哈希环上,用户请求的哈希值会顺时针匹配最近的服务器。