Java全栈面试题(四)--Spring框架

本文详细介绍了Spring的核心组件,包括IoC容器、AOP框架和MVC框架,阐述了IOC和AOP的概念及其在实际应用中的优势。此外,文章讨论了Spring MVC的工作流程和常用注解,以及Spring如何解决循环依赖问题。同时还涵盖了Spring事务管理、声明式事务的使用,以及Spring Boot和Spring Cloud的区别。最后,文章提到了MyBatis的相关内容,如#{}和${}的区别、缓存机制以及分页实现。

Spring的核心组件

        IoC容器(Inversion of Control):实现了对象的创建、管理和装配的功能,负责对象的实例化和依赖注入,它可以将我们编写的业务逻辑代码和控制流程解耦,提高代码的可重用性和可维护性。

        AOP框架(Aspect-Oriented Programming):基于动态代理实现,可以实现对系统中各个模块的横向逻辑进行统一处理,如事务管理、异常处理等。

        MVC框架(Model-View-Controller):Spring提供了一套轻量级的MVC框架,可以帮助我们更加方便地实现视图层、控制层和模型层的解耦,实现Web应用程序的快速开发。

        JDBC模块:Spring提供了一套JDBC模块,它封装了JDBC操作中的冗余代码,使得数据库操作变得更加简单和高效。

        集成模块:Spring提供了一些集成模块,可以帮助我们更加方便地将Spring集成到其他框架中,如与Struts、Hibernate等框架进行整合。

Spring MVC的核心组件

        DispatcherServlet:Spring MVC最核心的组件,基于Servlet容器实现。它是整个Spring MVC中的请求派发器,负责接收请求并将请求分发给不同的处理器进行处理。

        HandlerMapping:用来映射请求和处理器,DispatcherServlet会根据请求信息来查找合适的HandlerMapping,并将请求分发给相应的Handler进行处理。

        HandlerAdapter:指定如何执行处理器方法并将其结果返回给DispatcherServlet。一个处理器可能有多个HandlerAdapter,用来支持不同的方法返回类型。

        ViewResolver:负责将逻辑视图名称解析为View对象,Spring MVC框架默认提供了多种ViewResolver实现,如InternalResourceViewResolver、JstlView等。

        ModelAndView:包含处理器返回结果以及视图名称等信息,被DispatcherServlet使用来选择对应的视图渲染器进行渲染。

Spring两大核心技术是什么

        IOC和AOP

简单描述对IOC和AOP的理解

        IOC/DI:即控制反转,是一种设计模式,它可以通过将对象之间的依赖关系交给容器来管理,实现松耦合和模块化,使得代码的可维护性和可测试性得到大幅度提升。

        AOP:即面向切面编程,是一种编程思想,它能够将程序中的横切关注点(如日志、事务、安全等)与业务逻辑进行有效的解耦,提高代码的可维护性、可拓展性和可重用性。

        松耦合是指组件之间的关系程度较低,相互之间的耦合度小,彼此之间的影响较少。在程序设计中,松耦合可以提高系统的灵活性、可扩展性和可维护性。

        具体来说,松耦合可以表现为组件之间接口简单、互相独立、修改某一个组件不会影响到其他组件的运行等特点。相反,紧耦合则表示组件之间关系紧密,一旦其中一个组件发生改变,就会直接影响到其他的组件,导致系统的可维护性、可扩展性较差。

AOP能解决那些问题

        可以解决程序中的横切关注点问题,如日志、事务、安全等。

AOP的优点

     横向抽取机制:AOP能够将与业务无关的横切关注点(如日志、安全等)从业务逻辑中分离出来,形成独立的模块。这样可以降低代码的冗余度,提高代码的可维护性和可测试性。

        松耦合:使用AOP可以让各模块之间实现松耦合,即模块之间的依赖关系较弱,修改某一个模块不会影响到其他模块的运行,从而提高了系统的灵活性和可扩展性。

        集中处理:通过AOP,可以将相同的逻辑集中在一起处理,避免了代码的分散和重复,减少了代码的工作量和复杂度。

        代码重用:AOP中的切面可以被多个对象共享,这样就可以减少代码的复制和粘贴,提高代码的重用性和可维护性。

        总的来说,AOP可以使程序的设计更加模块化和可维护,提高代码的可重用性和可扩展性,对于大型复杂的应用程序设计非常有帮助。

