java八股文-spring

news2025/3/12 12:27:12

目录

1. spring基础

1.1 什么是Spring?

1.2 Spring有哪些优点?

1.3 Spring主要模块

 1.4 Spring常用注解

1.5 Spring中Bean的作用域

1.6 Spring自动装配的方式

 1.7  SpringBean的生命周期

1.8 多级缓存

1.9 循环依赖?

  1 .8.1 原因

1.8.2 解决 

2. IOC

2.1 spring IOC实现机制

2.2 IOC 容器的类型

2.3 spring ioc容器工作过程

2.3.1  配置元数据:配置 Spring 容器的方式

2.3.2. 启动 IOC 容器:加载配置并初始化容器

2.3.3 实例化 Bean:创建对象

2.3.4. 依赖注入:注入依赖

2.3.5. 初始化 Bean:执行初始化方法

2.3.6. 使用 Bean:通过容器获取 Bean

2.3.7. 销毁 Bean:执行销毁方法

2.3.8. 总结 Spring IOC 容器工作过程

2.4 有哪些不同类型的IOC(依赖注入)?

2.5 你推荐哪种依赖注入?构造器依赖注入还是Setter方法依赖注入?

 

3. AOP

3.1 解释AOP模块

3.2 Spring面向切面编程(AOP)

3.3、Spring AOP 实现原理

3.4 AOP在项目中的运用?

 3.4.1 举例日志

3.5 JDK 动态代理 vs CGLIB 动态代理

3.5.1 比较

3.5.2 JDK动态代理

主要特点:

工作原理:

示例代码:

使用限制:

3.5.2  CGLIB 动态代理

主要特点:

工作原理:

示例代码:

使用限制:

3.6  Spring AOP VS   AspectJ AOP 

3.6.1 比较

4. spring 事务

4.1 Spring事务的种类

4.1.1  编程式事务和声明式事务 比较

4.2 spring 的事务如何实现?

4.3  事务的传播行为? 

4.4 隔离级别

4.5  spring事务失效的场景?

5. springmvc

5.1 工作流程

5.2 springmvc 常用注解

5.3 Mvc中的控制器的注解?那个注解可以替代?

6. springboot

6.1 项目中为什么选择SpringBoot

6.2 springboot 自动配置原理

6.3.  注解


1. spring基础

1.1 什么是Spring?

        Spring是一个开源的Java EE开发框架。Spring框架的核心功能可以应用在任何Java应用程序中,但对Java EE平台上的Web应用程序有更好的扩展性。Spring框架的目标是使得Java EE应用程序的开发更加简捷,通过使用POJO为基础的编程模型促进良好的编程风格。

        Spring框架的核心理念是控制反转(IoC)和面向切面编程(AOP)

1.2 Spring有哪些优点?

  • 轻量级:Spring在大小和透明性方面绝对属于轻量级的,基础版本的Spring框架大约只有2MB。
  • 控制反转(IOC):Spring使用控制反转技术实现了松耦合。依赖被注入到对象,而不是创建或寻找依赖对象。
  • 面向切面编程(AOP): Spring支持面向切面编程,同时把应用的业务逻辑与系统的服务分离开来。
  • 容器:Spring包含并管理应用程序对象的配置及生命周期。
  • MVC框架:Spring的web框架是一个设计优良的web MVC框架,很好的取代了一些web框架。
  • 事务管理:Spring对下至本地业务上至全局业务(JAT)提供了统一的事务管理接口。
  • 异常处理:Spring提供一个方便的API将特定技术的异常(由JDBC, Hibernate, 或JDO抛出)转化为一致的、Unchecked异常。

1.3 Spring主要模块

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

1.4 Spring常用注解

1.5 Spring中Bean的作用域

1.6 Spring自动装配的方式

  • byName:根据Bean的名称自动匹配,假设Person有⼀个名为 car 的属性,如果容器中刚好有⼀个名为 car 的 bean,Spring 就会⾃动将其装配给Person的 car 属性
  • byType:根据Bean的类型自动匹配,假设Person有⼀个 Car 类型的属性,如果容器中刚好有⼀个Car 类型的 Bean,Spring 就会⾃动将其装配给Person这个属性
  • constructor:与byType类似,只不过是针对构造函数而言的,如果Person有⼀个构造
  • 函数,构造函数包含⼀个 Car 类型的⼊参,如果容器中有⼀个 Car 类型的 Bean,则 Spring 将自动把这个 Bean 作为 Person构造函数的⼊参;如果容器中没有找到和构造函数⼊参匹配类型的Bean,则 Spring 将抛出异常。
  • autodetect:根据 Bean 的自省机制决定采用byType 还是 constructor进行自动装配,如果Bean 提供了默认的构造函数,则采用byType,否则采⽤ constructor

1.7  SpringBean的生命周期

