日常梳理-Spring

文章目录

1.Spring

1.1 Spring bean的加载流程

Spring bean 的加载流程主要描述了 Spring 容器如何从配置元数据中解析并创建 bean 的过程。

  1. 配置元数据解析:

    • Spring 容器启动时,首先解析配置元数据。配置元数据可以是 XML 文件、注解或 Java 配置类。
    • 例如,解析 XML 文件中的 标签,或注解类上的 @Component、@Service 等注解。
  2. 组件扫描(Component Scanning):

    • Spring 容器会根据配置的扫描路径,查找带有 @Component、@Service、@Controller、@Repository 等注解的类,并将这些类注册为 bean。
    • 例如,@ComponentScan(“com.example”) 会扫描 com.example 包下的所有类。
  3. 实例化(Instantiation):

    • Spring 容器使用类加载器加载指定的类,并通过反射创建该类的实例。
    • 例如,调用类的构造函数创建实例。
  4. 属性赋值(Populate):

    • Spring 容器调用 set 方法或使用字段注入,将依赖注入到新创建的实例中。
    • 例如,使用 @Autowired 注解标注 set 方法或字段。
  5. 初始化(Initialization):

    • Spring 容器调用初始化方法,执行一些初始化操作。可以通过 @PostConstruct 注解或 init-method 属性来指定初始化方法。
    • 例如,@PostConstruct 注解的方法在实例化和属性赋值后被调用。

1.2 Spring中bean的生命周期

在不同的容器中,Bean的生命周期开始的时间不同。
对于ApplicationContext来说,当容器启动的时候,bean就已经实例化了。
而对于BeanFactory来说,直到调用getBean()方法的时候才进行实例化。

实例化 Instantiation -> 属性赋值 Populate -> 初始化 Initialization -> 销毁 Destruction

  1. 实例化(Instantiation):
    Spring 容器通过反射调用类的构造函数创建实例。
  2. 属性赋值(Populate):
    Spring 容器通过 set 方法或字段注入将依赖注入到实例中。
  3. 初始化(Initialization):
    Spring 容器调用初始化方法,执行一些初始化操作。可以通过 @PostConstruct 注解或 init-method 属性来指定初始化方法。
  4. 使用(Usage):
    bean 完全初始化后,可以被应用程序使用。
  5. 销毁(Destruction):
    Spring 容器调用销毁方法,执行一些清理操作。可以通过 @PreDestroy 注解或 destroy-method 属性来指定销毁方法。

1.3 Spring中IOC与AOP

概念

IOC:控制反转,是一种设计模式。
一层含义是控制权的转移:由传统的在程序中控制依赖转移到由容器来控制;
第二层是依赖注入(DI):将相互依赖的对象分离,在spring配置文件中或用注解的方式来描述他们的依赖关系。他们的依赖关系只在使用的时候才建立。简单来说就是不需要NEW一个对象了。

AOP:面向切面,是一种编程思想,OOP的延续。将系统中非核心的业务提取出来,进行单独处理。比如事务、日志和安全等。这个简单来说就是可以在一段程序之前或者之后做一些事。

Spring 的AOP和IOC都是为了解决系统代码耦合度过高的问题。使代码重用度高、易于维护。
不过AOP和IOC并不是spring中特有的,只是spring把他们应用的更灵活方便

DI

DI 就是依赖注入,其实和 IOC 大致相同,只不过是「同一个概念使用了不同的角度去阐述」
spring 中有三种注入方式

  • 接口注入
  • 构造器注入
  • set注入

AOP

AOP 意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术

AOP 实现主要分为两类:
  • 静态 AOP 实现, AOP 框架「在编译阶段」对程序源代码进行修改,生成了静态的 AOP 代理类(生成的 *.class 文件已经被改掉了,需要使用特定的编译器),比如 Aspect

  • 动态 AOP 实现, AOP 框架「在运行阶段」对动态生成代理对象(在内存中以 JDK 动态代理,或 CGlib 动态地生成 AOP 代理类),如 SpringAOP

    spring 中 AOP 的实现是「通过动态代理实现的」,如果是实现了接口就会使用 JDK 动态代理,否则就使用 CGLIB 代理。

有 5 种通知类型
  • @Before: 在目标方法调用前去通知
  • @AfterReturning: 在目标方法返回或异常后调用
  • @AfterThrowing: 在目标方法返回后调用
  • @After: 在目标方法异常后调用
  • @Around: 将目标方法封装起来,自己确定调用时机