AOP是如何实现的

        动态代理实现,AOP是通过将程序的关注点切面化,并在运行时动态地织入切面来实现的。这种方式使得程序各模块之间的耦合度降低,代码的可维护性和可扩展性提高。

        AOP是通过将程序的关注点切面化来实现的。具体来说,AOP将程序中的关注点分为两个维度:横向关注点和纵向关注点。横向关注点是指程序中多个模块都会用到的功能,如日志、事务、安全等;纵向关注点是指程序中某一个模块内部的逻辑关系,如业务逻辑、数据权限等。

        AOP通过给程序添加一组切面来解决横向关注点的问题。切面是一组横切逻辑,与程序的其他逻辑相互独立,可以被多个程序模块共享。在AOP中,切面可以被动态地织入weave)到程序的不同模块中,从而实现对横向关注点的统一处理。

        AOP的实现方式有多种,其中基于动态代理和字节码增强的方式比较常见。在这些实现方式中,程序的字节码会被修改,在运行时生成一个代理对象或修改原对象的字节码,从而在不修改源代码的情况下实现切面的织入。

        织入(weave)是AOP中的一个术语,指将横向关注点(如日志、事务、安全等)的处理逻辑动态地添加到程序的纵向逻辑中。织入可以发生在编译时、类加载时或运行时,其中运行时织入最为常见。

        在AOP中,织入是通过代理对象或修改字节码实现的,它可以在目标对象的方法执行前后插入特定操作,比如记录日志、进行安全检查或开启事务等。因此,织入使得不同模块之间的关注点得到了统一处理,提高了系统的可维护性和可扩展性。

        对于代理对象,织入通常发生在被代理对象的方法调用前后;对于通过修改字节码实现的增强,则是在目标对象的字节码中插入新的指令以实现织入逻辑。在织入时,需要注意不影响目标对象原有的业务逻辑,并且确保织入的逻辑和顺序正确,否则可能会引起意外错误。

        织入是AOP的核心概念,使得AOP框架能够透明地处理系统的各种横向关注点,提高了系统的可读性、可维护性和可拓展性。

简述Spring中常用的几种Advice注解

        @Around:唯一可以使ProceedingJoinPoint参数来控制流程的advice,在方法执行前拦截,可以在切面逻辑中手动释放拦截,且可以在其后加入逻辑代码,该代码段会在方法执行后执行。

        @Before:在目标方法执行前执行,可以用于实现权限控制、事务管理等。

        @After:在目标方法在目标方法执行后无论是否抛出异常都执行,可以用于释放资源、清理缓存等。

        @AfterReturning:在目标方法执行后返回结果时执行,可以用于修改返回值,记录日志等

        @AfterThrowing:在目标方法抛出异常时执行,可以用于统一处理异常,进行资源回收等。

CGLIB代理和JDK代理的区别

        JDK代理只能对实现接口的类生成代理,JDK代理使用的是反射机制实现AOP动态代理。

        CGLIB是针对类实现代理,对指定的类生成一个子类,并覆盖其中的方法,这种通过继承类的实现方式。CGLIB代理使用字节码处理框架ASM,通过修改字节码生成子类。

@Autowired和@Resource注解的区别

        @Autowired属于Spring框架,默认使用类型(byType)进行注入,按照类型匹配失败,在按照名字ByName匹配;

        @Resource是Java的注解,Spring支持@Resource。而@Resource首选按byName自动注入,如果匹配失败再按照类型byType匹配注入。

        @Resource的作用相当于@Autowired。 @Autowired首选按byType自动注入,而@Resource首选按byName自动注入。

Spring如何解决循环依赖问题

       Spring解决循环依赖的机制基于两个核心原理,提前暴露对象和三级缓存机制。这些机制可以帮助Spring在Bean的创建过程中暴露尚未完成实例化的Bean实力,并通过缓存机制协助完成Bean实例创建的过程,从而解决循环依赖问题。具体处理流程如下:

        1.Spring IoC容器在创建Bean实例时,如果发现存在循环依赖关系,则将正在创建的Bean实例暴露给提前暴露对象的机制,从而提前暴露还未完成实例化的Bean实例

        2.当Bean实例被暴露后,Spring会将其放入三级缓存中的ObjectFactory对象集合中的第一级缓存中

        3.如果依赖于当前Bean实例的其他Bean已经创建,且已经完成属性注入,则Spring会将当前Bean实例的ObjectFactory返回给需要该Bean实例的其他Bean,在它们的初始化过程中使用

        4.如果存在需要往当前Bean实例中注入属性,但是还没有创建的其他Bean,则Spring会将当前Bean实例放入第二级缓存中,表示它已经被创建过,但是这个Bean实例还没有完成完全的初始化

        5.Spring会递归地执行上述操作,知道所有Bean实例都完成创建的过程

        通过以上机制,Spring可以在Bean实例的创建过程中解决循环依赖问题。需要注意的是,如果循环依赖关系比较复杂或者出现了死循环,则Spring可能无法解决循环依赖问题,此时需要重新设计业务逻辑或Spring组件的结构

