0%

Spring系列之核心Feature

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
2
3
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.
This annotation is semantically equivalent to the <bean> element's primary attribute in Spring XML.
May be used on any class directly or indirectly annotated with @Component or on methods annotated with @Bean.

比如接口有多个候选依赖,指定一个具体的依赖实现用于自动注入。

@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
2
3
4
corePoolSize: 线程池维护线程的最少数量 
keepAliveSeconds 线程池维护线程所允许的空闲时间(TimeUnit unit: 时间单位,现有纳秒,微秒,毫秒,秒枚举值. )
maxPoolSize 线程池维护线程的最大数量
queueCapacity 线程池所使用的缓冲队列

当一个任务通过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。
image

ResourceLoader和ResourceLoaderAware

参考文章

为什么Spring5注入推荐用final去声明?

浅谈spring为什么推荐使用构造器注入

总结来说有这几个优点

  1. 保证依赖不可变(final关键字)
  2. 保证依赖不为空(省去了我们对其检查)
  3. 保证返回客户端(调用)的代码的时候是完全初始化的状态
  4. 避免了循环依赖
  5. 提升了代码的可复用性
    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

开启ajc编译的事务问题