Spring相关总结
1.IOC和AOP
1.IOC(控制反转)
定义:将bean对象的创建、初始化、销毁全部交给spring容器来进行管理,而不是开发者。具体的实现方法是DI(依赖注入
)
(1)依赖注入:依赖注入(Dependency Injection,DI)是一种设计模式,它通过将对象之间的依赖关系的创建和维护转移到外部容器中来,以减少对象之间的紧耦合性并提高可重用性。
(2)注入方法:1.注解注入;2.构造器注入;3.setter方式注入
优势
松耦合:对象之间的依赖关系由容器管理,减少了对象之间的直接依赖。
可测试性:依赖注入使得对象更容易进行单元测试,因为依赖可以通过注入的方式替换为模拟对象。
可维护性:通过配置文件或注解管理依赖关系,修改依赖关系时无需改变代码。
2.AOP(面向切面编程)
定义
AOP(面向切面编程)是一种编程范式,它通过将横切关注点(Cross-Cutting Concerns)从业务逻辑中分离出来,提高了代码的模块化和可维护性。横切关注点包括日志记录、事务管理、安全检查等。
业务使用
日志记录 用途:在方法执行前后记录日志信息,方便调试和跟踪系统运行情况。
事务管理 用途:确保方法在事务范围内执行,保证数据的一致性和完整性。
安全检查 用途:在方法执行前进行权限验证,确保只有授权用户才能执行特定操作。
缓存管理 用途:在方法执行前后处理缓存逻辑,避免重复查询数据,提高系统性能。
性能监控 用途:在方法执行前后记录方法的执行时间,用于性能分析和优化。
异常处理 用途:在方法执行时捕获和处理异常,统一异常处理逻辑,减少重复代码。
基本概念
Joinpoint(连接点)
被拦截到的每个点,spring中指被拦截到的每一个方法,spring aop一个连接点即代表一个方法的执行。
Pointcut(切入点)
对连接点进行拦截的定义(匹配规则定义规定拦截哪些方法,对哪些方法进行处理),spring 有专⻔的表达式语言定义。
Advice(通知)
拦截到每一个连接点即(每一个方法)后所要做的操作
前置通知(前置增强)— before() 执行方法前通知
返回通知(返回增强)— afterReturn 方法正常结束返回后的通知
异常抛出通知(异常抛出增强)— afetrThrow()
最终通知 — after 无论方法是否发生异常,均会执行该通知。
环绕通知 — around 包围一个连接点(join point)的通知,如方法调用。这是最强大的一种通知类型。环绕通知可以在方法调用前后完成自定义的行为。它也会选择是否继续执行连接点或直接返回它们自己的返回值或抛出异常来结束执行。
Aspect(切面)
切入点与通知的结合,决定了切面的定义,切入点定义了要拦截哪些类的哪些方法,通知则定义了拦截过方法后要做什么,切面则是横切关注点的抽象,与类相似,类是对物体特征的抽象,切面则是横切关注点抽象。
Target(目标对象)
被代理的目标对象
Weave(织入)
将切面应用到目标对象并生成代理对象的这个过程即为织入
Introduction(引入)
在不修改原有应用程序代码的情况下,在程序运行期为类动态添加方法或者字段的过程称为引入
在 Spring 框架中,事务管理可以通过全局事务管理(使用 AOP)和事务注解(
@Transactional
)来实现。以下是两者的优缺点对比,帮助你在实际开发中做出选择。AOP全局管理事物和注解开启事物
全局事务管理(AOP)
通过 AOP(面向切面编程)来管理事务,通常需要定义一个切面类来拦截方法调用,管理事务的开启、提交和回滚。
示例代码
@Aspect @Component public class TransactionAspect { @Autowired private PlatformTransactionManager transactionManager; @Around("execution(* com.example.service.*.*(..))") public Object manageTransaction(ProceedingJoinPoint joinPoint) throws Throwable { TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition()); try { Object result = joinPoint.proceed(); transactionManager.commit(status); return result; } catch (Throwable ex) { transactionManager.rollback(status); throw ex; } } }优点
灵活性和控制:可以在切面中灵活地定义事务的控制逻辑,例如嵌套事务、事务隔离级别、传播行为等。
集中管理:事务逻辑集中在切面中,方便维护和修改,减少代码重复。
动态应用:能够在运行时动态地控制事务的应用,例如根据条件决定是否开启事务。
缺点
配置复杂:需要编写切面类和事务管理器配置,增加了配置和代码的复杂度。
性能开销:AOP 的动态代理可能带来一定的性能开销,特别是在高并发场景下。
事务注解(
@Transactional
)通过在方法或类上使用
@Transactional
注解来声明事务,Spring 容器会在方法执行时自动管理事务。示例代码
@Service public class UserService { @Autowired private UserRepository userRepository; @Transactional public void createUser(User user) { userRepository.save(user); // 其他业务逻辑 } }优点
简单易用:只需在方法或类上添加
@Transactional
注解,代码简单清晰,易于理解和使用。集成方便:Spring Boot 和 Spring 框架对
@Transactional
注解的支持非常好,自动配置和管理事务,开发者无需关注事务的底层实现。减少代码:避免了编写切面类和切点表达式,减少了样板代码。
缺点
功能限制:对于复杂的事务逻辑(如嵌套事务、不同数据源的事务管理等),
@Transactional
注解的功能可能不足,需要依赖 AOP 或其他方式来实现。局部化管理:事务逻辑分散在不同的类和方法上,难以统一管理和维护。
总结
选择全局事务管理(AOP):
当需要高度灵活的事务控制和复杂事务逻辑时,如嵌套事务、动态事务管理等。
当需要将事务管理逻辑集中在一个切面中,方便统一维护和修改时。
选择事务注解(
@Transactional
):
当事务逻辑简单,主要是对常规的事务管理需求时。
当开发效率和代码简洁性更重要,且不需要复杂事务控制时。
在实际开发中,很多项目会结合使用这两种方式,根据具体的业务需求和复杂程度来选择合适的事务管理方案。对于大多数简单和中等复杂度的业务场景,使用
@Transactional
注解是更为快捷和方便的选择;对于需要高度定制化和复杂事务逻辑的场景,使用 AOP 进行全局事务管理更为合适。底层原理:
Spring的AOP实现原理其实很简单,就是通过动态代理实现的。
Spring AOP 采用了两种混合的实现方式:JDK 动态代理和 CGLib 动态代理。
JDK动态代理:Spring AOP的首选方法。 每当目标对象实现一个接口时,就会使用JDK动态代理。目标对象必须实现接口
CGLIB代理:如果目标对象没有实现接口,则可以使用CGLIB代理。
优势
模块化:将横切关注点从业务逻辑中分离出来,模块化管理。
可复用性:横切关注点可以在多个地方重用,无需重复代码。
可维护性:集中管理横切关注点的代码,修改时无需遍历所有业务逻辑。
2.SpringMVC
什么是SpringMVC
Spring MVC(Model-View-Controller)是 Spring 框架的一部分,用于构建基于 Web 的应用程序。它遵循经典的 MVC 模式,将业务逻辑、数据处理和视图展现分离开来,从而实现模块化和高内聚低耦合的设计。
组成部分
DispatcherServlet(前端控制器):是SpringMVC的核心部分,是一种前端控制器,由框架所提供
作用:统一处理请求和响应。除此之外也是整个控制流程的中心,由DispatcherServlet来调用其他组件,对用户的请求进行处理
HandlerMapping:处理器映射器,由框架所提供。
作用:根据请求的url、method等信息来查找具体的Handler(通俗讲——通常来说就是Controller)
Handler(通常就是Controller) :处理器,注意——这个就是软件开发人员自己开发设计的部分
作用:在DispatcherServlet的控制下,Handler对用户的请求进行处理
HandlerAdapter :处理器适配器,由框架所提供
作用:根据HandlerMapping所提供的Handler信息,会按照特定的规则去执行相关的处理器Handler
小结
Handler——是用来干活的工具
HandlerMapping——是根据需要干的活找到对应的工具
HandlerAdapter——是具体用工具干活的那个人
ViewResolver:视图解析器——由框架提供
作用:ViewResolver负责将处理结果生成View视图。ViewResolver首先会根据逻辑视图名解析成物理图名,即具体的页面地址,再生成View视图对象,最后将View进行渲染之后将页面呈现给用户
View :视图——软件开发人员自己设计
作用:View接口的职责就是接收model对象、Request对象、Response对象,最后渲染输出结果返回给Response对象
工作流程
1、用户将请求发送,由前端控制器DispatcherServlet来拦截并接收请求
2、前端控制器DispatcherServlet收到请求之后调用处理器映射器(HanlderMapping),去查找与请求对应的Handler
3、处理器映射器(HanlderMapping)找到具体的处理器(根据xml配置、注解等方式进行查找),返回一个处理器执行链(是一个包含处理器对象和拦截器(Interceptor)的对象【如果有拦截器的话】)
4、然后前端控制器DispatcherServlet调用了处理器适配器HandlerAdapter
5、处理器适配器会找到具体Handler的具体方法,并将获取到的参数执行完成之后将结果继续返回给DispatcherServlet(结果通常是ModelAndView)
6、然后前端控制器(DispatcherServlet)会调用视图解析器,并将ModelAndView传给它(ViewResolver)
7、视图解析器(ViewResolver)将获得的参数从逻辑视图转换为物理视图对象(View)返回给前端控制器(DispatcherServlet)
8、前端控制器(DispatcherServlet)调用物理视图进行渲染并返回。
9、前端控制器(DispatcherServlet)将渲染完毕的页面响应给用户
流程图
Spring MVC 与数据库交互的工作流程
用户请求:用户在浏览器中发起 HTTP 请求。
DispatcherServlet 接收请求:Spring MVC 的前端控制器 DispatcherServlet 接收请求并将其分发给相应的处理器(Controller)。
Controller 处理请求:Controller 处理请求,调用 Service 层进行业务逻辑处理。
Service 调用 Repository:Service 层调用 Repository 层(通常使用 Spring Data JPA 或 JDBC)与数据库进行交互。
数据库操作:Repository 层执行数据库操作(如查询、插入、更新、删除)并返回结果。
Service 返回结果:Service 层接收 Repository 层返回的结果并进行业务处理。
Controller 返回视图:Controller 将处理后的数据放入 Model,并返回视图名。
View 渲染:视图解析器将逻辑视图名解析为实际视图,视图渲染数据并生成 HTML 响应。
响应返回客户端:生成的 HTML 响应通过 DispatcherServlet 返回给客户端浏览器。
3.Spring Security
定义
Spring Security 是一个强大的、可定制的身份认证和访问控制框架,广泛用于保护基于 Spring 的应用程序。它提供了多种功能,包括但不限于认证、授权、防止攻击(如会话固定、点击劫持、跨站请求伪造等),以及与其他安全服务的集成。
核心概念
-
认证(Authentication):验证用户身份。
-
授权(Authorization):基于用户身份控制访问权限。
-
过滤器链(Filter Chain):一系列过滤器,用于处理安全相关的请求。
-
安全上下文(Security Context):存储当前用户的安全信息。
核心功能
-
身份验证(Authentication):
-
验证用户身份的过程。
-
提供多种认证方式,如表单登录、HTTP Basic 认证、LDAP、OAuth2 等。
-
-
授权(Authorization):
-
决定已认证的用户是否有权限访问特定资源。
-
提供基于角色和权限的访问控制。
-
-
攻击防护:
-
提供防止常见攻击的方法,如会话固定、点击劫持(Clickjacking)、跨站请求伪造(CSRF)等。
-
-
集成其他安全服务:
-
与 OAuth2、JWT、LDAP 等安全框架和服务集成,提供更强大的认证和授权功能。
-
-
安全事件处理:
-
提供安全事件的处理机制,如认证失败、访问拒绝等。
-
核心组件
-
SecurityContext:
-
存储当前用户的认证信息,在整个请求过程中保持。
-
-
AuthenticationManager:
-
负责进行用户认证的核心接口,通常通过
ProviderManager
实现。
-
-
UserDetailsService:
-
用于获取用户信息的接口,通常与数据库或其他用户存储系统集成。
-
-
GrantedAuthority:
-
代表用户的权限,通常与角色和权限相关联。
-
-
Filter Chain:
-
一组过滤器,处理所有进入应用程序的请求,通过这些过滤器实现安全控制。
-
5.Spring 数据库连接池
使用连接池的好处
①资源重用
避免了频繁创建、释放连接引起的大量性能开销。在减少系统消耗的基础上,另一方面也增进了系统运行环境的平稳性(减少内存碎片以及数据库临时进程/线程的数量)。
②更快的系统响应速度
在初始化过程中,就已经创建好若干数据库连接。此时连接的初始化工作均已完成。对于业务请求处理而言,直接利用现有可用连接,避免了数据库连接初始化和释放过程的时间开销,从而缩减了系统整体响应时间。
③新的资源分配手段
对于多应用共享同一数据库的系统而言,可在应用层通过数据库连接的配置,实现数据库连接池技术,几年钱也许还是个新鲜话题,对于目前的业务系统而言,如果设计中还没有考虑到连接池的应用,那么…….快在设计文档中加上这部分的内容吧。某一应用最大可用数据库连接数的限制,避免某一应用独占所有数据库资源。
④ 统一的连接管理,避免数据库连接泄漏
在较为完备的数据库连接池实现中,可根据预先的连接占用超时设定,强制收回被占用连接。从而避免了常规数据库连接操作中可能出现的资源泄漏。
2. 常见连接池
现在市面上的连接池有很多种,此处我也只列举几种使用较多的:
①C3P0
开源的JDBC连接池,实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。目前使用它的开源项目有Hibernate、Spring等。单线程,性能较差,适用于小型系统,代码600KB左右。
②DBCP
全称(Database Connection Pool),由Apache开发的一个Java数据库连接池项目, Jakarta commons-pool对象池机制,Tomcat使用的连接池组件就是DBCP。单独使用dbcp需要3个包:common-dbcp.jar,common-pool.jar,common-collections.jar,预先将数据库连接放在内存中,应用程序需要建立数据库连接时直接到连接池中申请一个就行,用完再放回。单线程,并发量低,性能不好,适用于小型系统。
③Tomcat Jdbc Pool
Tomcat在7.0以前都是使用common-dbcp做为连接池组件,但是dbcp是单线程,为保证线程安全会锁整个连接池,性能较差,dbcp有超过60个类,也相对复杂。Tomcat从7.0开始引入了新增连接池模块叫做Tomcat jdbc pool,基于Tomcat JULI,使用Tomcat日志框架,完全兼容dbcp,通过异步方式获取连接,支持高并发应用环境,超级简单核心文件只有8个,支持JMX,支持XA Connection。
④BoneCP
官方说法BoneCP是一个高效、免费、开源的Java数据库连接池实现库。设计初衷就是为了提高数据库连接池性能,根据某些测试数据显示,BoneCP的速度是最快的,要比当时第二快速的连接池快25倍左右,完美集成到一些持久化产品如Hibernate和DataNucleus中。BoneCP特色:高度可扩展,快速;连接状态切换的回调机制;允许直接访问连接;自动化重置能力;JMX支持;懒加载能力;支持XML和属性文件配置方式;较好的Java代码组织,100%单元测试分支代码覆盖率;代码40KB左右。
⑤Druid(德鲁伊)–推荐使用
Druid是Java语言中最好的数据库连接池,Druid能够提供强大的监控和扩展功能,是一个可用于大数据实时查询和分析的高容错、高性能的开源分布式系统,尤其是当发生代码部署、机器故障以及其他产品系统遇到宕机等情况时,Druid仍能够保持100%正常运行。主要特色:为分析监控设计;快速的交互式查询;高可用;可扩展;Druid是一个开源项目,源码托管在github上。
⑥Hikari
HiKariCP是数据库连接池的一个后起之秀,号称性能最好,可以完美地PK掉其他连接池,是一个高性能的JDBC连接池,基于BoneCP做了不少的改进和优化。并且 在springboot2.0之后,采用的默认数据库连接池就是Hikari。