Yui Help

Spring

AOP

简述

  1. 概念:Aspect-Oriented Programming,一般称为面向切面编程。

  2. 目的:用于将那些与业务无关的,但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块,这个模块被称为切面(Aspect)

  3. 用途:权限认证、日志、事务处理等,作为面向对象的一种补充

  4. 好处:减少重复代码,提高系统可维护性,降低模块间的耦合度

  5. 原理:使用的是动态代理

动态代理

JDK动态代理

  1. 只提供接口代理,不支持类代理

  2. 运行时生成动态代理类 $proxy.class

  3. 代理类实现了目标类接口,并且实现接口类所有方法增强代码

  4. 调用时,通过代理类先去调用处理类进行增强,再通过反射方式调用目标类的方法,从而实现AOP

CGLIB动态代理

  1. 没有实现接口

  2. 通过ASM在运行时动态生成目标类的一个子类 ,(还有相关类,主要是为了增强调用时效率)会生成多个

  3. 会重写父类所有的方法增强代码

  4. 调用时,先代理类进行增强,再直接调用父类对应方法 ,从而实现AOP

    1. 类被标记为final,无法使用CGLIB做动态代理的

    2. 除了目标子类代理类,还有个FastClass(路由类),可以(但不是必须)让本类方法调用进行增强,不会像jdk代理

相关方法

  1. 是否是代理对象: AopUtils.isAopProxy(AopContext.currentProxy());

  2. 是否是cglib代理对象: AopUtils.isCglibProxy(AopContext.currentProxy())

  3. 是否是jdk代理对象: AopUtils.isJdkDynamicProxy(AopContext.currentProxy());

相关名词

  1. 切面 Aspect 切面类,管理切点和通知

  2. 连接点 Join Point 被增强的业务方法

  3. 通知 Advice 需要增加到业务方法中的公共代码和逻辑

  4. 切点 Pointcut 决定那些方法需要增强,那些不需要。结合切点表达式

  5. 目标对象 Target Object 增强的对象

  6. 织入 Weaving Aspectj独有的,Spring aop织入方式是动态代理。

    1. 编译器

    2. 类加载期

    3. 运行期

  7. 其他

    1. Advisor 顾问。是Pointcut和Advice的一个结合

AspectJ

Spring AOP使用

  1. Spring AOP 提供了AspectJ的支持,

  2. 但只用到了AspectJ的切点解析和匹配,及@Aspect、@Before等注解

  3. 在容器启动时需要生成代理实例,在方法的调用上也会增加栈的深度,使得Spring AOP 性能没有AspectJ那么好

AspectJ本身

SpringIOC

控制反转

  1. new实例类,耦合度太高,维护不方便

  2. 引入IOC,将创建对象控制权交给了Spring,控制了对象的创建权利,Spring IOC去创建

  3. 要使用对象:需要通过DI(依赖注入)@Autowired,从容器中自动注入

优点

实现机制

工厂模式

BeanFactory.getBean(String beanName)

反射

通过反射,实例化创建Bean对象 BeanFactory.getBean(String className)

Bean

作用域

作用域:Prototype/Singleton/Request/Session/Global Session

  • Prototype:原型模式,每次获取bean都会创建以一个新的实例,因此不存在线程安全的问题。

  • Singleton:不同的线程访问同一个bean,如果这个bean中含有实例变量,并且线程具有对实例变量的写操作时,就会产生线程安全问题

    • 解决:使用ThreadLocal ,为每个线程创建独立的变量副本,互相隔离互不影响

  • 只要Bean是无状态的则一定是线程安全的

加载方式

  1. 使用@Component注解 和@ComponentScan对其进行扫描

  2. 在配置类中(@Configuration ),使用@Bean注解,将方法返回值加载到容器中

  3. 类上声明@Import(User.class)

注解

Autowired

