掘金 后端 ( ) • 2024-04-07 17:01

theme: Chinese-red

描述下Spring Ioc依赖注入,有哪些方式?

构造器依赖注入:构造器依赖注入在容器触发构造器的时候完成,该构造器有一系列的参数,每个参数代表注入的对象。

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

说下对Spring面向切面编程(AOP)的理解?以及常用术语

  • 面向切面编程AOP可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善。

可以和过滤器进行类比来理解AOP,有很多相似点。

  • OOP解决纵向的业务问题,AOP解决横向的问题,比如日志、安全验证、事务、异常等。

相同的代码重复的出现在项目的不同位置,不利于维护。可以将这些功能分别提取出来,由多份变成一份,

然后在编译或者运行时织入到指定的多个位置。

  • Spring底层使用了动态代理模式实现AOP。若目标对象实现了若干接口,Spring 使用JDK的动态代理。

若目标没有实现任何接口,Spring 使用 CGLIB 库生成目标类的子类。还可以配置不管是否实现接口,

都是要CGLIB。

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

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

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

before(前置通知):在一个方法之前执行的通知。

after(最终通知):当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。

after-returning(后置通知):在某连接点正常完成后执行的通知。

after-throwing(异常通知):在方法抛出异常退出时执行的通知。

around(环绕通知):在方法调用前后触发的通知。

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

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

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

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

BeanNameAutoProxyCreator:bean名称自动代理创建器

DefaultAdvisorAutoProxyCreator:默认通知者自动代理创建器

Metadata autoproxying:元数据自动代理织入:将切面和其他应用类型或对象连接起来创建一个通知对象的过程。织入可以在编译、加载或运行时完成。

Spring中常用的设计模式

  • 代理模式——Spring 中两种代理方式,若目标对象实现了若干接口,Spring 使用JDK的java. lang.reflect.Proxy类代理。若目标没有实现任何接口,Spring 使用 CGLIB 库生成目标类的子类。

  • 单例模式——在 Spring 的配置文件中设置 bean 默认为单例模式。

  • 模板方式模式——用来解决代码重复的问题。比如:RestTemplate、JmsTemplate、JpaTemplate。

  • 工厂模式——在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用同一个   接口来指向新创建的对象。Spring 中使用 beanFactory 来创建对象的实例。

简述Spring声明式事务中@Transaction中常用的两种事务传播行为?

通过propagation来执行事务的传播行为

REQUIRED: 使用调用者的事务,如果调用者没有事务,则启动新的事务运行

REQUIRES_NEW: 将调用者的事务挂起,开启新的事务运行。

谈谈你对spring框架的深入理解?

Spring一款容器框架,其核心是IOC和AOP

(1)IOC就是控制反转,指创建对象的控制权转移给Spring框架进行管理,并由Spring根据配置文件去创建实例和管理各个实例之间的依赖关系,对象与对象之间松散耦合,也利于功能的复用。DI依赖注入,和控制反转是同一个概念的不同角度的描述,即 应用程序在运行时依赖IoC容器来动态注入对象需要的外部依赖。

(2)最直观的表达就是,以前创建对象的主动权和时机都是由自己把控的,IOC让对象的创建不用去new了,可以由spring自动生产,使用java的反射机制,根据配置文件在运行时动态的去创建对象以及管理对象,并调用对象的方法的。

(3)AOP,一般称为面向切面,作为面向对象的一种补充,用于将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块,这个模块被命名为“切面”(Aspect),减少系统中的重复代码,降低了模块间的耦合度,提高系统的可维护性。可用于权限认证、日志、事务处理。

AOP实现的关键在于 代理模式,AOP代理主要分为静态代理和动态代理。静态代理的代表为AspectJ;动态代理则以Spring AOP为代表。

说一下Spring中支持的bean作用域?

Spring框架支持如下五种不同的作用域:

singleton:在Spring IOC容器中仅存在一个Bean实例,Bean以单实例的方式存在。

prototype:一个bean可以定义多个实例。

