java面试(Spring篇)

参考博客:https://blog.csdn.net/a745233700/article/details/80959716

一、Spring

1.什么是Spring

Spring是一个轻量级的IOC和AOP容器的框架,他为java程序提供了一套基础性服务,目的是为了简化应用程序的开发。主要包括一下几个模块:

  • Spring Core:核心类库,提供IOC服务。
  • Spring Context:提供框架式的bean访问方式,还包括了定时任务,JNDI等企业级功能。
  • Spring AOP:aop服务。
  • Spring DAO:对JDBC的抽象,简化了数据访问异常的处理。
  • Spring ORM:对现有的ORM框架的支持;
  • Spring Web:提供了面向web的多种特性,例如多方文件上传。
  • Spring MVC:提供了面向web的MVC模式的mvc模式的实现。

 2.Spring有什么优点?

  1. 轻量
  2. spring属于低侵入式设计,代码的污染极低。不强迫应用程序和框架的接口绑定
  3. spring的DI机制将对象之间的依赖关系交由框架处理,减低组件的耦合性;
  4. Spring提供了AOP技术,支持将一些通用任务,如安全、事务、日志、权限等进行集中式管理,从而提供更好的复用。
  5. spring对于主流的应用框架提供了集成支持。

3.Spring Ioc的理解

 IoC:控制反转。控制反转指的是我们将对象的控制权交给spring的Ioc容器,什么时机创建对象由容器决定。这样可以实现对象之间的松散耦合。依赖注入和控制反转其实是一个概念从不同角度的解释,DI指的是一个程序在运行的时候容器会动态的注入所需要的外部资源。通俗的讲,我们不必在通过new新建一个对象,可以让spring自动生产,然后我们通过反射机制在程序运行时根据配置文件动态的生成管理对象,并调用对象的方法。具体的提现时带参数的构造方法。如果没有控制反转,需要在类A内部新建一个对象B,才能在A内使用B的方法,依赖注入只在我们新建类A的时候把已经存在的类B注入进去,这样类A也可以使用注入的类B的方法。
依赖注入一般包括三类:

  1. 基于构造器的注入
  2. 基于get,set方法的注入
  3. 基于注解的注入
    --@Resource  (一般用于controller层注入service,根据设置的名称来实现注入)
    --@compoent :应用于普通的类中
    --@service:在servie层中使用
    --@controller:标记controller层
    --@reposistory:在dao层中使用
    --@Reference:dubbo的服务注入
    --@autowired:自动注入的方式进行注入,默认根据类的名称来进行装配

 

4.aop面向切面变成的理解

 OOP面向对象编程,允许我们对业务逻辑的纵向进行分割,摆脱了面向流程编程的弊端,将着重点放在对象上,将业务抽象为一个个对象。面向切面变成指的是横向的切分。我们把一些横向贯穿系统与业务无关,却与多个对象息息相关的功能提取出来单独封装成为了一个切面(Aspect),减少了代码的重复,降低了模块之间的耦合性,提高了系统的可维护性。一般来说用作切面的功能包括日志,权限,事务处理。

aop的核心是代理模式,AspecJ是静态代理,springAop是动态代理:
AspectJ是静态代理的增强,所谓静态代理,就是AOP框架会在编译阶段生成AOP代理类,因此也称为编译时增强,他会在编译阶段将AspectJ(切面)织入到Java字节码中,运行的时候就是增强之后的AOP对象。
Spring AOP使用的动态代理,所谓的动态代理就是说AOP框架不会去修改字节码,而是每次运行时在内存中临时为方法生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法。

动态代理分为两种:

  1. JDK动态代理只提供接口的代理,不支持类的代理。核心InvocationHandler接口和Proxy类,InvocationHandler 通过invoke()方法反射来调用目标类中的代码,动态地将横切逻辑和业务编织在一起;接着,Proxy利用 InvocationHandler动态创建一个符合某一接口的的实例,  生成目标类的代理对象。
  2. 如果代理类没有实现 InvocationHandler 接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成指定类的一个子类对象,并覆盖其中特定方法并添加增强代码,从而实现AOP。CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。

静态代理与动态代理区别在于生成AOP代理对象的时机不同,相对来说AspectJ的静态代理方式具有更好的性能,但是AspectJ需要特定的编译器进行处理,而Spring AOP则无需特定的编译器处理。