required属性

  • @Autowired(required = true)

    • 默认是true,表示注入的时候,该bean必须存在,否则会注入失败

  • @Autowired(required = false)

    • 忽略当前要注入bean,如果有直接注入,没有跳过,不会报错

  • 容器启动过程中,会初始化bean,spring核心之一(IOC)

  • 当前容器不能注入自己,这样就会不停的注入自己,陷入死循环,从而找不到要注入的bean

    • Spring框架提供的三级缓存来专门解决循环依赖

    • 构造函数注入会进入死循环

依赖注入方式

一、Field Injection
二、Construction Injection (推荐)
三、Setter Injection
对比

注入方式

可靠性

可维护性

可测试性

灵活性

循环关系检测

性能影响

Field Injection

不可靠

灵活

不检测

启动快

Constructor Injection

可靠

不灵活

自动检测

启动慢

Setter Injection

不可靠

灵活

不检测

启动快

Resource

和Autowire区别

Transactional

  • 回滚rollbackFor()。默认是RuntimeException

    • IOException不是RuntimeException子类,不会进行事务回滚

@Transactional(rollbackFor = IOException.class) public class Clazz { }

RequestParam & RequestBody

RequestParam

RequestBody

JavaConfig

注解的方式开发,代替xml

  1. @Configuration

  2. @Bean

  3. @ComponentScan

  4. @EnableWebMvc

  5. @ImportResource

  6. @PropertySource

依赖

spring-boot-starter-parent

  1. Java版本

    <properties> <java.version>1.8</java.version> </properties>
  2. 源码文件编码

    <properties> <project.build.sourceEncoding>GBK</project.build.sourceEncoding> </properties>
  3. 依赖管理

  4. 打包支持

  5. 动态识别资源

    <resource> <directory>src/main/resources</directory> <includes> <include>**/*.*</include> </includes> <filtering>true</filtering> </resource>
  6. 识别插件设置。如exec plugin,surefire,Git commit ID等

  7. 设别不同的配置。如application-dev.properties和 application-dev.yml

有些继承自其父级spring-boot-dependencies

事务

不生效

  1. Bean没有纳入Spring容器管理

    1. (不是动态代理的Bean),里面方法是没有事务管理的

  2. 自调用

    1. 调用当前类的方法,比如用this调用当前类的的方法

    2. 原因:this.methodA(),没有走TestService的代理类,所以事务会失效

    3. 解决

      1. methodA()和methodB()分别放到不同的类中

      2. 自己注入自己,用注入的实例调用

      3. 获取动态代理类,调用自己类的方法 且设置暴露当前代理对象到本地线程(@EnableAspectJAutoProxy(expostProxy=true))

        @Service public class TestService{ @Transactional public void methodA(){ } public void methodB() { ((TestService)AopContext.currentProxy()).methodA(); } }
  3. 异常没有抛出了,被try catch了

  4. 抛出的不是RuntimeException,而且没有指定rollbackFor=异常类型

  5. 事务方法不是public的,不会被动态代理

  6. 事务方法内启用新线程进行异步操作

  7. 数据库不支持事务

五种事务隔离级别

隔离级别

说明

DEFAULT

使用数据库默认的事务隔离级别

READ_COMMITTED

读已提交:防止脏读。但会出现不可重复读和幻读

READ_UNCOMMITTED

读未提交:最低隔离级别事务。会产生脏读、不可重复读和幻读

REPEATABLE_READ

可重复读:可以防止脏读、不可重复读。但会幻读

SERIALIZABLE

串行化:最高隔离级别最可靠

七种事务传播行为

传播行为

说明

REQUIRED

若存在事务,则支持当前事务,否则开启一个新的事务

SUPPORTS

MANDATORY

REQUIRES_NEW

总是新开,挂起当前事务

NOT_SUPPORTED

NEVER

NESTED

Other

SpringBoot属性加载顺序

  1. 命令行参数,ex: java -jar -Dspring.profile.active

  2. 操作系统环境变量

  3. application.properties或application.yml

  4. @Configuration注解的类,@PropertySource注解的属性

Last modified: 28 十一月 2023