request:每次HTTP请求都会创建一个新的Bean。该作用域仅适用于WebApplicationContext环境。

session:一个HTTP Session定义一个Bean。该作用域仅适用于WebApplicationContext环境。

globalSession:同一个全局HTTP Session定义一个Bean。该作用域同样仅适用于WebApplicationContext环境。bean默认的scope属性是"singleton"。

解释自动装配的各种模式?(扩展)

自动装配提供五种不同的模式供Spring容器用来自动装配beans之间的依赖注入:

no:默认的方式是不进行自动装配,通过手工设置ref 属性来进行装配bean。

byName:通过参数名自动装配,Spring容器查找beans的属性,这些beans在XML配置文件中被设置为byName。之后容器试图匹配、装配和该bean的属性具有相同名字的bean。

byType:通过参数的数据类型自动自动装配,Spring容器查找beans的属性,这些beans在XML配置文件中被设置为byType。之后容器试图匹配和装配和该bean的属性类型一样的bean。如果有多个bean符合条件,则抛出错误。

constructor:这个同byType类似,不过是应用于构造函数的参数。如果在BeanFactory中不是恰好有一个bean与构造函数参数相同类型,则抛出一个严重的错误。

autodetect:如果有默认的构造方法,通过 construct的方式自动装配,否则使用 byType的方式自动装配。

解释Spring框架中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的生命周期结束

简述SpringMVC 的工作原理?(处理请求流程)

(1)用户向服务器发送请求,请求被springMVC 前端控制器 DispatchServlet 捕获;

(2)DispatcherServle 对请求 URL 进行解析,得到请求资源标识符(URL),然后根据该 URL 调用 HandlerMapping将请求映射到处理器 HandlerExcutionChain;

(3)DispatchServlet 根据获得 Handler 选择一个合适的HandlerAdapter 适配器处理;

(4)Handler 对数据处理完成以后将返回一个 ModelAndView()对象给 DisPatchServlet;

(5)Handler 返回的 ModelAndView() 只是一个逻辑视图并不是一个正式的视图, DispatcherSevlet  通过ViewResolver 试图解析器将逻辑视图转化为真正的视图View;

(6)DispatcherServle 通过 model 解析出 ModelAndView()中的参数进行解析最终展现出完整的 view 并返回给客户端;

简述SpringMVC中处理模型数据的两种方式?

使用ModelAndView 作为方法的返回值,将 模型数据  和 视图信息封装到ModelAndView中

使用Map  或者是Model 作为方法的形参.  将模型数据添加到Map或者是Model中.

SpringMVC中如何实现请求域request中传递数据

  • 使用原生API request

  • 使用Model

  • 使用Map

  • 使用ModelMap

  • 使用ModelAndView

注意:传入的Model、ModelMap、Map类型的数的三种方式其实本质上都是 BindingAwareModelMap 类型的,而四种非原生方式底层都调用了原生的request.setAttribute(name,value)。

简述SpringMVC中如何返回JSON数据?

1. 在工程最终加入jackson的jar包

2. 在请求处理方法中,将返回值改为具体返回的数据的类型, 例如  数据的集合类型  List等。

3.在请求处理方法上使用@ResponseBody注解

PageHelper插件是如何使用

拦截器:它自己就在 IOC 容器中,所以可以直接从 IOC 容器中装配组件。

  1. pom.xml引入依赖
    <dependency>
       <groupId>com.github.pagehelper</groupId>
       <artifactId>pagehelper</artifactId>
       <version>5.1.11</version>
   </dependency>
  1. mybatis-config.xml配置分页插件

    在 MyBatis 的配置文件中添加 PageHelper 的插件:

    <plugins>
       <plugin interceptor="com.github.pagehelper.PageInterceptor">
           <property name="helperDialect" value="mysql"/>
       </plugin>
   </plugins>

其中,com.github.pagehelper.PageInterceptor 是 PageHelper 插件的名称,dialect 属性用于指定数据库类型(支持多种数据库)