aop的一些概念:

  • Aspec:切面,我们所要织入的业务。比如生成日志就是一个切面
  • PointCut:切点,我们要在哪个bean的哪个方法实现织入
  • Advice:通知
    前置通知(before) - 在目标方法被调用之前调用通知功能
    后置通知(after) - 在目标方法完成之后调用通知(不论程序是否出现异常),此时不会关心方法的输出是什么
    返回通知(after-returning) - 在目标方法成功执行之后调用通知
    异常通知(after-throwing) - 在目标方法抛出异常后调用通知
    环绕通知(around) - 通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为

springAop定义时要用到的一些注解:

一个类如果被@Aspec注释,说明是个切面类,如下定义的是日志切面类:
 

@Aspect
@Component
public class SysLogAspect {

}

@Pointcut 定义切点的位置,例如如下定义的是OperationLogger,OperationLogger类是个注释类,只要被该注释修饰的方法都会织入切面方法

@Pointcut("@annotation(com.slodon.admin.aop.OperationLogger)")
    public void controllerAspect() {
    }



//定义的注释方法,被这个注释的方法都会织入切面
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface OperationLogger {
    String option();
}

如图:五中通知方式

5、如何理解BeanFactory和ApplicationContext? 

1.首先我们要清楚,BeanFactory和ApplicationContext是Spring的两大容器,是Ioc的核心,也是SpringCore组件的核心。容器改变了bean的装配方式,对象由用户生成改为容器装配。

2.ApplicationContext是BeanFactory的子接口,两者在功能上有互通之处。BeanFactory管理了bean的定义,bean文档的配置,管理bean的加载和实例化,控制bean的生命周期,维护bean之间的依赖关系。ApplicationContext出了以上功能,还提供了一些框架功能

3.两者的区别在于:beanFactory是在程序启动后用到bean的地方才会加载bean的实例,而ApplicationContext在程序启动的时候会把所有的bean都加载。

4.beanFactory一般用在对资源依赖比较大的程序,因为启动的时候并没有实例化所有的bean,所以占用的资源比较少。但是相应的,运行速度不如applicationContext

5.applicationContext在启用的时候实例化所有的bean,一是使用bean的时候不必再次实例化,响应速度较快。而是在实例化bean的时候,如果某个bean实例化失败程序就不能启动,而beanFactory的话,只有在用到bean的时候才会报错。但是缺点是这种方式虽然响应速度快,但是对于内存等资源的占用很大,适合一些web程序。

6.SpringBean的生命周期

å¨è¿éæå¥å¾çæè¿°

å¨è¿éæå¥å¾çæè¿°

 SpringBean的生命周期整体上分为四大类,实例化->属性装配->初始化->销毁。

  1. 首先spring的容器会进行初始化,会对类BeanFactoryProcessor,BeanPostProcessor,InstantiationAwareBeanPostProcessor 进行实例化并执行对应的方法;这个时候对应的bean会调用其构造器进行bean的实例化。
  2. 第二步会对bean进行属性注入,然后调用bean级生命周期管理的相应接口的方法,包括BeanNameAware,BeanFactoryAware,InitializingBean
  3. 第三步对bean进行初始化,同时对于配置文件中的一些初始化方法进行初始化。
  4. 关闭容器的时候,会调用DiposibleBean.destory()方法,对bean进行销毁。然后调用配置文件中的一些销毁方法。

(1)实例化Bean:

对于BeanFactory容器,当客户向容器请求一个尚未初始化的bean时,或初始化bean的时候需要注入另一个尚未初始化的依赖时,容器就会调用createBean进行实例化。对于ApplicationContext容器,当容器启动结束后,通过获取BeanDefinition对象中的信息,实例化所有的bean。

(2)设置对象属性(依赖注入):

实例化后的对象被封装在BeanWrapper对象中,紧接着,Spring根据BeanDefinition中的信息 以及 通过BeanWrapper提供的设置属性的接口完成依赖注入。

(3)处理Aware接口:

接着,Spring会检测该对象是否实现了xxxAware接口,并将相关的xxxAware实例注入给Bean:

①如果这个Bean已经实现了BeanNameAware接口,会调用它实现的setBeanName(String beanId)方法,此处传递的就是Spring配置文件中Bean的id值;