1.4 Spring 事务的实现方式和实现原理

Spring 事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring 是无法提供事务功能的。
真正的数据库层的事务提交和回滚是通过binlog 或者 redo log 实现的。

1.4.1 Spring 事务的种类

Spring 支持编程式事务管理和声明式事务管理两种方式:

  • 编程式事务管理使用 TransactionTemplate。
  • 声明式事务管理建立在 AOP 之上的
  • 声明式事务最大的优点就是不需要在业务逻辑代码中掺杂事务管理的代码,只需在配置文件中做相关的事务规则声明或通过@Transactional 注解的方式,便可以将事务规则应用到业务逻辑中。
  • 声明式事务管理要优于编程式事务管理,这正是 spring 倡导的非侵入式的开发方式,使业务代码不受污染,只要加上注解就可以获得完全的事务支持。唯一不足地方是,最细粒度只能作用到方法级别,无法做到像编程式事务那样可以作用到代码块级别。
  • 声明式事务本质是通过 AOP 功能,对方法前后进行拦截,将事务处理的功能编织到拦截的方法中,也就是在目标方法开始之前加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。

1.4.2 事务的传播行为 propagation

Spring 事务的传播行为说的是,当多个事务同时存在的时候, Spring 如何处理这些事务的行为。

  • Propagation.REQUIRED(默认):如果当前存在事务,则加入该事务;如果当前没有事务,则启动一个新的事务。
  • Propagation.SUPPORTS:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就以非事务执行。‘
  • Propagation.MANDATORY:支持当前事务,如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
  • Propagation.REQUIRES_NEW:总是启动一个新的事务。如果当前存在事务,则将当前事务挂起。
  • Propagation.NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
  • Propagation.NEVER: 以非事务方式执行,如果当前存在事务,则抛出异常。
  • Propagation.NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则按 REQUIRED 属性执行。

1.4.3 事务的隔离级别 isolation

各数据库默认隔离级别

mysql —可重复读

oracle,sql server —读已提交

互联网项目请用:读已提交(Read Commited)这个隔离级别!

1、读未提交(read uncommitted)

事务尚未提交,其他事务即可以看到该事务的修改结果。隔离级别最差,脏读、不可重复读、幻读都不能避免

2、读提交(read committed)

  • 描述:防止脏读,但允许不可重复读和幻读。事务只能读取其他事务已提交的数据。
  • 解决:解决了脏读问题。

3、可重复读(repeatable read)-------innodb默认隔离级别

  • 描述:防止脏读和不可重复读,但允许幻读。事务在读取数据时,会加共享锁,防止其他事务修改数据。
  • 解决:解决了脏读和不可重复读问题

4、串行化(serializable)

  • 描述:最高的隔离级别,防止脏读、不可重复读和幻读。事务在读取数据时,会加范围锁,防止其他事务插入或删除数据。
  • 解决:解决了所有并发问题,但性能开销最大

1.4.4 事务的回滚行为

  • 默认回滚行为:默认情况下,事务管理器会回滚所有未检查的异常(即继承自 RuntimeException 的异常)。对于检查的异常(即继承自 Exception 的异常),事务管理器不会自动回滚。
  • 自定义回滚行为:可以通过 rollbackFor 和 noRollbackFor 属性自定义回滚行为。
    rollbackFor:指定哪些异常会触发事务回滚。
    noRollbackFor:指定哪些异常不会触发事务回滚。

1.4.5 事务的四大特性(ACID)

1、原子性(Atomicity)

操作要么全部成功,要么全部失败回滚。

2、一致性(Consistency)

事务执行前和执行后处于一致性状态。例如,转账前A、B共1000元,A、B之间转账后,两者之和仍应该是1000元。

3、隔离性(Isolation)

多个事务之间互不干扰。

SQL 标准定义了四种隔离级别:

  • 读未提交(Read Uncommitted):最低的隔离级别,允许读取未提交的数据(脏读)。
  • 读已提交(Read Committed):只能读取已提交的数据,避免了脏读。
  • 可重复读(Repeatable Read):保证在同一个事务中,多次读取同一数据的结果是一致的。
  • 串行化(Serializable):最高的隔离级别,完全隔离并发事务,确保事务的执行顺序。

