上一篇传送门:点我
由于Spring通常是和SSM组合起来的,所以本文将会从Spring出发,记录Spring以及一些其他相关框架的知识点。
什么是 Spring 框架
Spring 是一个轻量级的 JavaEE 框架,它通过依赖注入和面向切面编程,使得开发者更专注业务逻辑的实现,而无需关注过多底层细节。
Spring是如何简化开发的?
- 基于POJO的轻量级和最小侵入性编程
- 通过依赖注入和面向接口实现松耦合
- 基于切面和惯例进行声明式编程
- 通过切面和模板减少样板式代码
什么是Spring MVC?
Spring MVC是属于Spring framework生态下的一个模块,它是一个在servlet基础上构建,并且使用了MVC模式的Web框架,它的主要目的是为了去简化传统的Servlet+JSP模式下的Web开发方式。
其次,Spring MVC的整个架构设计是对Java Web中的MVC框架模式做了一些增强和扩展:
1.把传统MVC框架中的Controller控制器做了拆分,分成了前端控制器DispatcherServlet和后端控制器Controller;
2.把Model模型拆分成了业务层Service和数据访问层Repository;
3.在视图层,可以支持不同的视图,如Freemark、veelocity、JSP等等。
可以看出,Spring MVC就是天生为了MVC模式而设计的,使用Spring MVC开发MVC应用会相对更加灵活。
Spring MVC的执行流程是什么?
1.用户发起请求,请求先被Servlet拦截转发给Spring MVC框架。
2.Spring MVC里面的DispatcherServlet核心控制器会接收到请求,并将请求转发给HandlerMapping。
3.HandlerMapping负责解析请求,根据请求信息和配置信息找到对应的Controller类,不过这里如果有配置拦截器,就会按照顺序执行拦截器里面的preHandle方法。
4.找到匹配的Controller以后,把请求参数传递给Controller里面的方法。
5.Controller中的方法执行完以后,会返回一个ModelAndView,这里面会包括视图名称和需要传递给视图的模型数据。
6.视图解析器根据名称找到视图,然后把数据模型填充到视图里面再渲染成Html内容返回给客户端。
Spring Boot 相较于 Spring 有什么区别
Spring boot 是一个基于 spring 框架的开发框架,旨在简化 spring 程序搭建和部署。首先,spring boot 采取约定优于配置这样一个理念,这大大简化了 spring 应用程序的搭建和维护。约定优于配置也就是使用约定规则来自动配置,使得开发者不需要进行繁琐的 xml 配置, 从而关注于业务逻辑设计。其次 spring boot 内置了常用的应用服务器,使得项目部署方便。Springboot 还提供了大量的 starters 组件(开箱即用的依赖包),方便集成各种常用的框架和中间件,比如说 redis 、消息队列等。
说说SpringBoot的启动原理
1.加载配置文件与启动类:当SpringBoot项目启动时,它会首先读取项目中的配置文件,如application.yml或application.properties。这些配置文件指定了项目的各种配置信息,如启动端口号、数据库连接等。同时,SpringBoot会加载带有@SpringBootApplication注解的启动类。
2.初始化Spring容器:在加载完配置文件与启动类之后,SpringBoot通过Spring框架来初始化Spring容器。这个过程中,它会根据配置文件中的信息注册bean,创建bean实例,并完成依赖注入等操作。
3.开启自动配置功能:SpringBoot会自动扫描项目中的类,如果这些类中有@Configuration注解,SpringBoot会读取这个类中被@Bean注解标记的方法,从而生成Bean实例并注入到Spring容器中。这是SpringBoot自动配置功能的一部分,它大大简化了开发者的配置工作。
4.启动内嵌的Web服务器:SpringBoot内置了Tomcat、Jetty等Web服务器。在项目启动时,它会根据配置文件中的信息自动创建相应的Web容器,并将Spring容器注册到Web容器中。这使得SpringBoot应用程序可以直接以Web应用程序的形式运行。
5.启动SpringBoot应用程序:最后一步是启动SpringBoot应用程序。它会根据之前的启动步骤创建好的Spring容器以及Web服务器,启动相应的线程进行服务处理。
6.监听应用程序的状态:在应用程序运行过程中,SpringBoot还会监听应用程序的状态,并根据需要进行相应的操作。例如,当应用程序退出时,它会打印出详细的日志信息,并将应用程序的上下文环境恢复到初始状态。
谈谈SpringBoot中的自动装配机制
自动装配简单来说就是SpringBoot会自动去把第三方组件的bean装载到IOC容器中,不需要开发人员再去写bean相关的配置。
在SpringBoot中,只需要在启动类上加上 @SpringBootApplication注解就可以实现自动装配。@SpringBootApplication注解是一个复合注解,而真正实现自动装配功能的注解是 @EnableAutoConfiguration。
自动装配的实现主要依靠三个关键技术:
1.引入Starter启动依赖组件的时候,这个组件必须要包含一个Configuration配置类,在这个配置类里面需要通过@Bean注解声明需要装配到IOC容器里面的Bean对象;
2.这个配置类是放在第三方的jar包里面,然后通过SpringBoot中约定优于配置的理念,把这个配置类的全路径放在classpath:/META-INF/spring.factories文件里面,这样Spring就可以知道第三方jar包里这个配置类的位置,这一步骤主要是用到了Spring中的SpringFactoryLoader来完成的;
3.Spring拿到所有第三方jar包声明的配置类以后,再通过Spring提供的ImportSelector接口来实现对这些配置类的动态加载,从而完成自动装配的动作。
如何理解SpringBoot中的Starter组件?
Starter组件是SpringBoot中的一个核心功能特性之一,它的主要作用有以下几点:
1.Starter组件是以功能为维度,来维护对应jar包的版本依赖的,那么开发者就可以不需要去关心版本冲突这种容易出错的细节;
2.Starter组件会把对应功能的所有jar包依赖全部导进来,从而避免开发者自己去引入依赖带来的一些麻烦;
3.Starter组件内部集成了自动装配的机制,也就是说,程序依赖对应的Starter组件会自动集成到Spring的生态里面,并且对于相关Bean的管理,也是基于自动装配机制来完成的;
4.依赖Starter组件以后,这些组件对应的功能所需要维护的外部化配置会自动集成到SpringBoot里面,我们只需要在application.proporties文件里面去进行维护配置就好了,比如说Redis的Starter,只需要在application.proporties这个文件里面去维护redis的连接信息就可以直接使用了。
如何理解 Spring IOC?
Spring IOC 指的是控制反转,这是一种设计思想,将对象的创建和管理的控制权从应用程序代码中反转到 Spring容器(包含并管理应用对象的生命周期,就好比用桶子去装水,Spring就是桶子,而对象就是水)中,如此由Spring创建和管理的对象即被称为Bean。这样做的好处是,我们解除了对对象创建和管理的责任,只需关注业务逻辑的实现(解耦)。容器负责确保对象的创建和组装,保证它们在需要时可用,并且可以灵活地配置和管理对象的行为。
说说Spring IOC的工作流程
IOC的全称是Inversion Of Control,即控制反转。它的核心思想是把对象的管理权限交给了容器,应用程序如果需要使用某个对象的实例,那么直接从IOC容器里面获取就可以了,这种设计的好处在于降低了程序里面对象与对象之间的耦合性,使得程序的整个体系结构变得更加地灵活。
Spring里面提供了很多的方式去声明一个Bean,比如在xml配置文件里面,通过<bean>的标签,或者通过 @Component注解,又或是在Configuration配置类里通过 @Bean注解去声明等等。Spring在启动的时候会去解析这些Bean,然后保存到IOC容器里面。
Spring IOC的工作流程大致可以分为以下三个阶段:
第一个阶段是IOC容器的初始化阶段。这个阶段主要是根据程序里面定义的xml或者注解等Bean的声明方式,通过解析和加载后生成BeanDefinition,然后把BeanDefinition注册到IOC容器里面。通过xml或注解声明的bean,都会解析得到一个BeanDefinition实体,这个实体里面会包含bean的一些定义和一些基本属性。最后把这个BeanDefinition保存到一个Map集合里面,从而完成IOC的初始化。IOC容器的作用就是对这些注册的Bean的定义信息进行处理和维护,它是IOC容器控制反转的核心。
第二阶段是完成Bean的初始化和依赖注入。Spring会通过反射去针对没有设置lazy-init属性的单例bean进行初始化,同时也会完成Bean的依赖注入。
最后一个阶段是Bean的使用。我们可以通过@Autowired或@Resource注解,又或者是通过@BeanFactory.getBean()从IOC容器中去获取一个指定Bean的实例,另外针对设置了lazy-init属性以及非单例Bean的实例化,是在每一次获取Bean对象的时候,调用Bean的初始化方法来完成实例化的,并且Spring IOC容器不会去管理这些Bean。
讲讲依赖注入(DI)
依赖注入(DI)可以看作是Spring IOC的一种具体实现。它指的是创建被调用者的工作不再由调用者来完成,而是交由外部的容器来完成。容器会负责创建和管理这些对象,并在需要时将它们注入到调用者中。
依赖注入有两种主要方式:设值注入(setter注入)和构造器注入。设值注入是容器通过调用无参构造器或无参static工厂方法实例化bean之后,调用该bean的setter方法,即实现了设值注入;而构造器注入则是通过容器触发一个类的构造器来实现的,该类有一系列参数,每个参数代表一个对其他类的依赖。设值注入由于是用setter方法注入,所以相比于构造器注入更加灵活。
什么是Spring的循环依赖?Spring是如何解决循环依赖问题的?
Spring的循环依赖是指一个或多个bean实例之间存在直接或间接的相互依赖关系,构成了循环调用。循环依赖通常表现为互相依赖、间接依赖、自我依赖三种形态。
Spring设计了三级缓存来解决循环依赖的问题。第一级缓存里面会存储已经完全初始化的完整bean实例,这些实例可以直接被使用;第二级缓存里面存储的是已经实例化但还没有依赖注入的bean实例;第三级缓存是用来存储bean工厂的,它主要用来生成原始bean对象并放到第二个缓存里面。三级缓存的核心思想是把bean的实例化和bean中的依赖注入进行分离,采用一级缓存存储完整的bean实例,采用二级缓存存储不完整的bean实例,通过不完整的bean作为突破口从而解决循环依赖的问题。至于第三级缓存则主要是解决代理对象的循环依赖问题。
如何理解 Spring AOP
Spring AOP 可以让你通过给现有代码添加切面,实现额外的功能和行为,而不需要修改原有的代码,从而提高了代码的重用性、可维护性和可扩展性。假设有一个方法用于处理用户登录的逻辑,现在,你希望在每次用户登录前后记录日志。使用 Spring AOP,你可以创建一个切面,其中包含了记录日志的逻辑。然后,你只需要告诉 Spring,在哪些地方需要应用这个切面,比如在用户登录方法上。SpringAOP 会自动在用户登录方法执行前后,执行你定义的切面逻辑,从而实现了日志记录的功能,而不需要修改原有的用户登录方法。
Spring AOP and AspectJ AOP 有什么区别?AOP 有哪些实现方式?
AOP实现的关键在于代理模式,AOP代理主要分为静态代理和动态代理。静态代理的代表为AspectJ;动态代理则以Spring AOP为代表。
(1)AspectJ是静态代理的增强,所谓静态代理,就是AOP框架会在编译阶段生成AOP代理类,因此也称为编译时增强,他会在编译阶段将AspectJ(切面)织入到Java字节码中,运行的时候就是增强之后的AOP对象。
(2)Spring AOP使用的动态代理,所谓的动态代理就是说AOP框架不会去修改字节码,而是每次运行时在内存中临时为方法生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法。
JDK动态代理和CGLIB动态代理的区别
Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理:
JDK动态代理只提供接口的代理,不支持类的代理。JDK会在运行时为目标类生成一个动态代理类$proxy*.class,该代理类是实现了目标接口的一个类,并且代理类会实现接口中所有的方法进而增强代码,调用时通过代理类先去调用处理类进行增强,再通过反射的方式去调用目标方法,从而实现AOP。
如果代理类没有实现接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。CGLIB的底层是通过ASM(开源的字节码生成库)在运行时动态的生成目标类的代理类(除了代理类还会生成多个其他相关的类,主要是为了增强调用时的效率),代理类会重写父类所有的方法增强代码,调用时先通过代理类进行增强,然后代理类直接调用父类对应的方法进行调用目标方法,从而实现AOP。
- 由于CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,它是无法使用CGLIB去做动态代理的。
- CGLIB除了生成目标子类代理类,还有一个FastClass(路由类),可以(但不是必须)让本类方法调用进行增强,而不会像jdk代理那样,本类方法调用增强会失效。
谈谈Spring的AOP的底层实现原理
Spring AOP底层的实现主要依赖于动态代理技术,它允许我们在不修改原始业务代码的情况下,对方法进行拦截和增强。具体来说,Spring AOP使用了两种代理方式:JDK动态代理和CGLIB代理。
如果目标对象实现了至少一个接口,Spring AOP会默认使用JDK动态代理。在这种情况下,Spring会为目标对象创建一个实现了相同接口的代理对象。当客户端调用代理对象的方法时,实际上会触发代理对象中的增强逻辑,然后再由代理对象调用目标对象的原始方法。
如果目标对象没有实现任何接口,Spring AOP则会使用CGLIB代理。CGLIB是一个强大的代码生成库,它能够在运行时动态生成目标对象的子类,并作为代理对象。这个子类会重写父类的方法,并在方法调用前后插入增强逻辑。与JDK动态代理不同,CGLIB代理是通过继承而非接口实现的方式来完成代理的。
在Spring AOP中,切面(Aspect)是一个关键概念。切面定义了增强逻辑(Advice)和切点(Pointcut),用于确定在何时何地应用这些增强逻辑。切点表达式被用来匹配目标方法,从而决定是否在目标方法调用时应用某个增强。
总的来说,Spring AOP通过动态代理技术实现了对方法的拦截和增强,使得我们能够在不修改原始代码的情况下为应用程序添加额外的功能,如日志记录、事务管理、安全检查等。这种机制提高了代码的灵活性和可维护性,降低了系统的耦合度。
spring 中 bean 的生命周期是什么?
1.实例化(Instantiation):在这个阶段,Spring 容器创建对象的实例。根据配置和需要,可以使用构造函数或工厂方法来实例化对象。
2. 属性赋值(Property assignment):在实例化完成后,Spring 容器会自动将配置文件中定义的属性值注入到对象中,以完成依赖注入。这可以通过 Setter 方法、字段注入或构造函数注入来实现。
3. 初始化(Initialization):在属性赋值完成后,Spring 容器会调用对象中定义的初始化方法,以执行一些额外的初始化操作。这可以通过实现 InitializingBean 接口或在 XML 配置文件中指定init-method 来实现。
4. 使用(In Use):在对象初始化完成后,Spring 容器将对象置于可用状态,供其他对象或组件使用。在这个阶段,对象可以被其他对象调用和操作。
5. 销毁(Destruction):当 Spring 容器关闭或对象不再被使用时,容器会自动调用对象的销毁方法,以销毁对象并释放相关资源。这可以通过实现DisposableBean 接口或在 XML 配置文件中指定destroy-method 来实现。
Spring中有两个id相同的bean,会报错吗?
在同一个xml配置文件里面,不能存在id相同的两个bean,否则Spring容器在启动时会报错,这是因为id属性表示bean里面的一种唯一标志符号,所以Spring在启动时,会去验证id的唯一性,一旦发现重复就会报错,而这个错误发生在Spring对xml文件进行解析转化为BeanDefinition的阶段。
但是在两个不同的Spring配置文件里面,可以存在id相同的两个bean,IOC容器在加载bean的时候默认会把多个相同id的bean进行覆盖。
在Spring 3.X版本以后,Spring提供了一个**@Configuration注解去声明配置类,然后使用@Bean**注解去实现bean的声明。这种方式完全取代了xml的配置形式,在这种情况下,如果在同一个配置类里面去声明多个相同名字的bean,那么Spring IOC容器在解析的时候只会注册第一个声明bean的实例,后面重复的名字的bean实例就不会再注册了。
谈谈对BeanFactory和ApplicationContext的理解
BeanFactory和ApplicationContext都是Spring的IoC容器的重要组成部分。其中,BeanFactory是Spring的基础设施,提供了最基本的容器功能,主要负责实例化对象和获取对象。它采用的是延迟加载方式,即需要哪个bean时才会进行加载和实例化。这种方式比较轻量级,但在某些情况下可能导致运行时才发现配置问题。
而ApplicationContext则是BeanFactory的扩展和增强,它继承了BeanFactory的所有功能,并提供了更多的企业级服务。与BeanFactory不同,ApplicationContext 在容器启动时就会一次性加载并初始化所有的bean对象 。这样做的好处是可以在启动时就检测出配置问题,但同时也可能占用更多的内存空间和导致程序启动较慢。因此,在实际应用中,我们通常会根据具体需求来选择使用BeanFactory还是ApplicationContext。
谈谈BeanFactory和FactoryBean的区别
BeanFactory是所有Spring Bean容器的顶级接口,它为Spring的容器定义了一套规范,并提供像getBean这样的方法从容器中获取指定的Bean实例。BeanFactory再产生Bean的同时,还提供了解决Bean之间的依赖注入的能力,也就是所谓的DI;
而FactoryBean是一个工厂Bean,它是一个接口,主要功能是动态地生成某一类型的Bean实例,也就是说可以自定义一个Bean并且加载到IOC容器中,在FactoryBean中有一个重要的方法叫getObject(),这个方法是用来实现动态构建Bean的过程。
@Component和@Bean的区别是什么?
1.用途不同:@Component用于标识普通的类,@Bean是在配置类中声明和配置Bean对象;
2.使用方式不同:@Component注解是一个类级别的注解,Spring通过@ComponentScan注解扫描修饰了@Component注解的类,并注册到Spring IOC容器中;而@Bean注解是通过方法级别的注解使用,在配置类中手动声明和配置Bean;
3.控制权不同:@Component注解修饰的类是由Spring框架来创建和初始化的,而@Bean注解则允许开发人员手动控制Bean的创建和配置过程,所以@Bean注解在配置上会相对更灵活一点。
@Resource和@Autowired的区别是什么?
@Resouce和@Autowired都是Spring中用来实现Bean的依赖注入的注解。
@Autowired是Spring里面提供的一个注解,它默认是根据类型来实现bean的依赖注入的,@Autowired中有一个required属性,它的默认值是true,表示的是强制要求bean实例的注入,在应用启动时,如果IOC容器中不存在对应类型的bean,那么启动的时候就会发生报错,但如果不希望去实现自动注入,可以把这个属性设置为 false。其次,如果在Spring IOC容器中存在多个相同类型的bean实例,由于@Autowired注解是根据类型来注入bean实例的,所以Spring容器启动时会提示一个错误(原本只能注入一个单实例,但是在IOC容器中会有多个,从而导致注入失败),针对这个问题可以使用@Primary或@Qualifier这两个注解来解决(@Primary可以在存在多个相同类型bean的时候,优先使用声明了@Primary注解的bean;而@Qualifier注解则类似于条件筛选,它可以根据bean的名字去找到需要装配的目标bean)。
@Resource是JDK里提供的注解,只是Spring在实现上提供了这种注解功能的支持。它的使用方式和@Autowired注解完全相同,最大的差异在于@Resource可以支持ByName和ByType两种注入方式,假设两个属性它都没有配置,则会先根据定义的属性名去匹配,如果没有匹配成功再去根据类型匹配,如果均未匹配到就会发生报错。
总结一下,@Autowired注解是根据类型来匹配的,而 @Resource注解则可以根据name和type来匹配 ,默认是name匹配;@Autowired注解是Spring里定义的注解,而 @Resource是JDK中定义的注解,只是Spring对该注解提供了支持;@Autowired如果需要name匹配的话,则需要配合@Primary或者@Qualifier注解来实现。
为什么Spring不建议使用@Autowired注解?
虽然 @Autowired 是 Spring Boot 中最常用的依赖注入方式之一,但是在实际开发中,建议尽量避免使用 @Autowired,而是使用构造函数注入或者 @Resource 注解注入。
以下是使用 @Autowired 存在的一些问题:
1.不够明确:在使用 @Autowired 进行依赖注入时,Spring 会自动根据类型来匹配 Bean,如果存在多个类型相同的 Bean,就会产生歧义。此时,需要使用 @Qualifier 注解或者 @Primary 注解来指定具体的 Bean。但是,这种方式不够明确,容易出现错误。
**2.难以测试:**使用 @Autowired 进行依赖注入时,需要在测试中手动创建 Bean,并将其注入到测试类中。这种方式比较麻烦,而且容易出现错误。
**3.无法保证依赖注入的顺序:在使用 @Autowired 进行依赖注入时,Spring 会根据 Bean 的创建顺序来注入依赖,这种方式无法保证依赖注入的顺序。
因此,在实际开发中,建议使用构造函数(官方推荐)**注入或者 @Resource 注解注入。这种方式更加明确、易于测试,并且可以保证依赖注入的顺序,所以不建议使用@Autowired实现依赖注入。
@Conditional注解的作用是什么?
@Conditional的作用是为bean的装载操作提供一个条件判断,只有在满足条件的情况下,Spring才会把当前的bean装载到IOC容器里面,而这个条件的实现是我们可以自定义去完成的。可以通过实现Condition接口并重写里面的matches方法去实现自定义的逻辑,所以@Conditional注解增加了bean装配的灵活性,在SpringBoot里面还对@Conditional注解做了进一步的拓展,比如增加了**@ConditionalOnClass、@ConditionalOnBean**等一系列的注解,这使得在开发过程中可以不再去写那些条件判断的逻辑,而可以直接根据本身的语义去完成对应条件的装配。
Spring中使用了哪些设计模式及应用场景
1.工厂模式,在各种BeanFactory以及ApplicationContext创建中都用到了;
2.模板模式,在各种BeanFactory以及ApplicationContext实现中也都用到了;
3.代理模式,Spring AOP利用了Aspectj AOP实现的,Aspectj AOP的底层用了动态代理;
4.策略模式,加载资料文件的方式,使用了不同的方法,比如:ClassPathResource,FileSystemResource,ServletContextResource,UrlResource,但它们都有共同的接口Resource;在AOP的实现中,采用了两种不同的方式,JDK动态代理和CGLIB代理;
5.单例模式,比如在创建bean的时候;
6.观察者模式,Spring中的ApplicationEvent,ApplicationListener,ApplicationEventPublisher;
7.适配器模式,MethodBeforeAdviceAdapter,ThrowsAdviceAdapter,AfterReturningAdapter;
8.装饰者模式,源码中类型带Wrapper或者Decorator的都是。
Spring的事务传播机制是什么?
多个事务方法相互调用时,事务如何在这些方法之间进行传播,Spring中提供了7种不同的传播特性,来保证事务的正常执行:
REQUIRED: 默认的传播特性,如果当前没有事务,则新建一个事务,如果当前存在事务,则加入事务;
SUPPORTS: 如果当前存在事务,则加入该事务,如果不存在事务,则以非事务的方式执行;
MANDATORY: 如果当前存在事务,则加入到当前事务中;如果当前没有事务,则抛出异常;
REQUIRED_NEW: 不管是否存在事务,都会新建一个事务,新老事务相互独立,外部事务抛出异常回滚也不会影响内部事务的正常提交;
**NOT_SUPPORTED:**以非事务方式执行操作,如果当前存在事务,则挂起当前事务;
NEVER: 不使用事务,如果当前事务存在,则抛出异常;
NESTED: 如果当前存在事务,则在当前事务中创建一个新的嵌套事务;如果当前没有事务,则创建一个新的事务。
NESTED和REQUIRED_NEW的区别:
REQUIRED_NEW是新建一个事务并且新开始的这个事务与原有事务无关,而NESTED则是当前存在事务时会开启一个嵌套事务,在NESTED情况下,父事务回滚时,子事务也会回滚,而REQUIRED_NEW情况下,原有事务回滚,不会影响开启新的事务。
NESTED和REQUIRED的区别:
REQUIRED情况下,调用方法存在事务时,则被调用方和调用方使用同一个事务,那么被调用方出现异常时,由于共用一个事务,所以无论是否catch异常,事务都会回滚,而在NESTED情况下,被调用方发生异常时,调用方可以catch其异常,这样只有子事务回滚,父事务不会回滚。
Spring事务的隔离级别有哪些?
Spring中的事务隔离级别就是数据库的事务隔离级别,分为以下几种:
- read uncommitted(读未提交)
- read committed(读已提交)
- repeatable read(可重复读)
- serializable(串行化)
在进行配置的时候,如果数据库和Spring代码中的隔离级别不同,那么以Spring的配置为主。
Mybatis如何实现动态SQL?
MyBatis通过提供一系列的XML标签来实现动态SQL的构造,这些标签允许我们根据参数的不同动态地生成SQL语句。下面是一些主要的动态SQL元素以及它们的作用:
< if > 标签:这是最常用的动态SQL元素。它允许我们根据某个条件来决定是否包含特定的SQL片段。例如,如果查询条件中包含了用户的名字,我们可以使用标签来动态地添加WHERE name = #{name}这个条件。
< choose >、< when >、< otherwise > 标签:这组标签类似于编程语言中的switch-case结构。它们允许我们根据多个条件来选择性地包含不同的SQL片段。每个< when >标签代表一个条件,当该条件满足时,会包含其内部的SQL片段。如果没有任何< when >标签的条件被满足,那么< otherwise >标签内的SQL片段将被包含。
< foreach > 标签:这个标签在处理集合或数组时非常有用,比如在IN查询中。它允许我们遍历一个集合,并为集合中的每个元素生成相应的SQL片段。例如,如果我们有一个用户ID的列表,并且想要根据这些ID来查询用户信息,那么可以使用< foreach >标签来动态地生成WHERE id IN (1, 2, 3, …)这样的条件。
< trim >、< where >、< set > 标签:这些标签在处理一些复杂的SQL语句时非常有用。< trim >标签允许我们去除多余的SQL片段,如多余的逗号或AND/OR操作符。< where >标签会自动处理WHERE关键字和条件的拼接,避免因为动态条件导致的SQL语法错误。< set >标签则主要用于UPDATE语句中,它会自动处理SET关键字和字段更新的拼接。
总的来说,MyBatis的动态SQL功能非常强大且灵活,可以根据不同的业务需求来动态地生成SQL语句。但是,在使用动态SQL时也要注意防止SQL注入等安全问题,确保所有的输入都被正确处理。
Mybats中的#{}和${}有什么区别?
Mybatis中的#{}和${}都是实现动态SQL的方式,通过这两种方式都可以动态地把参数传入到XML里面,在传递以后,在执行操作之前,Mybatis会对这两个占位符进行动态的解析。
#号占位符等同于jdbc里面的?号占位符,它相当于向PreparedStatement中的预处理语句设置参数,而PreparedStatement里面的SQL语句是预编译的,那么SQL语句里面使用的占位符就规定了SQL语句的结构,并且在设置参数的时候,如果有特殊字符,则会自动进行转义,所以#号占位符可以防止SQL注入的情况发生。
而使用 $号的方式传参,相当于直接把参数拼接到了原始的SQL里面,是字符串拼接的方式生成最终SQL语句,Mybatis不会对它进行任何特殊的处理。
所以 $号和 #号最大的区别在于,前者是动态参数,而后者是占位符,动态参数无法防止SQL注入(例如用户端直接在搜索界面输入SQL语句例如‘OR ‘1’ = ‘1’,从而直接绕过身份验证获取敏感数据’)的问题,所以在实际应用里面应当尽可能地使用#号占位符
谈谈你对Spring Security的理解
Spring Security是一个基于Spring框架的开源安全框架,它提供了一套全面的安全解决方案,用于保护Java应用程序的安全性。
Spring Security的主要功能包括身份验证、授权、密码加密、会话管理和安全事件处理等。它可以集成到各种类型的应用程序中,包括Web应用程序、RESTful服务和微服务等。
下一篇传送门: 点我