②如果这个Bean已经实现了BeanFactoryAware接口,会调用它实现的setBeanFactory()方法,传递的是Spring工厂自身。

③如果这个Bean已经实现了ApplicationContextAware接口,会调用setApplicationContext(ApplicationContext)方法,传入Spring上下文;

(4)BeanPostProcessor:

如果想对Bean进行一些自定义的处理,那么可以让Bean实现了BeanPostProcessor接口,那将会调用postProcessBeforeInitialization(Object obj, String s)方法。

(5)InitializingBean 与 init-method:

如果Bean在Spring配置文件中配置了 init-method 属性,则会自动调用其配置的初始化方法。

(6)如果这个Bean实现了BeanPostProcessor接口,将会调用postProcessAfterInitialization(Object obj, String s)方法;由于这个方法是在Bean初始化结束时调用的,所以可以被应用于内存或缓存技术;

以上几个步骤完成后,Bean就已经被正确创建了,之后就可以使用这个Bean了。

(7)DisposableBean:

当Bean不再需要时,会经过清理阶段,如果Bean实现了DisposableBean这个接口,会调用其实现的destroy()方法;

(8)destroy-method:

最后,如果这个Bean的Spring配置中配置了destroy-method属性,会自动调用其配置的销毁方法。

 7.如何理解SpringBean的作用域?

spring中的bean大概分为5种范围:

  1. singleton:单例模式,spring每个容器中只有一个丹单例模式bean的对象,由BeanFactory自身来维护
  2. prototype:为每个bean请求都创建一个实例
  3. request:为每个网络请求都设置一个bean,当请求结束的时候bean会被回收
  4. session:session范围内会存在一个实例,session失效bean也会失效
  5. global-session:全局作用域,global-session和Portlet应用相关。当你的应用部署在Portlet容器中工作时,它包含很多portlet。如果你想要声明让所有的portlet共用全局的存储变量的话,那么这全局变量需要存储在global-session中。全局作用域与Servlet中的session作用域效果相同。

8.Spring框架中的单例Beans是线程安全的么?

 Spring框架并没有对单例bean进行任何多线程的封装处理。关于单例bean的线程安全和并发问题需要开发者自行去搞定。但实际上,大部分的Spring bean并没有可变的状态(比如Serview类和DAO类),所以在某种程度上说Spring的单例bean是线程安全的。如果你的bean有多种状态的话(比如 View Model 对象),就需要自行保证线程安全。最浅显的解决办法就是将多态bean的作用域由“singleton”变更为“prototype”。

9、Spring如何处理线程并发问题?

 Spring并没有对线程安全相关问题进行封装,bean有自己的作用域,默认的作用域是单例模式,即程序从启动开始对于一个bean只创建一个单例,直到应用结束bean才会被销毁。spring中的bean大多都是无状态的,无状态理解为不管是单线程或者是多线程模式,都不会涉及到线程安全问题。

对于一些涉及到线程安全状态的bean,spring采用ThreadLocal的方法来实现线程安全。

同步机制实现方式是通过加锁实现对对象访问的安全控制,这是一种时间换取空间的做法,用户想要访问bean就必须获得锁,而在未释放锁之前,对象的所有线程处于阻塞状态。

而threadlocal是通过空间换取时间的方式来实现线程安全,当有线程访问bean的时候,threadlocal为每个线程创建一个bean对应的副本,这样不同线程操作的是不同副本,这样隔绝了多个线程的数据访问冲突,这种情况的话解决线程安全问题。

ThreadLocal提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的变量封装进ThreadLocal。

10.如何理解spring的事务管理

参考:https://blog.csdn.net/roberts939299/article/details/77587425

spring对于事务的支持是基于数据库的事务管理的,数据库的事务提交和回滚是通过binlog和redolog日志文件来实现的。

spring事务分为两种,编程式和声明式:

  1. 编程式:编程式书屋使用TransactionTemplate。
  2. 声明式:声明式事务。声明式事务是基于aop的事务管理,通过把事务在方法的前后织入,即开始方法时开始事务,根据方法执行的结果来确认是提交还是回滚。

    声明式事务最大的优点就是不需要在业务逻辑代码中掺杂事务管理的代码,只需在配置文件中做相关的事务规则声明或通过@Transactional注解的方式,便可以将事务规则应用到业务逻辑中。声明式事务管理要优于编程式事务管理,这正是spring倡导的非侵入式的开发方式,使业务代码不受污染,只要加上注解就可以获得完全的事务支持。唯一不足地方是,最细粒度只能作用到方法级别,无法做到像编程式事务那样可以作用到代码块级别。

 11.spring的事务传播行为