4、持久性(Durability)

事务一旦提交,数据的改变是永久性的,即使这时候数据库发生故障,数据也不会丢失。

1.4.6 与事务隔离级别的相关问题

1.4.6.1 脏读
  • 定义:脏读是指一个事务读取了另一个事务未提交的数据
  • 问题:如果事务 A 读取了事务 B 未提交的数据,而事务 B 最终回滚,那么事务 A 读取到的数据是无效的,这会导致数据不一致。
1.4.6.2 不可重复读
  • 定义:不可重复读是指一个事务在读取同一数据时,多次读取的结果不一致。这通常是因为另一个事务在两次读取之间修改了数据。
  • 问题:如果事务 A 两次读取同一数据,中间事务 B 修改了该数据并提交,事务 A 会看到不同的结果,这会导致数据不一致。
1.4.6.3 幻读
  • 定义:幻读是指一个事务在读取一组数据时,多次读取的结果不一致。这通常是因为另一个事务在两次读取之间插入或删除了数据。
  • 问题:如果事务 A 两次读取同一组数据,中间事务 B 插入或删除了数据并提交,事务 A 会看到不同的结果,这会导致数据不一致。

小结:

不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。

解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表

1.5 SpringMVC

五大组件

  • DispatcherServlet
  • HandleMapping
  • Controller
  • ModeAndView
  • ViewResolver

介绍

1.DispatcherServlet

这个控件是SpringMVC 最核心的一个控件,顾名思义其实他就是一个Servlet,是Spring写好的一个Servlet

2.HandleMapping

控件标明了路径与Controller的对应关系,不同的路径访问不同的Controller

3. Controller

用来处理业务逻辑的Java类

4. ModeAndView

Mode用来绑定处理后所得的数据,View视图名

5. ViewResolver

视图解析器明确了视图名与视图对象的关系,是调用demo.jsp还是调用demo.html,以及明确视图的位置

关系图

在这里插入图片描述

1.6 Spring中都用到了哪些设计模式

  • 单例模式:Spring 中的 Bean 默认都是单例的
  • 工厂模式:比如通过 BeanFactory 和 ApplicationContext 来生产 Bean 对象
  • 代理模式:AOP 的实现方式就是通过代理来实现,Spring主要是使用 JDK 动态代理和 CGLIB 代理
  • 观察者模式:Spring 事件驱动模型观察者模式的
  • 适配器模式:Spring AOP 的增强或通知(Advice)使用到了适配器模式
  • 模板模式:Spring 中 jdbcTemplate 等以 Template 结尾的对数据库操作的类,都会使用到模板方法设计模式,一些通用的功能
  • 包装器模式:我们的项目需要连接多个数据库,而且不同的客户在每次访问中根据需要会去访问不同的数据库。这种模式让我们可以根据客户的需求能够动态切换不同的数据源

1.7 spring 中有哪些核心模块

  • Spring Web:它提供Web应用开发的支持
  • Spring Core:Spring核心,它是框架最基础的部分,提供IOC和依赖注入DI特性
  • Spring Context:Spring上下文容器,它是 BeanFactory 功能加强的一个子接口
  • Spring MVC:它针对Web应用中MVC思想的实现
  • Spring DAO:提供对JDBC抽象层,简化了JDBC编码,同时,编码更具有健壮性
  • Spring ORM:它支持用于流行的ORM框架的整合,比如:Spring + Hibernate、Spring + iBatis、Spring + JDO的整合等
  • Spring AOP:即面向切面编程,它提供了与AOP联盟兼容的编程实现

1.8 Spring自动装配原理

Spring 的自动装配机制通过组件扫描、注解解析和依赖注入,实现了自动化的依赖管理

  1. 容器在启动的时候会调用 EnableAutoConfigurationImportSelector.class 的 selectImports方法「获取一个全面的常用 BeanConfiguration 列表」
  2. 之后会读取 spring-boot-autoconfigure.jar 下面的spring.factories,「获取到所有的 Spring 相关的 Bean 的全限定名 ClassName」
  3. 之后继续「调用 filter 来一一筛选」,过滤掉一些我们不需要不符合条件的 Bean
  4. 最后把符合条件的 BeanConfiguration 注入默认的 EnableConfigurationPropertie 类里面的属性值,并且「注入到 IOC 环境当中」

1.9 循环依赖