Spring事务

        Spring框架为事务管理提供了一个一致的抽象,在不同的事务API(JDBC、JPA、MyBatis)中具有一致的编程模型

        支持声明式事务管理,与编程式事务相比,编程式事务管理的API更简单。往往只需要在类或者方法上标注事务注解即可。

        Spring框架的声明式事务管理是通过Spring面向切面编程(AOP)实现的,底层依赖数据库的事务功能

事务管理有两种用法:编程式事务和声明式事务

        编程式事务是通过硬编码的方式使用Spring提供的事务相关类来控制事务。主要分为两种用法:

        通过PlatformTransactionManager控制事务;

        通过TransactionTemplate控制事务。

        其中,PlatformTransactionManager是最原始的方式,代码量较大,后面其他方式都是针对这种方式的封装。在代码中需要手动进行事务管理,即明确指定哪些方法需要事务支持,需要在方法中使用try-catch语句捕获异常并手动回滚事务。

        声明式事务则是通过AOP技术实现事务管理。主要分为两种用法:

        基于XML配置;

        基于注解配置。

        在声明式事务中,事务管理的细节被抽象出来形成了一个横切面,通过AOP将事务管理代码注入到应用程序的业务逻辑中。在代码中不需要手动进行事务管理,只需要标注哪些方法需要事务支持,事务管理的工作由Spring框架在运行时自动完成。

        两种方式的区别在于,编程式事务需要手动实现事务管理,代码量较大,但相对灵活,适用于一些特殊情况。而声明式事务则是通过AOP自动实现事务管理,代码量较少,但相对不够灵活,适用于大多数情况。

事务注解以及作用(@Transactional)

        为单个方法或类上添加事务管理

        标注事务注解的类,其全部方法都有事务

        标注了事务注解的方法,默认情况会开启事务,方法中全部功能执行完成以后,会自动提交事务,默认情况下,如果方法出现了RuntimeException(含子类型)则会回退事务

        Spring框架的声明式事务管理是通过Spring面向切面编程(AOP)实现的,底层依赖数据库的事务功能

Spring常用注解

      声明bean的注解

        @Component组件,没有明确的角色

        @Service在业务逻辑层使用(service层)

        @Repository在数据访问层使用(dao/mapper层)

        @Controller在展现层使用,控制器的声明(controller层)

      注入bean注解

        @Autowired:由Spring提供

        @Resource:由JSR-250提供

      java配置类相关注解

        @Configuration声明当前类为配置类

        @Bean注解在方法上,声明当前方法的返回值为一个bean

        @ComponentScan用于对Component进行扫描

        @EnableAspectJAutoProxy注解开启Spring对AspectJ代理的支持

        @Scope设置Bean的作用域

        @PostConstruct由JSR-250提供,在构造函数执行完之后执行

        @PreDestory由JSR-250提供,在Bean销毁前执行

        @Value为属性注入值

        @PropertySource加载配置文件

        @EnableScheduling在配置类上使用,开启计划任务的支持

      切面(AOP)相关注解

        @Aspect声明一个切面。AspectJ的注解

        @Before在方法执行之前执行(方法上)

        @After 无论是否有异常之后都会执行(方法上)

        @AfterThrowing 在方法执行出现异常之后执行(方法上)

        @AfterReturing 在方法正常执行之后执行(方法上)

        @PointCut声明切点

        @Order指定多个切面的优先级,数值越小越先执行;

      测试相关注解

        @SpringBootTest

JSR-250,全称为Java Specification Request 250,是Java平台通用注解的一部分,旨在定义一组注解来表达常见的语义概念,以避免在Java EE和Java SE组件之间出现冗余的重复注解。JSR-250广泛应用于Java EE技术栈中的各种组件,如EJB3、Servlet、JSP等。常见的JSR-250注解包括:

  • @PostConstruct:在依赖注入完成后执行,用于初始化对象;
  • @PreDestroy:在对象销毁前执行,用于清理资源;
  • @Resource:用于依赖注入,可以指定注入的名称和类型等信息;
  • @RolesAllowed:用于声明访问方法所需要的权限角色。

关注业务逻辑而非底层细节。除此之外,JSR-250还提供了一些注解用于管理事务、处理异常等方面的功能。

