TodoItem
深入理解IOC和DI之间的关系
Basic Knowledge
Service层的代码相互调用,可能会导致依赖死循环
可以在二个需要相互依赖的Service之间抽出一层OperateService,通过OperateService解耦。
@Transactional引发的思考
加入有这样的场景:
AService.doA()方法调用到BService.doB()方法,而且二者都是注解了事务,抛出异常时会回滚。
1 | @Transactional(rollbackFor = Exception.class) |
加入在doA()中调用了doB()之后才出现的异常,这个时候doB()的事务会不会回滚?
根据我自己的测试,doB()中正常执行完毕,这个时候事务依然还不会被提交,而doA()在doB()执行完了之后如果抛出异常,那么doA()和doB都会回滚。
那么问题来了,如果有这样的业务场景,需要在doB执行之后必须提交事务,即使在其执行之后doA()后面的逻辑抛出异常,doB的事务也要提交到数据库的时候,要怎么处理?
可以通过@Trancational注解去处理,注解在doB上:
1 | @Transactional(rollbackFor = Exception.class, noRollbackFor = ServiceDoAException.class) |
@Transactional什么时候加,什么时候由Spring自动加
@Primary
1 | Indicates that a bean should be given preference when multiple candidates are qualified to autowire a single-valued dependency. If exactly one 'primary' bean exists among the candidates, it will be the autowired value. |
比如接口有多个候选依赖,指定一个具体的依赖实现用于自动注入。
@Order
自定义不指定其顺序的优先权值小一些,很多时候配置可能没有覆盖掉Spring默认的配置类。
@ControllerAdvice vs @RestControllerAdvice
@ControllerAdvice can be used even for REST web services as well, but you need to additionally use @ResponseBody.
Spring封装好的便捷线程池ThreadPoolTaskExecutor
https://www.cnblogs.com/achengmu/p/8137276.html
https://blog.csdn.net/lipc_/article/details/52786377
1 | corePoolSize: 线程池维护线程的最少数量 |
当一个任务通过execute(Runnable)方法欲添加到线程池时,线程池的处理逻辑如下:
- 如果此时线程池中的数量小于corePoolSize,即使线程池中的线程都处于空闲状态,也要创建新的线程来处理被添加的任务。
- 如果此时线程池中的数量等于corePoolSize,但是缓冲队列workQueue未满,那么任务被放入缓冲队列。
- 如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,并且线程池中的数量小于maximumPoolSize,建新的线程来处理被添加的任务。
- 如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,并且线程池中的数量等于maximumPoolSize,那么通过 handler所指定的策略来处理此任务。也就是:处理任务的优先级为:核心线程corePoolSize、任务队列workQueue、最大线程 maximumPoolSize,如果三者都满了,使用handler处理被拒绝的任务。
线程池自我维护的功能: - 当线程池中的线程数量大于corePoolSize时,如果某线程空闲时间超过keepAliveTime,线程将被终止。这样,线程池可以动态的调整池中的线程数。
RejectedExecutionHandler
RejectedExecutionHandler handler: 用来拒绝一个任务的执行,有两种情况会触发拒绝处理器:
- 在execute方法中若addIfUnderMaximumPoolSize(command)为false,即线程池已经饱和。
- 在execute方法中, 发现runState!=RUNNING || poolSize == 0,即已经shutdown,就调用ensureQueuedTaskHandled(Runnable command),在该方法中有可能调用reject。
@Async注解其背后的原理
Spring默认的线程执行器defaultExecutor为什么要用SingletonSupplier封装起来?
ConcurrentHashMap
Spring线程池debug跟到最底层如下,用到的也是Java的ExecutorService。
ResourceLoader和ResourceLoaderAware
为什么Spring5注入推荐用final去声明?
总结来说有这几个优点
- 保证依赖不可变(final关键字)
- 保证依赖不为空(省去了我们对其检查)
- 保证返回客户端(调用)的代码的时候是完全初始化的状态
- 避免了循环依赖
- 提升了代码的可复用性
Setter injection versus constructor injection and the use of @Required
Spring中propagation的7种事务配置
REQUIRED:支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。
MANDATORY:支持当前事务,如果当前没有事务,就抛出异常。
REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起。
1
标志REQUIRES_NEW会新开启事务,外层事务不会影响内部事务的提交/回滚
- NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
- NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
- NESTED:支持当前事务,如果当前事务存在,则执行一个嵌套事务,如果当前没有事务,就新建一个事务。
————————————————
版权声明:本文为CSDN博主「sayok_why」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/sayoko06/article/details/79164858
org.springframework.core.io.Resource
Spring AOP vs Aspectj
https://www.baeldung.com/spring-aop-vs-aspectj
Implementing a Custom Spring AOP Annotation
Aspect Oriented Programming(AOP):面向切面编程。
- 连接点(JoinPoint) :程序执行的某个特定位置,如某个方法调用前,调用后,方法抛出异常后,这些代码中的特定点称为连接点。简单来说,就是在哪加入你的逻辑增强,连接点表示具体要拦截的方法,切点是定义一个范围,而连接点是具体到某个方法;
- 切点(PointCut):每个程序的连接点有多个,如何定位到某个感兴趣的连接点,就需要通过切点来定位,切点用于来限定Spring-AOP启动的范围,通常我们采用表达式的方式来设置范围;
- 增强(Advice) 增强是织入到目标类连接点上的一段程序代码;
- 前置通知(before):在执行业务代码前做些操作;
- 后置通知(after):在执行业务代码后做些操作,无论是否发生异常,它都会执行,比如关闭连接对象;
- 异常通知(afterThrowing):在执行业务代码后出现异常,需要做的操作,比如回滚事务;
- 返回通知(afterReturning):在执行业务代码后无异常,会执行的操作;
- 环绕通知(around):方法调用前后执行;
- 目标对象(Target):需要被加强的业务对象;
- 织入(Weaving):织入就是将增强添加到对目标类具体连接点上的过程,织入是一个形象的说法,具体来说,就是生成代理对象并将切面内容融入到业务流程的过程;
- 代理类(Proxy):一个类被AOP织入增强后,就产生了一个代理类;
- 切面(Aspect):切面由切点和增强组成,它既包括了横切逻辑的定义,也包括了连接点的定义,SpringAOP就是将切面所定义的横切逻辑织入到切面所制定的连接点中。
https://www.baeldung.com/spring-aop-annotation
Spring AOP系列文章
https://www.baeldung.com/spring-aop
Problem Solution
Connection will not be managed by Spring
原因是service 没有加@transactional 注解,未加注解的情况下,出现异常的时候spring将不会回滚事物
Null return value from advice does not match primitive return type for
如果是使用了Spring的异步处理注解@Async的方法,不要有返回,直接void