ApplicationContext容器中,Bean的生命周期流程如上图所示,流程大致如下:

  • 1.首先容器启动后,会对scope为singleton且非懒加载的bean进行实例化,
  • 2.按照Bean定义信息配置信息,注入所有的属性,
  • 3.如果Bean实现了BeanNameAware接口,会回调该接口的setBeanName()方法,传入该Bean的id,此时该Bean就获得了自己在配置文件中的id,
  • 4.如果Bean实现了BeanFactoryAware接口,会回调该接口的setBeanFactory()方法,传入该Bean的BeanFactory,这样该Bean就获得了自己所在的BeanFactory,
  • 5.如果Bean实现了ApplicationContextAware接口,会回调该接口的setApplicationContext()方法,传入该Bean的ApplicationContext,这样该Bean就获得了自己所在的ApplicationContext,
  • 6.如果有Bean实现了BeanPostProcessor接口,则会回调该接口的postProcessBeforeInitialzation()方法,
  • 7.如果Bean实现了InitializingBean接口,则会回调该接口的afterPropertiesSet()方法,
  • 8.如果Bean配置了init-method方法,则会执行init-method配置的方法,
  • 9.如果有Bean实现了BeanPostProcessor接口,则会回调该接口的postProcessAfterInitialization()方法,
  • 10.经过流程9之后,就可以正式使用该Bean了,对于scope为singleton的Bean,Spring的ioc容器中会缓存一份该bean的实例,而对于scope为prototype的Bean,每次被调用都会new一个新的对象,期生命周期就交给调用方管理了,不再是Spring容器进行管理了
  • 11.容器关闭后,如果Bean实现了DisposableBean接口,则会回调该接口的destroy()方法,
  • 12.如果Bean配置了destroy-method方法,则会执行destroy-method配置的方法,至此,整个Bean的生命周期结束

1.8 多级缓存

  • 一级缓存singletonObjects: 存储已经完全初始化的单例Bean。类型ConcurrentHashMap<String, Object>
  • 二级缓存earlySingletonObjects: 多了一个early,表示缓存的是早期的bean对象。早期是什么意思?表示Bean的生命周期还没走完就把这个Bean放入earlySingletonObjects,通常是为了避免循环依赖。类型ConcurrentHashMap<String, Object>
  • 三级缓存singletonFactories: 存储创建Bean的工厂ObjectFactory,用于解决循环依赖。类型:ConcurrentHashMap<String, ObjectFactory<?>>