@PropertySource是Spring框架中的一个注解,用于引入外部的.properties或者.yml文件,将其中的属性值注入到Spring容器中的Environment对象中。

具体来说,我们可以在一个Java配置类上添加@PropertySource注解,指定外部属性文件的位置。例如:

@Configuration

@PropertySource("classpath:/com/example/app.properties")

    publice class AppConfig{ // .....}

这段代码表示在classpath中搜索名为app.properties的文件,并将其中的属性值加载到Spring容器的Environment对象中。

需要注意的是,如果在多个@PropertySource注解中使用同名的属性,最后一个注解中定义的属性值将被使用覆盖之前的值。

@PropertySource注解还有一些其他的属性,例如:

  • value:外部属性文件的位置,支持读入多个文件,可以使用数组的形式;
  • name:用于设置properties文件的名称,与value属性二选一;
  • encoding:指定properties文件的编码方式,默认为UTF-8;
  • ignoreResourceNotFound:是否忽略找不到的资源文件,默认为false。

@EnableScheduling是@Spring框架中的一个注解,用于开启定时任务的支持。当我们在Spring Boot应用中使用@Scheduled注解定义定时任务时,必须在配置类上添加@EnableScheduling注解才能使定时任务生效。

具体来说,@EnableScheduling注解会开启一个后台线程池,用于执行被@Scheduled注解的方法。需要注意的是,它仅适用于当前的应用程序上下文,如果有多个应用程序上下文,则需要在每个上下文中重新声明@EnableScheduling注解以启用定时任务。

以下是一个示例代码:

@Configuration

@EnableScheduling

   publice class AppConfig{ // .....}

依赖注入的三种方式

        属性注入:通过直接给字段赋值来设置依赖对象,即先创建实例后再直接赋值。此方法存在被误用或滥用的风险,不建议使用。

        构造器注入:通过构造函数参数传递依赖对象,即将所有必需的依赖关系都声明在构造函数参数中。此方法使得创建实例时就已经建立了完整的依赖关系,从而确保了依赖的完整性和一致性。

        setter方法注入:通过提供Setter方法来设置依赖对象,即先创建实例后再通过Setter方法来设置依赖对象。此方法使得对依赖对象的更新更加灵活,缺点是存在可能某个依赖未被设置的情况。

Spring中Bean作用域

        singleton:单例模式,全局有且仅有一个实例

        prototype:原型模式,每次获取Bean时都会创建一个新的实例

        request:Web请求作用域,每个HTTP请求都会创建一个新的实例

        session:Web会话作用域,同一个HTTP Session共享一个实例

        globalSession:全局会话作用域,只在基于portlet的Web应用中使用,它表示全局唯一的Portlet会话

        在使用@Scope注解时,常用的属性包括value和proxyMode。其中,Value属性用于指定Bean的作用域范围,而proxyMode属性则用于指定使用哪种作用域代理。

@Scope注解是Spring IoC容器中的一个作用域,可以用于指定Bean在容器中的生命周期。具体来说,在 Spring IoC 容器中,@Scope注解提供了以下几种作用域范围:

        singleton:单例模式,全局有且仅有一个实例;

        prototype:原型模式,每次获取Bean时都会创建一个新的实例;

        request:Web请求作用域,每个HTTP请求都会创建一个新的实例;

        session:Web会话作用域,同一个HTTP Session共享一个实例;

        globalSession:全局会话作用域,只在基于portlet的Web应用中使用,它表示全局唯一的Portlet会话。

除了以上标准的作用域外,我们还可以通过自定义作用域来扩展@Scope注解的使用范围。

在使用@Scope注解时,常用的属性包括value和proxyMode。其中,value属性用于指定Bean的作用域范围,而proxyMode属性则用于指定使用哪种作用域代理。

Spring MVC、Spring Cloud、Spring Boot的区别

        Spring MVC是Spring的一个模块,一个web框架,它提供了丰富的功能和灵活性,包括:请求分发、请求参数解析、视图渲染等。Spring MVC的目标是为了实现Web应用程序的开发,使得开发者可以快速构建灵活的Web应用程序。

        Spring Cloud是一个开源的微服务框架,主要用于构建分布式架构中的微服务应用。它提供了一系列的工具和组件,帮助开发者解决了很多分布式开发中的常见问题,例如:服务注册与发现、配置中心、负载均衡、断路器、网关等。Spring Cloud支持多种开发语言和服务注册中心,如Eureka、Consul、ZooKeeper等

        Spring Boot是一个可以快速构建独立应用程序的框架。它为Spring框架的使用者提供了一种更快速、更简单的方式来构建Spring应用程序。它利用自动配置和约定优于配置的方式,帮助开发者省去了很多繁琐的配置工作。Spring Boot配合Spring Cloud使用可以快速搭建微服务架构。

        Spring MVC主要用于Web应用程序开发;Spring Cloud是构建分布式微服务应用的框架;Spring Boot是一个快速构建独立应用程序的框架,也可以用来与Spring Cloud搭配构建微服务。

Spring和Spring Boot的区别

    Spring:

        Spring 框架提供了企业软件的各种基础组件,有了这些基础组件的帮助,开发者就可以更多的聚焦在软件的业务功能,大大提升开发效率。

        Spring 的核心功能包括:IoC/DI(依赖注入、控制反转) 和 AOP(面向切面编程)

        Spring 还提供了:事务管理、MVC、测试、数据访问等组件

    SpringBoot:

        Spring Boot是以Spring为基础,帮助快速搭建Spring应用程序。开箱即用,几乎不用配置

        Spring Boot提供了统一的依赖管理,可以很少代码就能整合各种资源,包括JDBC、MyBatis等

        Spring Boot提供了内嵌服务器、安全健康检查等开箱即用的功能

        Spring Boot还提供了打包工具,可以将应用打成Fat Jar,然后一个命令就能启动

Spring和Spring Boot的区别如下:

  • Spring是一个综合性的框架,提供了很多核心特性和扩展功能,如IoC、AOP、MVC、JDBC等,并可以与其他框架集成使用,如Hibernate、MyBatis、Struts等。
  • Spring Boot是在Spring基础之上构建的快速开发框架,通过自动化配置、内嵌服务器等特性,简化了Spring应用程序的初始化配置、开发以及部署过程。相比于Spring,Spring Boot更加轻量级,注重约定优于配置,提供了更加便捷和快速的开发方式。

总的来说,Spring Boot是在Spring基础之上提供了更加便捷、快速、轻量级的开发方式,能够大大提高开发效率和代码质量。

Spring Boot自动配置原理

        @EnableAutoConfiguration会读取工厂配置        /META-INF/spring.factories

        找到标注@Configuration的自动配置类

        自动配置类中使用@ConditionalXXX注解,进行条件配置,根据条件初始化Bean组件

        可以根据属性文件、Bean对象、Bean类型自动配置

        Spring Boot会在classpath下查找META-INF/spring.factories文件,并将其中所有EnableAutoConfiguration指定的配置类读取到spring容器中。

        在应用启动时,Spring Boot会通过SpringBootApplication注解中的@ComponentScan扫描所有的 @Configuration 配置类 。

        当Spring Boot需要某个服务(例如数据库),但用户没有配置时,Spring Boot会根据依赖关系,自动添加默认的配置。

        自动配置类通常使用@Conditional注解来判断特定的条件是否成立,从而决定是否启用该自动配置类。

        用户可以通过自定义的配置覆盖默认的自动配置,只需提供自己的@Configuration类即可。

        综上,Spring Boot自动配置的原理就是,在程序启动时,根据classpath下的META-INF/spring.factories文件中的配置和用户配置的内容,判断应用所需的服务是否已经配置,如果没有则自动添加默认的配置,然后将所有@Configuration类加载到Spring容器中以供使用。这种自动化的配置方式,大大降低了应用的配置复杂度,并且可以使开发者更加专注于业务逻辑的实现

Spring MVC的设计理念

        MVC是一种使用MVC设计创建Web应用程序的模式

        Model表示应用程序核心,处理应用程序数据逻辑的部分

        View显示数据

        Controller处理输入与交互流程

Spring MVC的处理流程

        1.用户发送请求至前端控制器DispatcherServlet

        2.DispatcherServlet收到请求调用处理器映射器HandlerMapping

        3.处理器映射器根据请求url找到具体的处理器,生成处理器执行链HandlerExecutionChain(包括处理器对象和处理器拦截器)一并返回给DispatcherServlet

        4.DispatcherServlet根据处理器Handler获取处理器适配器HandlerAdapter执行HandlerAdapter处理一系列的操作,如:参数封装、数据格式转换,数据验证等操作

        5.执行处理器Handler(Controller,也叫页面控制器)

        6.Handler执行完成返回ModeAndView

        7.HandlerAdapter将Handler执行结果ModelAndView返回到DispatcherServlet

        8.DispatcherServlet将ModelAndView传给ViewReslover视图解析器

        9.ViewReslover解析后返回具体View

        10.DispatcherServlet对View进行渲染视图(即将模型数据model填充至视图中)

        11.DispatcherServlet响应用户

        用户发送请求到前端控制器DispatcherServlet,前端控制器调用处理器映射器HandlerMapping根据URL找到具体的处理器,生成处理器执行链返回给前端控制器,前端控制器调用处理器适配器HandlerAdapter执行Controller中的方法,返回ModeAndView对象给前端控制器,前端控制器将ModeAndView对象传给视图解析器ViewReslover,视图解析器解析后返回具体的View对象给前端控制器,前端控制器对View进行渲染后响应给用户。

Spring MVC常用注解

        @Controller:用于配合组件扫描(@ComponentScan)创建控制器对象,常与@RequestMapping注解结合使用,其元注解包括@Component

        @RestController:一个方便的注解,它元注解有@Controller和@ResponseBody注解

        @ResponseBody:表明控制器方法的返回值绑定到HTTP响应体

        @RequestMapping:使用@RequestMapping注解来映射请求到控制器方法

        @PostMapping:用于将HTTP POST请求映射到特定的处理方法的注解

        @GetMapping:用于将HTTP GET请求映射到特定的处理方法的注解

        @RequestBody:标注在方法参数上,表示网络请求正文映射到丰富参数

        @RequestParam:将请求参数映射到控制器的方法参数上

        @PathVariable:将请求路径上“URL模板”映射到控制器的方法参数上

        @ResponseStatus:设定HTTP响应状态码

        @RequestHeader:映射请求头到控制器方法参数

如何处理get请求

        @GetMapping:用于将HTTP GET请求映射到特定的处理方法的注解

        @RequestMapping:使用@RequestMapping注解来映射请求到控制器方法,添加请求方式属性

Spring Validation

        Spring Validation是Spring Framework提供的一种轻量级的校验框架,用于检验Java Bean对象中的属性是否符合要求。通过注解、API等方式来定义对象属性校验规则,并提供统一的校验方法进行处理。

        使用Spring Validation可以有效地避免因代码逻辑不当或数据异常导致系统出现错误。在Spring Boot中,Spring Validation的默认实现是Hibernate Validator。

常见的使用方式:

        在Java Bean对象属性上添加注解,例如@NotNull、@Size等,来定义属性校验规则

        在Controller层的方法中,利用@Valid或@Validated注解对参数进行校验

        自定义校验器,通过实现ConstraintValidator接口,定义自己的校验规则

注意:在使用Spring Validation时,需要确保Bean对象实现了Serializable接口,否则在分布式环境下可能会出现序列化错误

        在配置类中配置快速失败,Spring Validation框架执行检查时,即使存在多个错误,当检查到第一个错误时,就会停止检查,并反馈错误

Spring Security

        Spring Security是一个基于Spring Framework的强大且高度可定制化的身份验证和访问控制框架。它提供了全方位的安全管理,并结合了诸多安全措施,使得应用程序可以进行安全扩展、集成和部署。Spring Security的目标是为了Spring应用程序提供全面的安全解决方案。

        Spring Security可以被用来保护Web应用程序、RESTful API、方法调用等各种形式的Java应用程序

  Spring Security的核心组件:

        身份验证:主要负责用户的认证,也就是验证用户的身份是否合法

        访问控制:主要负责对用户进行访问权限的控制,有哪些资源可以被访问或操作,哪些资源不能被访问或操作

        安全事件:负责监控Spring Security中发生的重要事件,如登录成功、登录失败、会话过期等,从而确保系统的安全性和完整性

     --Spring Security通常需要与其他安全框架一起使用,例如OAuth2、OpenID Connect等,以实现更加复杂的安全方案。在Spring Boot中,Spring Security已经预装并配置好,只需要稍作修改即可使用。

基于Spring Security与JWT的单点登录

        具体实现:Spring Security框架是根据SecurityContext中的Authentication对象来处理认证的,所以,要想Spring Security识别用户的身份,必须将相关信息创建为Authentication对象,然后存入到SecurityContext中;JWT与传统的Session不同,它本身可以解析出有意义的数据;在开发时,应该在验证用户登录成功后,将用户的相关信息用于生成JWT数据,然后响应到客户端,并且,用户在后续的访问过程中,应该携带JWT数据,服务器端就可以使用Filter组件接收到JWT数据,并解析出用户身份相关的信息,用于创建Authentication对象,最终将此对象存入到SecurityContext中。

RESTful

        RESTful API是一种基于HTTP协议的Web服务接口,它具有高度的灵活性和可扩展性,且易于集成和部署

        RESTful是一种基于HTTP协议设计和实现Web服务的架构风格。RESTful API提供了一种通用的Web服务接口,使得客户端可以通过HTTP协议发送请求,从而与服务器进行数据交换,实现资源的增、删、改、查等操作

        常见的RESTful API使用JSON或XML等格式的数据进行通信。客户端通过向RESTful API 发送请求发起操作,例如GET请求可以获取资源,POST请求可以创建新的资源,PUT请求可以修改资源,DELETE请求可以删除资源

    RESTful API的设计理念:

        使用HTTP协议:RESTful API使用HTTP协议定义资源的访问方式,使得客户端可以通过标准的HTTP方法进行操作

        资源的唯一标识符(URL):客户端与服务器都有一个唯一的URL,客户端通过URL访问和操作资源

        表示层状态转化(REST):客户端与服务器之间的交互,不应该保存任何会话状态,每次请求都包含所有必要的信息。服务器对请求进行处理后,需要将资源的最新状态返回给客户端

        统一接口:RESTful API应该提供统一的接口定义,使用标准HTTP方法与状态码,以达到简单、可预测、易于理解的效果

MyBatis #{}和${}的区别

        #{}是预处理,${}是字符串替换

        MyBatis处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法赋值

        MyBatis处理${}时,就是把${}替换成变量的值,也就是字符串拼接,字符串拼接存在SQL注入风险

        在MyBatis中,#{}和${}都是用于占位符的语法。(语法分析、语义分析、编译、执行)

  #{}是预编译。会将参数值作为一个占位符传入SQL语句,MyBatis底层会使用PreparedStatement的setXXX方法来设置参数值,可以有效防止SQL注入攻击;

  ${}不是预编译的。会将参数值直接拼接到SQL语句中,可能存在SQL注入风险。如果需要表示某个部分只是字段的值,需要使用一对单引号将它框住('${}')。

  #{}可用于任何SQL语句中,包括动态SQL中的if、choose等标签,而${}仅仅适用于普通SQL语句。

在MyBatis中,当需要拼接的变量不能带单引号时,必须使用${},比如:

        当SQL中表名或列名是通过参数传递进来时,使用${}

        在order by排序语句中,因为order by后面必须跟字段名,而字段名不能带引号

        在动态SQL语句中,如果需要将参数直接拼接到SQL语句中,则也需要使用${}

MyBatis如何防止SQL注入

        使用预处理语句(#{}):MyBatis底层使用JDBC进行数据库连接和操作,在进行SQL语句的预编译时,会自动将输入参数中的特殊字符进行转义,从而避免SQL注入攻击的发生。

        使用OGNL表达式:MyBatis内置了一种表达式语言OGNL,用于对Java对象进行操作。在使用OGNL表达式时,MyBatis会自动将输入参数中的特殊字符进行转义,从而保证SQL语句的安全性。

        使用参数映射:MyBatis可以将输入参数映射为Java对象,并使用其属性值作为SQL语句的参数,从而避免手动拼接字符串的风险。

        使用动态SQL:MyBatis的动态SQL语句可以根据不同的条件拼接出不同的SQL语句,从而避免手动拼接字符串的风险。同时,MyBatis可以自动进行参数类型转换和转义,保证SQL语句的安全性。

MyBatis的一级缓存二级缓存

        MyBatis一级缓存是SqlSession级别的缓存,当用户发起查询时,MyBatis先在Local Cache进行查询,如果缓存命中的话,直接返回结果给用户,如果缓存没有命中的话,查询数据库,结果写入Local Cache,最后返回结果给用户。MyBatis的一级缓存是默认开启的,作用是提高查询效率,减少对数据库的访问,从而提升系统的性能。

        MyBatis二级缓存是全局缓存,被多个SqlSession共享数据,减少重复查询的开销,提高系统的性能。二级缓存默认是不开启的,需要手动配置。通过在Mapper.xml文件中添加<cache>标签开启二级缓存。开启二级缓存后,数据查询执行的流程就是二级缓存->一级缓存->数据库。二级缓存的生命周期是应用程序的整个运行周期,它会将查询结果缓存到内存中,以减少对数据库的访问。

两者的区别

        作用范围不同:一级缓存的作用范围是在同一个SqlSession中共享数据,而几乎缓存的作用范围是在多个SqlSession之间共享数据

        存储位置不同:一级缓存是存储在SqlSession对象中的,而二级缓存是存储在SessionFactory对象中的。

        缓存数据的有效性不同:一级缓存的有效性仅限于同一个SqlSession当中,而二级缓存的有效性可以跨多个SqlSession,因此需要保证缓存数据的一致性和及时性。

        总的来说,MyBatis的一级缓存主要是为了减少数据库的访问次数,提高查询效率;而二级缓存是为了实现数据的共享,在多个SqlSession之间共享数据,以提高系统的性能。

MyBatis如何不走一级缓存

        禁用一级缓存:MyBatis没有提供一级缓存的启用、禁用开关,但是在Mapper文件对应的语句中增加flushCache="true",表示执行该操作时清空缓存,同时还会加上userCache="false",表示禁用该操作的缓存

简述MyBatis的单个参数,多个参数如何声明

        单个参数,直接在SQL语句中使用#{参数名}的占位符即可,在执行时会把参数值替换到占位符中。

       多个参数:

        1.匿名参数:按照参数在方法中出现的顺序,一次加上#{0},#{1}等占位符来引用参数值

        2.使用@Param注解:在方法参数前使用@Param("参数名")注解来为参数命名,然后在SQL语句中使用#{参数名}占位符来引用参数值

        3.实体类封装参数:将参数封装成一个实体类,在SQL语句中使用#{实体类属性名}占位符来引用参数值

        4.Map集合:将参数封装成一个Map,在SQL语句中使用#{Map键名}占位符来引用参数值

MyBatis如何完成批量操作,举例说明

        基于Java代码的批量操作:通过SqlSession提供的insert()、update()、delete()方法来实现批量操作。这些方法有两个重载版本,一个是只接受单个参数,另一个是接受Collection类型的参数。

        基于Mapper XML的批量操作:借助MyBatis提供的foreach标签,讲一个集合中的元素动态地拼接成多个SQL语句进行批量操作

MyBatis缓存优先级

        二级缓存->一级缓存->数据库

MyBatis和MyBatis plus的区别

        MyBatis是一个开源的基于Java的持久化框架,主要用于数据库访问,在SQL映射配置文件或注解中配置SQL语句,可以灵活地实现SQL查询、插入、更新、删除等操作,还支持高级映射、存储过程和自定义SQL等特性。

        MyBatis-plus则是在MyBatis框架的基础上进行了二次封装,提供了一些更加便捷的操作方式和内置的常用功能模块。比如分页查询、条件构造器、自动填充、性能分析器等。

        MyBatis更注重灵活性和自由度,需要自行编写SQL语句,MyBatis-plus则更注重便捷性和开发效率,提供了许多实用的功能模块,适合开发速度较快、业务逻辑简单的项目。

MyBatis如何实现分页

        limit实现分页:使用SQL语句的limit关键字指定查询结果的偏移量和限制数量。

        RowRounds实现分页:在查询SQL后添加limit限制语句,通过RowRounds参数来指定limit的偏移量和取值个数,实现分页查询

        MyBatis分页插件PageHelper实现分页:通过拦截器机制,拦截SQL语句中的select操作,对其进行重写,从而实现分页查询功能

        PageHelper 在拦截 SQL 语句时,会解析 SQL 语句中的参数,获取分页相关的信息(如当前页码、每页记录数等),并基于这些信息生成重写后的 SQL 语句。在生成 SQL 语句时,PageHelper 会将 select 操作的结果集限定在指定的分页范围内,并且将总记录数作为返回值传递给应用程序。

物理分页:通过在SQL语句中添加ROWNUM、LIMIT或TOP等关键字进行分页

逻辑分页:通过Java代码中根据分页参数手动处理分页逻辑来实现

游标分页、滚动分页、哈希分页、内容分页、时间分页、基于数据量的分页、基于搜索的分页、基于位置的分页、基于标记的分页、基于主键范围的分页

写过原生的分页吗?用过什么插件吗?分页插件的原理?

        原生分页就是利用MySQL的limit实现分页

        通过MyBatis分页插件PageHelper实现分页

        PageHelper通过MyBatis拦截器实现的分页,核心类是PageInterceptor

MyBatis延迟加载

        MyBatis的延迟加载就是按需查询,在需要的时候进行查询。

        在MyBatis的属性中配置:将lazyLoadingEnable设置为true表示开启延迟加载,没认为false。将aggressiveLazyLoading设置为false表示按需加载,默认为true

JDBC和MyBatis的区别

        JDBC是java提供的操作数据库的API,JDBC的弊端就是编程工作量相对较大且繁琐

        MyBatis是支持普通SQL查询,存储过程和高级映射的持久层的框架。MyBatis封装了JDBC API,能够通过反射将JDBC与Java对象映射,基本不用JDBC代码

        由于采用反射进行映射,MyBatis性能比原生JDBC API略慢

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值