spring 是怎么解决循环依赖的?

循环依赖就是说两个对象相互依赖,形成了一个环形的调用链路

spring 使用三级缓存去解决循环依赖的,其核心逻辑就是把实例化和初始化的步骤分开,然后放入缓存中,供另一个对象调用

「第一级缓存」:用来保存实例化、初始化都完成的对象
「第二级缓存」:用来保存实例化完成,但是未初始化完成的对象
「第三级缓存」:用来保存一个对象工厂,提供一个匿名内部类,用于创建二级缓存中的对象

当 A、B 两个类发生循环引用时 大致流程

  1. A 完成实例化后,去「创建一个对象工厂,并放入三级缓存」当中如果 A 被 AOP 代理,那么通过这个工厂获取到的就是 A 代理后的对象;如果 A 没有被 AOP 代理,那么这个工厂获取到的就是 A 实例化的对象
  2. A 进行属性注入时,去「创建 B」
  3. B 进行属性注入,需要 A ,则「从三级缓存中去取 A 工厂代理对象」并注入,然后删除三级缓存中的 A 工厂,将 A 对象放入二级缓存
  4. B 完成后续属性注入,直到初始化结束,将 B 放入一级缓存
  5. 「A 从一级缓存中取到 B 并且注入 B」, 直到完成后续操作,将 A 从二级缓存删除并且放入一级缓存,循环依赖结束

spring 解决循环依赖有两个前提条件:

1.「不全是构造器方式」的循环依赖(否则无法分离初始化和实例化的操作)
2.「必须是单例」(否则无法保证是同一对象)

为什么要使用三级缓存,二级缓存不能解决吗?

可以,三级缓存的功能是只有真正发生循环依赖的时候,才去提前生成代理对象,否则只会「创建一个工厂并将其放入到三级缓存」中,但是不会去通过这个工厂去真正创建对象。

如果使用二级缓存解决循环依赖,意味着所有 Bean 在实例化后就要完成 AOP 代理,这样「违背了 Spring 设计的原则」,Spring 在设计之初就是在 Bean 生命周期的最后一步来完成 AOP 代理,而不是在实例化后就立马进行 AOP 代理。

2. 注解

2.1 启动类注解

2.1.1 @SpringBootApplication

组合注解,整合了多个其他注解的功能,用于简化 Spring Boot 应用程序的配置和启动。

  • @Configuration:标记该类为一个配置类,等同于 Spring 的 XML 配置文件中的 标签,用于定义配置类,可被 @ComponentScan 扫描到并加载配置类中的 bean。
  • @EnableAutoConfiguration:启用 Spring Boot 的自动配置机制,根据添加的 jar 依赖自动配置 Spring 应用程序,如自动配置数据源、消息队列、安全框架等。
  • @ComponentScan:自动扫描并加载符合条件的组件或bean,可以检测项目中的 @Component、@Service、@Controller、@Repository 等注解,并将它们注册为 Spring 容器中的 bean。

2.1.2 @EnableFeignClients

启用 Feign 客户端的自动配置和扫描

2.1.3 @EnableDiscoveryClient

启用服务发现客户端功能,将 Spring Boot 应用程序注册到 Eureka、Consul、Nacos 等服务注册中心中,并且可以实现自动的服务发现和负载均衡。

2.2 和组件声明周期有关的注解

2.2.1 @PostConstruct

  • 描述:用于标注一个方法,在该方法上使用此注解后,Spring 容器会在创建并注入所有依赖之后,调用该方法。 这个方法通常用于执行一些初始化操作。
  • 适用场景:适用于需要在组件初始化后立即执行一些设置或初始化逻辑的场景。

2.2.2 @PreDestroy

  • 描述:用于标注一个方法,在该方法上使用此注解后,Spring 容器会在销毁组件之前调用该方法。这个方法通常用于执行一些清理操作。
  • 适用场景:适用于需要在组件销毁前执行一些清理或资源释放操作的场景。

2.2.3 @Configuration

  • 描述:用于标注一个配置类,该类可以包含多个 @Bean 注解的方法,用于定义和配置多个 bean。
  • 适用场景:适用于需要集中管理配置和 bean 定义的场景,特别是在使用 Java 配置类时。