SpringMVC中如何实现Restful风格的数据传输和接收

  1. web.xml中添加过滤器org.springframework.web.filter.HiddenHttpMethodFilter,负责根据表单项的取值情况将POST请求转换为PUT请求或者DELETE。

  2. 视图中页面上使用Restful的地址提交请求(不管是Ajax还是非Ajax请求均可)。

  3. Controller中方法使用@GetMapping/@PostMapping/@PutMapping/@DeleteMapping指定映射路径,如果包含路径变量使用{}来表示,方法参数前使用@PathVariable注解将路径变量和参数绑定。

简单的谈一下SpringMVC的核心API(核心组件)

  • DispatcherServlet:总控制器

  • HandlerMapping:处理器映射器,建立了请求路径和分控制器方法之间的映射

  • HandlerExecutionChain:总控制器调用HandlerMapping组件的返回值,是一个执行链,不仅有要执行的分控制器方法,还有相应的多个拦截器,组成一个执行链

  • HandlerAdapter:处理器适配器,调用Handler,不是由总控制直接调用的,而是由HandlerAdapter来调用

  • ViewResolver:逻辑视图(result)----->物理视图(/WEB-INF/templates/result.html)

请解释@Autowired注解的工作机制及required属性的作用?

首先会使用byType的方式进行自动装配,如果能唯一匹配,则装配成功,

如果匹配到多个兼容类型的bean, 还会尝试使用byName的方式进行唯一确定.

如果能唯一确定,则装配成功,如果不能唯一确定,则装配失败,抛出异常.

默认情况下, 使用@Autowired标注的属性必须被装配,如果装配不了,也会抛出异常.

可以使用required=false来设置不是必须要被装配.

说下ContextLoaderListener的作用

常见使用场景:

  • 场景1:使用了Spring但是没有使用SpringMVC的web项目(比如Dubbo服务提供者),如何加载Spring配置文件?可以使用ContextLoaderListener来加载。

  • 场景2:使用了SpringMVC但是项目规模大,有多个配置文件,除了使用DispatcherServlet一次性加载,是否有其他方法?可以使用ContextLoaderListener和DispatcherServlet分别加载。

使用及其注意事项:

  • public class ContextLoaderListener extends ContextLoader implements ServletContextListener,该类是一个ServletContextListener,在项目启动的时候加载。注意:Servlet、Filter、Listener的加载顺序:Listener、Filter、Servlet。所以会先加载ContextLoaderListener ,再加载DispatcherServlet。

  • 使用ContextLoaderListener加载非SpringMVC配置文件创建的IoC容器是父容器,DispatcherServlet加载SpringMVC的的配置文件创建的IoC容器是子容器。子容器优先使用自己的Bean,如果没有,可以使用父容器的Bean。

  • 注意事项:同时使用了ContextLoaderListener和DispatcherServlet,如果<context:component-scan >的路径设置不合理,就会重复的创建Bean,甚至导致无法应用业务层事务的问题。

111.png

1. 请描述一下Spring的事务管理?

1、声明式事务管理的定义:用在 Spring 配置文件中声明式的处理事务来代替代码式的处理事务。这样的好处是,事务管理不侵入开发的组件,具体来说,业务逻辑对象就不会意识到正在事务管理之中,事实上也应该如此,因为事务管理是属于系统层面的服务,而不是业务逻辑的一部分,如果想要改变事务管理策划的话,也只需要在定义文件中重新配置即可,这样维护起来极其方便。

基于 TransactionInterceptor  的声明式事务管理:两个次要的属性: transactionManager,用来指定一个事务治理器, 并将具体事务相关的操作请托给它; 其他一个是 Properties 类型的transactionAttributes 属性,该属性的每一个键值对中,键指定的是方法名,方法名可以行使通配符, 而值就是表现呼应方法的所运用的事务属性。

2、基于 @Transactional 的声明式事务管理:Spring 2.x 还引入了基于 Annotation 的体式格式,具体次要触及@Transactional 标注。@Transactional 可以浸染于接口、接口方法、类和类方法上。算作用于类上时,该类的一切public 方法将都具有该类型的事务属性。