事务传播行为指的是多个事务同时存在,各个事务之间的影响:

① PROPAGATION_REQUIRED:如果当前没有事务,就创建一个新事务,如果当前存在事务,就加入该事务,该设置是最常用的设置。

② PROPAGATION_SUPPORTS:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就以非事务执行。‘

③ PROPAGATION_MANDATORY:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就抛出异常。

④ PROPAGATION_REQUIRES_NEW:创建新事务,无论当前存不存在事务,都创建新事务。

⑤ PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。

⑥ PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。

⑦ PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则按REQUIRED属性执行。

12.Spring中的事务隔离级别: 

① ISOLATION_DEFAULT:这是个 PlatfromTransactionManager 默认的隔离级别,使用数据库默认的事务隔离级别。

② ISOLATION_READ_UNCOMMITTED:读未提交,允许另外一个事务可以看到这个事务未提交的数据。

③ ISOLATION_READ_COMMITTED:读已提交,保证一个事务修改的数据提交后才能被另一事务读取,而且能看到该事务对已有记录的更新。

④ ISOLATION_REPEATABLE_READ:可重复读,保证一个事务修改的数据提交后才能被另一事务读取,但是不能看到该事务对已有记录的更新。

⑤ ISOLATION_SERIALIZABLE:一个事务在执行的过程中完全看不到其他事务对数据库所做的更新。

14. spring事件的理解

1.什么是事件:
事件可以理解为spring为bean与bean之间通讯提供的一种方式,当我们希望一个bean的行为能被另一个bean所知道并作出相应的处理,我们可以利用事件来实现。


2.事件分为哪几部分:
spring的事件可以分为三个部分:

  • 事件源:需要被监控的类--事件本身
  • 事件监听器:负责接收具体的事件源的事件
  • 事件广播器:负责发布事件

 

3.spring的事件的实现的具体流程

  • 首先事件源必须继承ApplicationEvent或者其子类,并重写构造方法--其子类类型下文会有提到
  • 事件监听器需要实现ApplicationListener接口,通过实现其方法onApplicationEvent,来实现对业务监听
  • 事件的发布是通过spring的容器ApllicationContext的publishEvent方法来实现的

 

4.spring的事件监听有什么特点呢?

首先spring的事件是同步的,如果某个事件发布成功了--publishEvent()执行之后,整个线程会处于阻塞状态,只有当onApllication方法接收到event并且处理成功之后才会继续执行下个事件,这种特点有利于做事务管理

 

5.spring框架之中有定义哪些事件呢?

事件的父类是ApplicationEvent,spring中一共有两个类继承自该类:ApplicationContextEvent和RequestHandledEvent
ApplicationContextEvent一共有4个子类:

  • ContextRefreshedEvent:在调用ConfigurableApplicationContext 接口中的refresh()方法时被触发,刷新
  • ContextStartedEvent:当容器调用ConfigurableApplicationContext的Start()方法开始/重新开始容器时触发该事件
  • ContextClosedEvent:当ApplicationContext被关闭时触发该事件。容器被关闭时,其管理的所有单例Bean都被销毁
  • ContextStoppedEvent:当容器调用ConfigurableApplicationContext的Stop()方法停止容器时触发该事件

RequestHandledEvent只有定义了DispatcherServlet时才会产生该事件,它代表Servlet请求事件,在Web应用中,当一个http请求(request)结束触发该事件。

如果一个bean实现了ApplicationListener接口,当一个ApplicationEvent 被发布以后,bean会自动被通知。


6.事件有哪些优点:

优点:模块分离,解耦,业务分离

 

 

二、SpringMVC

参考文章:https://blog.csdn.net/a745233700/article/details/80963758

1.什么是SpringMVC?

spring是基于Java的实现了MVC框架的一个请求驱动的web框架,通过Model,View,Controller分离的方式将web程序解耦。把复杂的业务逻辑分成了几个部分。这样使得程序之间的依赖更小,耦合度降低,有利于人员写作开发项目。

 2.springMVC什么优点?

 (1)可以支持各种视图技术,而不仅仅局限于JSP;