2.2.4 @Bean

  • 描述:用于在配置类中定义一个 bean。标注在方法上,该方法的返回值将被注册为 Spring 容器中的一个 bean。
  • 适用场景:适用于需要手动定义和配置 bean 的场景,特别是在使用 Java 配置类时。

2.2.5 @Component

  • 描述:用于标注一个组件,Spring 会自动扫描并注册为一个 bean。这个注解可以用于标注任何类,使其成为一个 Spring 管理的组件。
  • 适用场景:适用于需要自动扫描和注册为 Spring bean 的类。

2.2.6 @Controller

  • 描述:用于标注一个控制器层组件,Spring 会自动扫描并注册为一个 bean。这个注解是 @Component 的一个特化版本,主要用于控制器层。
  • 适用场景:适用于控制器层组件。

2.2.7 @Service

  • 描述:用于标注一个服务层组件,Spring 会自动扫描并注册为一个 bean。这个注解是 @Component 的一个特化版本,主要用于服务层。
  • 适用场景:适用于服务层组件。

2.2.8 @Repository

  • 描述:用于标注一个数据访问层组件,Spring 会自动扫描并注册为一个 bean。这个注解是 @Component 的一个特化版本,主要用于数据访问层。
  • 适用场景:适用于数据访问层组件。

2.2.9 @ApplicationRunner 和 @CommandLineRunner

  • 描述:这两个注解用于在 Spring Boot 应用启动后执行一些特定的操作。@ApplicationRunner 在 @CommandLineRunner 之后执行。
  • 适用场景:适用于需要在应用启动后立即执行一些初始化或启动逻辑的场景。

2.3 @Autowired 和@Resource

2.3.1 区别

  1. Autowired是Spring提供的,默认是按照类型装配注入的
  2. @Resource是java提供的,默认是按照名称来装配注入的,只有当找不到与名称匹配的bean才会按照类型来装配注入
  3. 默认情况下使用@Autowired注释进行自动注入时,Spring容器中匹配的候选bean数目必须有且仅有一个

可以通过@Qualifier注释指定注入Bean的名称,和@Autowired配合使用,这时自动注入的策略就从byType转变成byName了。

2.3.2 @Autowired

  • 原理:Spring容器会根据注解标注的属性类型,在容器中查找匹配的bean。如果找到一个匹配的bean,则将其注入到标注的属性中;如果找到多个匹配的bean,则会根据一些规则(如优先级、是否为首选bean等)来选择一个进行注入;如果没有找到匹配的bean,则会抛出异常。
  • 使用场景:当项目中对某个类型的bean只有一个实例时,使用按类型装配非常方便,无需关心bean的具体名称,只需关注类型即可。例如,项目中只有一个UserService接口的实现类UserServiceImpl,在需要注入UserService的地方使用@Autowired注解即可。
  • 优点:减少了对bean名称的依赖,使得代码更加简洁、易读,同时也降低了因bean名称变更而导致的错误风险。
  • 缺点:当存在多个相同类型的bean时,可能会导致注入结果不确定,需要通过其他方式(如@Primary、@Qualifier等)来进一步指定注入的bean

2.3.3 实战

  1. 方式1:按照【类型】注入
@Autowired
private BookDao bookDao;
  1. 方式2:按照【名称】注入
@Resource( name="bookDao")
private BookDao bookDao;   //spring容器中找name为bookDao
  1. 方式3:按照类型注入(autowired)时,如果注入的是一个接口,而这个接口又有多个实现类,则会报错。可以使用如下解决方案,配合@Qualifier使用按名称注入:
@Autowired  //按照类型注入    但是,如果找到多个匹配的就会报错,expected single matching bean but found 2
@Qualifier("userServiceImpl2")  //按照名称注入
  1. 注意:@Qualifier不能当独使用,一般配合@Autowired使用
//@Autowired  按照类型注入
//@Qualifier("userServiceImpl")  //按照名称注入
@Resource(name="userServiceImpl")  //按照名称注入
private UserService userService;

2.4 @Transactional

2.5 @RequestMapping 和 @GetMapping @PostMapping 区别

  • @GetMapping是一个组合注解,是@RequestMapping(method = RequestMethod.GET)的缩写。
  • @PostMapping是一个组合注解,是@RequestMapping(method = RequestMethod.POST)的缩写。

2.6 缓存注解

2.6.1 @Cacheable

可以用在方法或者类级别。当他应用于方法级别的时候,缓存返回值。当应用在类级别的时候,这个类的所有方法的返回值都将被缓存。