1.9 循环依赖?

  1 .9.1 原因

    

  1. 依赖注入:在 Spring 中,如果两个或多个 Bean 相互依赖而没有明确的初始化顺序,容器在创建这些 Bean 时就会陷入死循环。
  2. 构造器注入:构造器注入是一个常见的导致循环依赖的问题,因为 Spring 在实例化一个 Bean 时,如果该 Bean 的构造方法依赖于另一个 Bean,这个依赖关系无法通过简单的代理或懒加载解决。
  3. 自动装配(Autowired):使用自动装配方式进行依赖注入时,可能不小心出现循环依赖。

  1.9.2 解决 

  1. 通过 setter 注入解决(推荐)

    • Spring 容器在创建 Bean 时,先创建 Bean 的实例(但不完全初始化),然后将其放入容器中,再处理其依赖的其他 Bean。
    • 在 setter 注入方式下,Spring 容器可以通过先实例化一个 Bean,稍后再注入依赖的方式来避免死循环。
  2. 通过 @Lazy 注解

    • 可以通过 @Lazy 注解将某些 Bean 的初始化延迟到实际使用时进行。通过懒加载来避免循环依赖。
  3. 通过构造器注入的解决方案

    • 如果循环依赖发生在构造器注入时,Spring 容器无法直接解决这个问题(即无法通过 A 创建 B,B 创建 A)。这种情况需要调整代码设计,例如:
      • 使用 @PostConstruct 或 @Autowired 的 setter 方法来替代构造器注入。
      • 将依赖关系的部分移到单独的 Bean 中,以打破循环。

    2. IOC

    2.1 spring IOC实现机制

    1. 配置元数据:通过 XML 配置文件、Java 配置类(注解方式)或注解(如 @Component)来定义和配置 bean。
    2. 初始化容器:当 Spring 容器启动时,它会读取配置元数据(如 XML 或 Java 配置类)来创建和配置相应的 Bean。
    3. 依赖注入:容器根据配置的规则,自动注入 Bean 的依赖,并将这些依赖注入到目标对象中。
    4. 对象管理:容器会管理 Bean 的生命周期,负责对象的创建、初始化、销毁等。

    2.2 IOC 容器的类型

    特性BeanFactoryApplicationContext
    定义Spring 的最基本容器接口,用于管理 Bean 的创建和获取Spring 的更高级容器接口,扩展了 BeanFactory,提供更多的功能
    功能仅支持基础的 Bean 管理功能,如 Bean 的创建、获取、销毁提供更多功能,如国际化支持、事件发布、AOP 支持、应用上下文等
    延迟初始化默认情况下支持延迟加载,直到需要时才实例化 Bean默认情况下,支持 Eager 初始化(提前初始化),不过可以通过配置支持延迟加载
    应用场景适用于资源有限的场景(例如设备端、嵌入式系统等)适用于大多数应用场景,通常用于 Web 和企业级应用开发
    支持的功能不支持 AOP、事件机制、国际化等高级功能支持 AOP、事件机制、国际化、自动装配、环境配置等丰富功能
    实现类XmlBeanFactory(Spring 3.x 以前使用)<br> DefaultListableBeanFactoryAnnotationConfigApplicationContext<br> ClassPathXmlApplicationContext
    实例化方式Bean 的实例化过程相对简单提供更多的管理功能,例如注册监听器、处理配置等
    性能相对较轻量,适合简单的 Bean 管理因为功能丰富,相对来说比 BeanFactory 更加复杂,可能稍慢
    获取 Bean使用 getBean() 方法获取 Bean使用 getBean() 方法获取 Bean,功能扩展更多(例如可以按类型获取)
    生命周期管理主要管理 Bean 的生命周期支持更多生命周期的管理,如事件发布、Bean 初始化后的回调等
    常见实现类DefaultListableBeanFactoryAnnotationConfigApplicationContextGenericWebApplicationContext

    2.3 spring ioc容器工作过程

    2.3.1  配置元数据:配置 Spring 容器的方式

    Spring IOC 容器的工作首先依赖于配置元数据。配置元数据描述了容器应该如何管理 Bean 对象。配置元数据可以有多种方式:

    • XML 配置:通过 XML 文件定义 Bean。
    • 注解配置:通过 Java 注解(如 @Component)来定义 Bean。
    • Java 配置类:通过 @Configuration 和 @Bean 注解来定义 Bean。

    2.3.2. 启动 IOC 容器:加载配置并初始化容器

    启动 Spring 容器时,容器会加载配置元数据并开始初始化。容器的启动会解析配置文件或注解信息,识别所有的 Bean 定义和 Bean 之间的依赖关系。

    2.3.3 实例化 Bean:创建对象

    Spring IOC 容器根据解析的配置信息实例化 Bean。容器首先实例化 Bean,但在这个过程中,Bean 的依赖关系尚未注入。此时,Bean 对象是创建但尚未完全初始化的。

    2.3.4. 依赖注入:注入依赖

    在实例化 Bean 之后,Spring 会检查是否存在依赖注入(DI)。如果一个 Bean 依赖于另一个 Bean,Spring 会通过构造器注入或 setter 注入的方式来为 Bean 注入依赖。

    依赖注入的方式:

    • 构造器注入:在创建对象时通过构造方法传递依赖。
    • Setter 注入:通过调用 setter 方法注入依赖。
    • 自动装配:Spring 自动根据类型或名称注入依赖。

    2.3.5. 初始化 Bean:执行初始化方法

    Spring 容器实例化并注入依赖后,会调用 Bean 的初始化方法。初始化方法可以通过以下两种方式定义:

    • 使用 @PostConstruct 注解:在 Bean 初始化后自动调用。
    • 通过 init-method 配置:在 XML 配置中指定初始化方法。

    2.3.6. 使用 Bean:通过容器获取 Bean

    在容器初始化完成后,应用程序可以从容器中获取 Bean 来执行实际的业务逻辑。容器负责管理 Bean 的生命周期和状态。通常使用 getBean() 方法来获取容器中的 Bean。

    2.3.7. 销毁 Bean:执行销毁方法

    当容器关闭时,它会销毁所有的 Bean。如果 Bean 定义了销毁方法,容器会在销毁 Bean 时自动调用这些方法。

    销毁方法配置:

    • 使用 @PreDestroy 注解:在销毁 Bean 前自动调用。
    • 通过 destroy-method 配置:在 XML 配置中指定销毁方法。

    2.3.8. 总结 Spring IOC 容器工作过程

    Spring IOC 容器的工作过程可以总结为以下几个关键步骤:

    1. 配置元数据:通过 XML 配置文件或注解方式定义 Bean。
    2. 启动 IOC 容器:容器读取配置元数据并初始化。
    3. 实例化 Bean:容器根据配置创建 Bean 实例。
    4. 依赖注入:通过构造器、setter 或自动装配注入依赖。
    5. 初始化 Bean:执行初始化方法。
    6. 使用 Bean:从容器中获取 Bean,执行业务逻辑。
    7. 销毁 Bean:容器关闭时调用销毁方法。

    2.4 有哪些不同类型的IOC(依赖注入)?

    • 构造器依赖注入:构造器依赖注入在容器触发构造器的时候完成,该构造器有一系列的参数,每个参数代表注入的对象。
    • Setter方法依赖注入:首先容器会触发一个无参构造函数或无参静态工厂方法实例化对象,之后容器调用bean中的setter方法完成Setter方法依赖注入。

    2.5 你推荐哪种依赖注入?构造器依赖注入还是Setter方法依赖注入?

    你可以同时使用两种方式的依赖注入,最好的选择是使用构造器参数实现强制依赖注入,使用setter方法实现可选的依赖关系。

     

      3. AOP

      3.1 解释AOP模块

           AOP模块用来开发Spring应用程序中具有切面性质的部分。该模块的大部分服务由AOP Aliance提供,这就保证了Spring框架和其他AOP框架之间的互操作性。另外,该模块将元数据编程引入到了Spring。

      3.2 Spring面向切面编程(AOP)

      1.    面向切面编程(AOP):允许程序员模块化横向业务逻辑,或定义核心部分的功能,例如日志管理和事务管理。

      2.    切面(Aspect) :AOP的核心就是切面,它将多个类的通用行为封装为可重用的模块。该模块含有一组API提供 cross-cutting功能。例如,日志模块称为日志的AOP切面。根据需求的不同,一个应用程序可以有若干切面。在Spring AOP中,切面通过带有@Aspect注解的类实现。

      3.   通知(Advice):通知表示在方法执行前后需要执行的动作。实际上它是Spring AOP框架在程序执行过程中触发的一些代码。Spring切面可以执行一下五种类型的通知:

      • before(前置通知):在一个方法之前执行的通知。
      • after(最终通知):当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。
      • after-returning(后置通知):在某连接点正常完成后执行的通知。
      • after-throwing(异常通知):在方法抛出异常退出时执行的通知。
      • around(环绕通知):在方法调用前后触发的通知。

      4.   切入点(Pointcut):切入点是一个或一组连接点,通知将在这些位置执行。可以通过表达式或匹配的方式指明切入点。

      引入:引入允许我们在已有的类上添加新的方法或属性。

      5.  目标对象:被一个或者多个切面所通知的对象。它通常是一个代理对象。也被称做被通知(advised)对象。

      6.  代理:代理是将通知应用到目标对象后创建的对象。从客户端的角度看,代理对象和目标对象是一样的。有以下几种代理:

      • BeanNameAutoProxyCreator:bean名称自动代理创建器
      • DefaultAdvisorAutoProxyCreator:默认通知者自动代理创建器
      • Metadata autoproxying:元数据自动代理

      7.  织入:将切面和其他应用类型或对象连接起来创建一个通知对象的过程。织入可以在编译、加载或运行时完成。

      3.3、Spring AOP 实现原理

      实现AOP的技术,主要分为两大类:

      • 一是采用动态代理技术,利用截取消息的方式,对该消息进行装饰,以取代原有对象行为的执行;
      • 二是采用静态织入的方式,引入特定的语法创建“方面”,从而使得编译器可以在编译期间织入有关“方面”的代码。

      Spring AOP 的实现原理其实很简单:AOP 框架负责动态地生成 AOP 代理类,这个代理类的方法则由 Advice和回调目标对象的方法所组成, 并将该对象可作为目标对象使用。AOP 代理包含了目标对象的全部方法,但AOP代理中的方法与目标对象的方法存在差异,AOP方法在特定切入点添加了增强处理,并回调了目标对象的方法。

      Spring AOP使用动态代理技术在运行期织入增强代码。使用两种代理机制:基于JDK的动态代理(JDK本身只提供接口的代理)和基于CGlib的动态代理。

      • (1) JDK的动态代理 JDK的动态代理主要涉及java.lang.reflect包中的两个类:Proxy和InvocationHandler。其中InvocationHandler只是一个接口,可以通过实现该接口定义横切逻辑,并通过反射机制调用目标类的代码,动态的将横切逻辑与业务逻辑织在一起。而Proxy利用InvocationHandler动态创建一个符合某一接口的实例,生成目标类的代理对象。 其代理对象必须是某个接口的实现, 它是通过在运行期间创建一个接口的实现类来完成对目标对象的代理.只能实现接口的类生成代理,而不能针对类
      • (2)CGLib CGLib采用底层的字节码技术,为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类的调用方法,并顺势织入横切逻辑.它运行期间生成的代理对象是目标类的扩展子类.所以无法通知final、private的方法,因为它们不能被覆写.是针对类实现代理,主要是为指定的类生成一个子类,覆盖其中方法. 在spring中默认情况下使用JDK动态代理实现AOP,如果proxy-target-class设置为true或者使用了优化策略那么会使用CGLIB来创建动态代理.Spring AOP在这两种方式的实现上基本一样.以JDK代理为例,会使用JdkDynamicAopProxy来创建代理,在invoke()方法首先需要织入到当前类的增强器封装到拦截器链中,然后递归的调用这些拦截器完成功能的织入.最终返回代理对象.

      3.4 AOP在项目中的运用?

       3.4.1 举例日志

      •  自定义注解
      import java.lang.annotation.*;
      
      @Target({ElementType.METHOD})   // 指定注解使用在方法上
      @Retention(RetentionPolicy.RUNTIME)
      @Documented
      public @interface methodLog {
      
          String log();
      }
      
      • 切面
      @Aspect   // 标识当前类为切面
      @Component
      public class CustomLogAspect {
      
          // getLogger(Class<?> clazz)
          public static final Logger logger = LoggerFactory.getLogger(CustomLogAspect.class);
      
          // 以自定义注解 @CustomLog为切点
          @Pointcut("@annotation(com.example.interviewStudy.annotation.methodLog)")
          public void logPcut() {
          }
      
          // 前置通知: 在切点之前织入
          @Before("logPcut()")
          public void doBefore(JoinPoint joinPoint) throws JsonProcessingException {
              ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
              HttpServletRequest request = attributes.getRequest();
              logger.info("========== 开始打印请求参数 ===========");
              logger.info("URL: {}", request.getRequestURL().toString());
              logger.info("HTTP Method: {}", request.getMethod());
              logger.info("Controller的全路径 和 执行方法: {} , {}方法", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName());
              logger.info("请求入参:{}", new ObjectMapper().writeValueAsString(joinPoint.getArgs()));
          }
      
          // 后置通知,在切入点之后织入
          @After("logPcut()")
          public void doAfter() {
              logger.info("======== 请求日志输出完毕 ========");
          }
      
          /**
           * 环绕通知: ProceedingJoinPoint对象调用proceed方法,实现 原本目标方法的调用
           *   ProceedingJoinPoint 只支持环绕通知,如果其他通知也采用ProceedingJoinPoint作为连接点,就会出现异常
           *   ==> Caused by: java.lang.IllegalArgumentException: ProceedingJoinPoint is only supported for around advice
           * */
          @Around("logPcut()")
          public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
      
              long start = System.currentTimeMillis();
      
              Object result = joinPoint.proceed();
              long end = System.currentTimeMillis();
      
              logger.info("请求结果: {}", new ObjectMapper().writeValueAsString(result));
              logger.info("请求处理耗时: {} ms", (end - start));
              return result;
          }
      
      • 在接口上添加自定义注解
      @RestController
      @RequestMapping("/aop")
      public class CustomAspectController {
      
          @GetMapping("/hello")
          @MethodLog(info = "AOP实现请求日志输出")
          public String hello(String uname) {
              return "hello " + uname;
          }
      }
      

      3.5 JDK 动态代理 vs CGLIB 动态代理

      3.5.1 比较

      特性JDK 动态代理CGLIB 动态代理
      代理方式基于接口,通过反射机制生成代理类基于继承,通过字节码生成代理类
      要求目标类必须实现接口目标类可以不实现接口,不限于接口代理
      性能较低(由于每次方法调用都涉及反射)较高(由于基于字节码生成,性能较好)
      代理对象代理对象实现目标接口代理对象继承目标类
      缺点不能代理没有接口的类不能代理 final 类和 final 方法
      应用场景适用于目标类有接口时适用于目标类没有接口时

      3.5.2 JDK动态代理

      JDK 动态代理是基于 Java 反射机制,通过接口来创建代理对象。它要求目标类实现至少一个接口,代理类通过实现该接口来代理目标对象的方法。

      主要特点:
      • 接口驱动:JDK 动态代理只能对实现了接口的类创建代理对象。
      • 通过 java.lang.reflect.Proxy 类创建代理:JDK 动态代理通过 Proxy.newProxyInstance() 方法生成代理对象,内部会使用反射来调用接口的方法。
      工作原理:

      JDK 动态代理利用 Proxy 类和 InvocationHandler 接口来实现动态代理。InvocationHandler 是代理逻辑的实现类,重写 invoke() 方法处理对目标对象方法的调用。

      示例代码:
      import java.lang.reflect.*;
      
      interface Greeting {
          void sayHello();
      }
      
      class GreetingImpl implements Greeting {
          public void sayHello() {
              System.out.println("Hello, world!");
          }
      }
      
      class MyInvocationHandler implements InvocationHandler {
          private Object target;
      
          public MyInvocationHandler(Object target) {
              this.target = target;
          }
      
          @Override
          public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
              System.out.println("Before method call");
              Object result = method.invoke(target, args);
              System.out.println("After method call");
              return result;
          }
      }
      
      public class JDKProxyExample {
          public static void main(String[] args) {
              Greeting greeting = new GreetingImpl();
              MyInvocationHandler handler = new MyInvocationHandler(greeting);
              Greeting proxy = (Greeting) Proxy.newProxyInstance(
                  greeting.getClass().getClassLoader(),
                  new Class[]{Greeting.class},
                  handler
              );
              proxy.sayHello();
          }
      }
      
      使用限制:
      • 必须有接口:JDK 动态代理只能对实现了接口的类进行代理。如果目标类没有接口,JDK 动态代理无法使用。

      3.5.2  CGLIB 动态代理

      CGLIB(Code Generation Library)是一个第三方库,用于通过字节码生成技术来创建目标类的子类。CGLIB 通过继承目标类的方式实现代理,不需要目标类实现接口,因此可以对没有接口的类进行代理。

      主要特点:
      • 基于继承:CGLIB 动态代理是通过继承目标类来创建代理类,因此不要求目标类实现接口。
      • 效率较高:由于它是基于字节码操作,通过继承生成子类,它的性能相对较好,尤其是在没有接口时。
      工作原理:

      CGLIB 通过继承目标类,并在子类中重写目标类的方法来实现代理逻辑。它使用 MethodInterceptor 接口来定义代理行为。

      示例代码:
      import org.springframework.cglib.proxy.Enhancer;
      import org.springframework.cglib.proxy.MethodInterceptor;
      import org.springframework.cglib.proxy.MethodProxy;
      
      class Greeting {
          public void sayHello() {
              System.out.println("Hello, world!");
          }
      }
      
      class MyMethodInterceptor implements MethodInterceptor {
          private Object target;
      
          public MyMethodInterceptor(Object target) {
              this.target = target;
          }
      
          @Override
          public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args, MethodProxy proxy) throws Throwable {
              System.out.println("Before method call");
              Object result = method.invoke(target, args);
              System.out.println("After method call");
              return result;
          }
      }
      
      public class CGLIBProxyExample {
          public static void main(String[] args) {
              Greeting greeting = new Greeting();
              MyMethodInterceptor interceptor = new MyMethodInterceptor(greeting);
              
              Enhancer enhancer = new Enhancer();
              enhancer.setSuperclass(Greeting.class);
              enhancer.setCallback(interceptor);
              
              Greeting proxy = (Greeting) enhancer.create();
              proxy.sayHello();
          }
      }
      

      使用限制:
      • 不能代理 final 类和 final 方法:由于 CGLIB 是通过继承目标类来生成代理类的,因此它不能代理 final 类或者含有 final 方法的类。

      3.6  Spring AOP VS   AspectJ AOP 

      3.6.1 比较

      特性Spring AOPAspectJ AOP
      实现方式基于代理(JDK 动态代理或 CGLIB)基于字节码增强(编译时、类加载时、运行时)
      切面支持方法级切面方法级和字段级切面
      通知支持前置、后置、环绕、异常、返回通知更丰富的通知支持(构造通知、字段通知等)
      织入时机运行时织入编译时、类加载时、运行时织入
      性能相对较低(依赖动态代理)较高(编译时或类加载时织入)
      使用场景适合 Spring 管理的 Bean 和方法级切面适合需要全面 AOP 支持的应用
      功能扩展性较简单,适合基本 AOP 使用功能强大,适合复杂的 AOP 场景

       

      4. spring 事务

      4.1 Spring事务的种类

      4.1.1  编程式事务声明式事务 比较

      特性编程式事务声明式事务
      事务控制方式手动控制事务的生命周期Spring 自动管理事务
      代码复杂度代码冗长,业务代码与事务代码混合代码简洁,事务与业务解耦
      灵活性灵活,可根据业务需求自定义事务行为灵活性较低,配置有限
      易用性需要开发者显式控制事务的开启、提交等通过注解或 XML 配置,易于使用
      适用场景需要复杂事务控制、动态事务管理常规的、简单的事务管理
      性能影响事务代码显式存在,可能对性能有些影响由于 AOP 机制,可能有一些性能开销
      事务管理复杂度需要手动处理事务状态,容易出错由框架自动管理事务,减少出错几率

      4.2 spring 的事务如何实现?

             Spring通过AOP(面向切面编程)和代理机制来实现事务管理。Spring会在应用中生成代理对象,在事务开始时自动开启事务,并在方法执行后根据事务的状态决定是否提交或回滚事务。

      4.3  事务的传播行为? 

      1. PROPAGATION_REQUIRED:如果当前存在事务,则加入该事务;否则,创建新的事务(默认行为)。
      2. PROPAGATION_REQUIRES_NEW:无论当前是否有事务,都会创建一个新的事务,当前事务会被挂起。
      3. PROPAGATION_SUPPORTS:如果当前有事务,则加入该事务;否则,不开启事务。
      4. PROPAGATION_NOT_SUPPORTED:如果当前有事务,则挂起该事务;如果当前没有事务,则不创建事务。
      5. PROPAGATION_NEVER:如果当前存在事务,则抛出异常;如果当前没有事务,则不创建事务。
      6. PROPAGATION_MANDATORY:如果当前不存在事务,则抛出异常;如果当前有事务,则加入该事务。
      7. PROPAGATION_NESTED:如果当前有事务,则创建一个嵌套事务,嵌套事务的提交或回滚不会影响外部事务。

      4.4 隔离级别

      1. ISOLATION_DEFAULT:使用数据库默认的隔离级别。

      2. ISOLATION_READ_UNCOMMITTED:允许读取未提交的数据,可能会出现脏读。

      3. ISOLATION_READ_COMMITTED:只能读取已提交的数据,避免脏读。

      4. ISOLATION_REPEATABLE_READ:读取的数据在事务过程中不会改变,避免不可重复读。

      5. ISOLATION_SERIALIZABLE:最高的隔离级别,保证事务之间完全隔离,避免幻读。

      4.5  spring事务失效的场景?

      5. springmvc

      5.1 工作流程

       

      • 客户端向服务端发送一次请求,该请求会先到前端控制器/ 中央控制器 DispatcherServlet
      • DispatcherServlet 接收到请求后会调用HandlerMapping处理器映射器,由此得知,该请求由哪个Controller来处理(此时并不调用Controller)
      • DispatcherServlet调用HandlerAdapter处理器适配器,告诉处理器适配器应该要去执行哪个Controller
      • HandlerAdapter处理器适配器去执行Controller并得到ModelAndView(数据和视图),并层层返回给DispatcherServlet
      • DispatcherServlet 将 ModelAndView 交给 ViewResolver视图解析器解析,然后返回真正的视图
      • DispatcherServlet将模型数据填充到视图中
      • DispatcherServlet将结果响应给客户端

      5.2 springmvc 常用注解

      5.3 Mvc中的控制器的注解?那个注解可以替代?


      答:一般用@Controller注解,也可以使用@RestController,@RestController注解相当于@ResponseBody + @Controller,表示是表现层,除此之外,一般不用别的注解代替。

      6. springboot

      6.1 项目中为什么选择SpringBoot

      • SpringBoot简化了Spring,可以快速搭建企业级项目,而且开发起来效率也会更高,它的主要优点如下:
      • 版本锁定:SpringBoot在父工程中进行了大量常见依赖的版本锁定,省去了我们查找依赖版本和解决版本冲突的麻烦
      • 起步依赖:SpringBoot以功能化的方式将需要的依赖进行组装,并且允许程序员以starter的方式进行引入
      • 默认配置:SpringBoot实现了大量依赖框架的默认配置项,程序员无须再进行自己配置
      • 内置Tomcat:SpringBoot内置了一个tomcat,使用它开发的程序无需再进行tomcat部署,可直接运行

      6.2 springboot 自动配置原理

      6.3.  注解

      注解作用描述示例代码
      @SpringBootApplication入口注解,包含 @Configuration@EnableAutoConfiguration@ComponentScan,通常用于主类java @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
      @EnableAutoConfiguration开启自动配置功能,根据 classpath 和配置文件自动配置应用所需的 Beanjava @EnableAutoConfiguration public class Application { // 配置 }
      @SpringBootConfiguration表示 Spring Boot 配置类,等同于 @Configuration 注解java @SpringBootConfiguration public class AppConfig { // 配置 }
      @ComponentScan扫描指定包下的组件进行自动装配,通常与 @SpringBootApplication 一起使用java @ComponentScan(basePackages = "com.example") public class Application { // 配置 }
      @EnableConfigurationProperties允许将 @ConfigurationProperties 标注的类注入 Spring 容器,支持从配置文件中加载配置java @EnableConfigurationProperties(MyProperties.class) public class Application { // 配置 }
      @ConfigurationProperties将类映射到配置文件中的属性,简化配置注入java @ConfigurationProperties(prefix = "my") public class MyProperties { private String name; private int value; }
      @ConditionalOnProperty根据配置属性启用或禁用某个 Beanjava @ConditionalOnProperty(name = "feature.enabled", havingValue = "true") @Bean public MyBean myBean() { return new MyBean(); }
      @ConditionalOnClass根据类是否在 classpath 中存在来启用某个 Beanjava @ConditionalOnClass(DataSource.class) @Bean public DataSource dataSource() { return new HikariDataSource(); }
      @ConditionalOnMissingBean仅在容器中没有指定类型的 Bean 时才创建该 Beanjava @ConditionalOnMissingBean(MyService.class) @Bean public MyService myService() { return new MyServiceImpl(); }
      @EnableAutoConfiguration开启自动配置功能,通常由 @SpringBootApplication 自动引入java @EnableAutoConfiguration public class Application { // 配置 }
      @Value从配置文件中读取配置并注入到字段java @Value("${app.name}") private String appName;
      @BootApplicationSpring Boot 的增强版本的 @SpringBootApplication,提供更多灵活性java @BootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }

        本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2299826.html

        如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

        相关文章

        NLP 八股 DAY1:BERT

        BERT全称&#xff1a;Pre-training of deep bidirectional transformers for language understanding&#xff0c;即深度双向Transformer。 模型训练时的两个任务是预测句⼦中被掩盖的词以及判断输⼊的两个句⼦是不是上下句。在预训练 好的BERT模型后⾯根据特定任务加上相应的⽹…

        蓝桥与力扣刷题(230 二叉搜索树中第k小的元素)

        题目&#xff1a;给定一个二叉搜索树的根节点 root &#xff0c;和一个整数 k &#xff0c;请你设计一个算法查找其中第 k 小的元素&#xff08;从 1 开始计数&#xff09;。 示例 1&#xff1a; 输入&#xff1a;root [3,1,4,null,2], k 1 输出&#xff1a;1示例 2&#xff…

        半遮挡检测算法 Detecting Binocular Half-Occlusions

        【1. 背景】&#xff1a; 本文分析【Detecting Binocular Half-Occlusions&#xff1a;Empirical Comparisons of Five Approaches】Geoffrey Egnal和Richard P. Wildes于2002年发表在IEEE Transactions on Pattern Analysis and Machine Intelligence上&#xff0c;这是1篇中…

        PHP培训机构教务管理系统小程序

        &#x1f511; 培训机构教务管理系统——智慧教育&#xff0c;高效管理新典范 &#x1f680; 这款教务管理系统&#xff0c;是基于前沿的ThinkPHP框架与Uniapp技术深度融合&#xff0c;匠心打造的培训机构管理神器。它犹如一把开启高效运营与精细管理的金钥匙&#xff0c;专为…

        无人机不等同轴旋翼架构设计应用探究

        “结果显示&#xff0c;对于不等组合&#xff0c;用户应将较小的螺旋桨置于上游以提高能效&#xff0c;但若追求最大推力&#xff0c;则两个相等的螺旋桨更为理想。” 在近期的研究《不等同轴旋翼性能特性探究》中&#xff0c;Max Miles和Stephen D. Prior博士深入探讨了不同螺…

        CTFHub技能树-密码口令wp

        目录 引言弱口令默认口令 引言 仅开放如下关卡 弱口令 通常认为容易被别人&#xff08;他们有可能对你很了解&#xff09;猜测到或被破解工具破解的口令均为弱口令。 打开环境&#xff0c;是如下界面&#xff0c;尝试一些弱口令密码无果 利用burpsuite抓包&#xff0c;然后爆…

        【NLP251】BertTokenizer 的全部 API 及 使用案例

        BertTokenizer 是 Hugging Face 的 transformers 库中用于处理 BERT 模型输入的分词器类。它基于 WordPiece 分词算法&#xff0c;能够将文本分割成词汇单元&#xff08;tokens&#xff09;&#xff0c;并将其转换为 BERT 模型可以理解的格式。BertTokenizer 是 BERT 模型的核心…

        【MySQL常见疑难杂症】常见文件及其所存储的信息

        1、MySQL配置文件的读取顺序 &#xff08;非Win&#xff09;/etc/my.cnf、/etc/mysql/my.cnf、/usr/local/mysql/etc/my.cnf、&#xff5e;/.my.cnf 可以通过命令查看MySQL读取配置文件的顺序 [roothadoop01 ~]# mysql --help |grep /etc/my.cnf /etc/my.cnf /etc/mysql/my.c…

        IDEA集成DeepSeek

        引言 随着数据量的爆炸式增长&#xff0c;传统搜索技术已无法满足用户对精准、高效搜索的需求。 DeepSeek作为新一代智能搜索技术&#xff0c;凭借其强大的语义理解与深度学习能力&#xff0c;正在改变搜索领域的游戏规则。 对于 Java 开发者而言&#xff0c;将 DeepSeek 集成…

        leetcode:627. 变更性别(SQL解法)

        难度&#xff1a;简单 SQL Schema > Pandas Schema > Salary 表&#xff1a; ----------------------- | Column Name | Type | ----------------------- | id | int | | name | varchar | | sex | ENUM | | salary | int …

        SQLMesh系列教程-3:SQLMesh模型属性详解

        SQLMesh 的 MODEL 提供了丰富的属性&#xff0c;用于定义模型的行为、存储、调度、依赖关系等。通过合理配置这些属性&#xff0c;可以构建高效、可维护的数据管道。在 SQLMesh 中&#xff0c;MODEL 是定义数据模型的核心结构&#xff0c;初学SQLMesh&#xff0c;定义模型看到属…

        【Leetcode 952】按公因数计算最大组件大小

        题干 给定一个由不同正整数的组成的非空数组 nums &#xff0c;考虑下面的图&#xff1a; 有 nums.length 个节点&#xff0c;按从 nums[0] 到 nums[nums.length - 1] 标记&#xff1b;只有当 nums[i] 和 nums[j] 共用一个大于 1 的公因数时&#xff0c;nums[i] 和 nums[j]之…

        【第4章:循环神经网络(RNN)与长短时记忆网络(LSTM)— 4.6 RNN与LSTM的变体与发展趋势】

        引言:时间序列的魔法钥匙 在时间的长河中,信息如同涓涓细流,绵延不绝。而如何在这无尽的数据流中捕捉、理解和预测,正是循环神经网络(RNN)及其变体长短时记忆网络(LSTM)所擅长的。今天,我们就来一场深度探索,揭开RNN与LSTM的神秘面纱,看看它们如何在时间序列的海洋…

        简单几个步骤完成 Oracle 到金仓数据库(KingbaseES)的迁移目标

        作为国产数据库的领军选手&#xff0c;金仓数据库&#xff08;KingbaseES&#xff09;凭借其成熟的技术架构和广泛的市场覆盖&#xff0c;在国内众多领域中扮演着至关重要的角色。无论是国家电网、金融行业&#xff0c;还是铁路、医疗等关键领域&#xff0c;金仓数据库都以其卓…

        八、SPI读写XT25数据

        8.1 SPI 简介 SPI&#xff08;Serial Peripheral Interface&#xff0c;串行外设接口&#xff09;是一种同步串行通信协议&#xff0c;广泛用于嵌入式系统中连接微控制器与外围设备&#xff0c;如传感器、存储器、显示屏等。 主要特点 1. 全双工通信&#xff1a;支持同时发送…

        Visionpro 齿轮测量

        效果展示 一、题目要求 求出最大值&#xff0c;最小值&#xff0c;平均值 二、分析 1.首先要进行模板匹配 2.划清匹配范围 3.匹配小三角的模板匹配 4.卡尺 5.用找圆工具 工具 1.CogPMAlignTool 2.CogCaliperTool 3.CogFindCircleTool 4.CogFixtureTool 三、模板匹…

        索引以及索引底层数据结构

        一、什么是索引&#xff1f; 索引&#xff08;index&#xff09;是数据库高效获取数据的数据结构&#xff08;有序&#xff09;。在数据之外&#xff0c;数据库系统还维护着满足特定查找算法的数据结构&#xff08;B树&#xff09;&#xff0c;这些数据结构以某种方式指向真在…

        开业盛典活动策划方案拆解

        道叔来给大家详细剖析咱们方案库里刚收录的这份《蜀大侠火锅店武侠风开业盛典活动策划方案》了&#xff0c;保证让你看完直呼过瘾&#xff0c;收获满满&#xff01; 一、主题创意&#xff1a;武侠风&#xff0c;直击人心 首先&#xff0c;咱们得夸一下这活动的主题——“XXX‘…

        API 接口自动化

        HTTP协议 - 白月黑羽 HTTP协议简介 如果客户端是浏览器&#xff0c;如何在chrome浏览器中查看 请求和响应的HTTP消息&#xff1f;按f12-》network 清除当前信息 响应的消息体在Response里看 点preview&#xff0c;可以看响应的消息体展开的格式 HTTP请求消息 请求头 reques…

        安全测试|SSRF请求伪造

        前言 SSRF漏洞是一种在未能获取服务器权限时&#xff0c;利用服务器漏洞&#xff0c;由攻击者构造请求&#xff0c;服务器端发起请求的安全漏洞&#xff0c;攻击者可以利用该漏洞诱使服务器端应用程序向攻击者选择的任意域发出HTTP请求。 很多Web应用都提供了从其他的服务器上…