编程式事物管理的定义:在代码中显式挪用 beginTransaction()、commit()、rollback()等事务治理相关的方法, 这就是编程式事务管理。Spring 对事物的编程式管理有基于底层 API 的编程式管理和基于 TransactionTemplate 的编程式事务管理两种方式。

说一下你对spring框架中通知类型的理解?

(1)前置通知(Before Advice):在连接点(Join point)之前执行的通知。

(2)后置通知(After Advice):当连接点退出的时候执行的通知(不论是正常返回还是异常退出)。

(3)环绕通知(Around Advice):包围一个连接点的通知,这是最强大的一种通知类型。 环绕通知可以在方法调用前后完成自定义的行为。它也可以选择是否继续执行连接点或直接返回它们自己的返回值或抛出异常来结束执行。

(4)返回后通知(AfterReturning Advice):在连接点正常完成后执行的通知(如果连接点抛出异常,则不执行)

抛出异常后通知(AfterThrowing advice):在方法抛出异常退出时执行的通知

请说出SpringMVC和Spring中常用的注解,并阐明其作用?

  1. @Controller,使用它标记的类就是一个SpringMVC Controller 对象

  2. @RequestMapping,处理请求映射地址

  3. @PathVariable,用于对应restful风格url中的参数

  4. @RequestParam,将请求的参数绑定到方法中的参数上

  5. @ResponseBody,将返回类型直接输入到http response body中

  6. @RequestBody,方法参数直接被绑定到http request body中

  7. @Component:泛指各种组件

  8. @Service:业务层

  9. @Repository:数据访问层

  10. @Controller、@Service、@Repository都可以称为@Component。

@RequestMapping注解用在类上面有什么作用?

它是一个用来处理请求地址映射的注解,可用于类或方法上。

用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。

简述一下@RestController注解的作用

如果需要 @ResponseBody 注解作用在类上时,我们可以直接使用 @RestController 注解,这个注解相当于@ResponseBody + @Controller注解

SpringMVC怎么样设定重定向和转发的?

(1)转发:在返回值前面加"forward:",譬如"forward:user.do?name=method4"

(2)重定向:在返回值前面加"redirect:",譬如"redirect:http://www.baidu.com"

1. 如何理解编程式事务与声明式事务?并说出他们的区别

编程式事务和声明式事务是两种常见的事务管理方式。

编程式事务是在代码中显式地编写事务管理逻辑。开发人员需要手动在代码中控制事务的开始、提交或回滚,并处理可能出现的异常。编程式事务通常使用事务管理接口(如JDBC的Connection对象)来实现。

声明式事务是通过配置的方式来管理事务,而不需要在代码中显式地编写事务管理逻辑。开发人员只需在配置文件中声明事务的属性,如事务的传播行为、隔离级别等,由事务管理框架自动管理事务的开始、提交或回滚。

这两种事务管理方式的区别如下:

代码侵入性:编程式事务需要在代码中显式地编写事务管理逻辑,与业务逻辑代码紧密耦合,造成代码的冗余。而声明式事务通过配置方式管理事务,使得业务逻辑与事务管理逻辑解耦。

管理粒度:编程式事务可以灵活地控制事务的开始、提交或回滚,适用于复杂的事务场景。而声明式事务由事务管理框架自动管理事务,粒度较粗,适用于简单的事务场景。

可读性和可维护性:声明式事务通过配置文件来管理事务,代码清晰简洁,易于理解和维护。而编程式事务需要在代码中编写事务管理逻辑,代码复杂,可读性和可维护性较差。

综上所述,编程式事务适用于复杂的事务场景,提供了更高的灵活性和粒度控制;而声明式事务适用于简单的事务场景,使得代码更加清晰简洁。

SpringMVC的返回值类型有哪些,具体说出一个使用场景?

有String, ModelAndView。ModelAndView类把视图和数据都合并的一起的,但一般用String比较好。