2.6.2 @Cacheable注解

有三个参数:value(必须的)、key(可选)和condition(可选)。

  • value: 指明了缓存将被存到什么地方。
  • key(可选): 任何存储在缓存中的数据为了高速访问都需要一个key。spring默认使用被@Cacheable注解的方法的签名来作为key,当然你可以重写key,自定义key可以使用SpEL表达式。
  • condition(可选): 同样的,也是引用一个SpEL表达式。但是这个参数将指明方法的返回结果是否被缓存。

总结:当执行到一个被@Cacheable注解的方法时,Spring首先检查condition条件是否满足,如果不满足,执行方法,返回;如果满足,在value所命令的缓存空间中查找使用key存储的对象,如果找到,将找到的结果返回,如果没有找到执行方法,将方法的返回值以key-对象的方式存入value缓存中,然后方法返回。

2.6.3 @CacheEvict 清除缓存

2.6.4 @ExceptionHandler捕捉异常,进行统一处理

2.7 @NotNull和@NotEmpty和@NotBlank

  1. @NotBlank:只能作用在String上,不能为null,而且调用trim()后,长度必须大于0

    ("test")    即:必须有实际字符
    
  2. @NotNull:作用在基本类型上。不能为null,但可以为empty,没有size的约束

    (""," ","   ")      
    
  3. @NotEmpty:作用在集合类上面。不能为null,而且size>0

    (" ","  ")
    

2.8 @Slf4j

安装Lombok插件

声明:如果不想每次都写private final Logger logger = LoggerFactory.getLogger(当前类名.class); 可以用注解@Slf4j;

3. 动态代理

3.1 JDK和CGLIB动态代理原理

动态代理解决了方法之间的紧耦合,

IOC解决了类与类之间的紧耦合!

3.1.1 Cglib和jdk动态代理的区别?

1、Jdk动态代理:利用拦截器(必须实现InvocationHandler)加上反射机制生成一个代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理

2、 Cglib动态代理:利用ASM框架,对代理对象类生成的class文件加载进来,通过修改其字节码生成子类来处理

3.1.2 什么时候用cglib什么时候用jdk动态代理?

1、目标对象生成了接口 默认用JDK动态代理

2、如果目标对象使用了接口,可以强制使用cglib

3、如果目标对象没有实现接口,必须采用cglib库,Spring会自动在JDK动态代理和cglib之间转换

3.1.3 JDK动态代理和cglib字节码生成的区别?

1、JDK动态代理只能对实现了接口的类生成代理,而不能针对类

2、Cglib是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法,并覆盖其中方法的增强,但是因为采用的是继承,所以该类或方法最好不要生成final,对于final类或方法,是无法继承的

3.1.4 Cglib比JDK快?

1、cglib底层是ASM字节码生成框架,但是字节码技术生成代理类,在JDL1.6之前比使用java反射的效率要高

2、在jdk6之后逐步对JDK动态代理进行了优化,在调用次数比较少时效率高于cglib代理效率

3、只有在大量调用的时候cglib的效率高,但是在1.8的时候JDK的效率已高于cglib

4、Cglib不能对声明final的方法进行代理,因为cglib是动态生成代理对象,final关键字修饰的类不可变只能被引用不能被修改

3.2 Spring如何选择是用JDK还是cglib?

1、当bean实现接口时,会用JDK代理模式

2、当bean没有实现接口,用cglib实现

3、可以强制使用cglib(在spring配置中加入<aop:aspectj-autoproxy proxyt-target-class=”true”/>)

3.3 JDK和CGLIB动态代理总结

JDK代理是不需要第三方库支持,只需要JDK环境就可以进行代理,使用条件:

1)实现InvocationHandler

2)使用Proxy.newProxyInstance产生代理对象

3)被代理的对象必须要实现接口

CGLib必须依赖于CGLib的类库,但是它需要类来实现任何接口代理的是指定的类生成一个子类,覆盖其中的方法,是一种继承但是针对接口编程的环境下推荐使用JDK的代理;

application.properties和application.yml文件

  • spring boot项目中同时存在application.properties和application.yml文件时,两个文件都有效,但是application.properties的优先级会比application.yml高
  • 配置文件所在目录不同优先级也不同。如下图1~4优先级从高到低
    在这里插入图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值