(2)与Spring框架集成(如IoC容器、AOP等);

(3)清晰的角色分配:前端控制器(dispatcherServlet) , 请求到处理器映射(handlerMapping), 处理器适配器(HandlerAdapter), 视图解析器(ViewResolver)。

(4) 支持各种请求资源的映射策略。

 3.SpringMVC的工作过程

  1. 用户发送请求到DispacherServlet---前端控制器
  2. DispacherServlet接受到请求之后,调用HandlerMapping处理器映射器,形成handle
  3. 处理器映射器根据对应的url映射到对应的controller对象,处理handle对象一并返回给控制器
  4. 控制器调用处理器适配器HandlerAdapter
  5. 处理器适配器通过具体的适配到对应的处理器,也称为后端控制器handler(即controller)
  6. handler返回对应的modelAndView
  7. 视图解析器解析对应的ModelAndView,返回view对象
  8. 前端控制器渲染视图,把modelAndView填充到view中
  9. 前端控制器把视图返回给请求

 

 

4.Spring MVC的主要组件?

  1. DispacherServlet-前端控制器:接收请求,响应结果,处理各个部件之间的协作,降低了其余部件之间的耦合性
  2. HandlerMapping-处理器映射器:根据请求的url寻找对应的handler
  3. HandlerAdapter-处理器适配器:根据对应的handler找到具体的controller,执行handler
  4. Handler-控制器:需拆单要程序猿开发,具体指的是我们所编写的controller
  5. ViewResolver-视图解析器:进行视图的解析,将视图根据其逻辑名称解析成为view
  6. View-视图:指具体的前端页面(jsp,freemarker等),需要程序猿开发

 

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

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

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

 

6、SpringMvc怎么和AJAX相互调用的?

通过Jackson框架就可以把Java里面的对象直接转化成Js可以识别的Json对象。具体步骤如下 :

(1)加入Jackson.jar

(2)在配置文件中配置json的映射--用到bean:MappingJackson2HttpMessageConverter

(3)在接受Ajax方法里面可以直接返回Object,List等,但方法前面要加上@ResponseBody注解。

配置文件如下:

 

7、如何解决POST请求中文乱码问题,GET的又如何处理呢?

1.post乱码需要在web.xml之中设置一个过滤器:

2.get 方法(主要是tomcat的问题)

修改tomcat配置文件添加编码与工程编码一致;

对参数进行重新编码;

10、SpringMvc的控制器是不是单例模式,如果是,有什么问题,怎么解决?

答:是单例模式,所以在多线程访问的时候有线程安全问题,不要用同步,会影响性能的,解决方案是在控制器里面不能写字段。

11、 SpringMVC常用的注解有哪些?

@RequestMapping:用于处理请求 url 映射的注解,可用于类或方法上。用于类上,则表示类中的所有响应请求的方法都是以该地址作为父路径。

@RequestBody:注解实现接收http请求的json数据,将json转换为java对象。

@ResponseBody:注解实现将conreoller方法返回对象转化为json对象响应给客户。

12、SpingMvc中的控制器的注解一般用那个,有没有别的注解可以替代?

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

13、如果在拦截请求中,我想拦截get方式提交的方法,怎么配置?

答:可以在@RequestMapping注解里面加上method=RequestMethod.GET。

14、怎样在方法里面得到Request,或者Session?

答:直接在方法的形参中声明request,SpringMvc就自动把request对象传入。

15、如果想在拦截的方法里面得到从前台传入的参数,怎么得到?

答:直接在形参里面声明这个参数就可以,但必须名字和传过来的参数一样。

16、如果前台有很多个参数传入,并且这些参数都是一个对象的,那么怎么样快速得到这个对象?

答:直接在方法中声明这个对象,SpringMvc就自动会把属性赋值到这个对象里面。

17、SpringMvc中函数的返回值是什么?

答:返回值可以有很多类型,有String, ModelAndView。ModelAndView类把视图和数据都合并的一起的,但一般用String比较好。

18、SpringMvc用什么对象从后台向前台传递数据的?

答:通过ModelMap对象,可以在这个对象里面调用put方法,把对象加到里面,前台就可以通过el表达式拿到。

19、怎么样把ModelMap里面的数据放入Session里面?

答:可以在类上面加上@SessionAttributes注解,里面包含的字符串就是要放入session里面的key。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值