Spring相关面试题

一、说说你对Spring的_IOC_机制的理解可以吗?

IOC机制就八个字:控制反转,依赖注入;
这么回答,太过简答,面试官也不认可,所以咱们得深入一点讲,可以举个例子有逻辑的回答:

在没有使用spring之前,都是使用Servlet在处理请求类似于如下:

public class MyServlet {

    private MyService myService=new MyServiceImpl();

    public void doPost(HttpRequest request){
        //业务逻辑
        myService.doRequest(request);
    }

}

此时在使用service时是直接在Servlet中直接new出对应的实现类,那如果有非常多的Servlet都使用了MyServiceImpl这个实现类,并且现在要跟换一个实现类,不再使用MyServiceImpl,而是使用NewServiceImpl这个实现类,那怎么办,是不是要每一个Servlet里面都去修改一下实现类,那这个工作量太大了,而且还可能没改干净导致错误;

那spring就应运而生了,带入了IOC机制,改变后的代码为:

@Controller
public class MyServlet {

    @Autowired
    private MyService myService;

    public void doPost(HttpRequest request){
        //业务逻辑
        myService.doRequest(request);
    }

}

在MyServlet上加上了注解,代表着该类交给IOC容器去管理,大家重点看Servie,去掉了具体的实现类,直接在上面加上@Autowired,那么IOC容器就会去寻找实现了MyService这个接口的实现类,当然这个实现类需要加上@Service注解交给IOC容器管理,否则Spring是找不到的,这样当你要跟换实现类时,那就在需要的实现类上面加上@Service注解即可,将代码的耦合度大大降低;

总结一下,SpringIOC和Spring容器会根据xml配置(早期)或者是你的注解,去实例化你的一些bean对象,然后根据xml配置或者注解,去对bean对象之间的引用关系进行依赖注入,这个就是MyServlet依赖了MyService,所以Spring会自动帮我们实例化好MyService对象;

实例化的底层核心技术是反射,Spring会通过反射的技术,直接根据你的类去构建对应的对象出来;

Spring IOC最大的共享就是实现了系统的类与类之间彻底的解耦合;

这么回答就非常棒了。

二、说说你对Spring的AOP机制的理解可以吗?

AOP机制也就是咱们常说的面向切面编程,啥是面向切面编程呢,就是这些额外增加的代码不和逻辑写在一块,并且很多方法都可以共用;

下面咱们使用代码示例来讲解

@Service
public class MyServiceImpl implements MyService{

    public void doService(){
		//事务启动
	
        // 执行 insert 操作
        // 执行 update 操作
        // 执行 delete 操作
        // 执行 update 操作

		//如果发生异常则事务回滚
		//事务提交
    }

}

上面这段代码是非常常见的写在Service内的一段对数据库进行操作的代码,首先进行事务启动,结束之后在进行事务的提交,如果中间发生异常还需事务回滚,只要是对数据库操作的方法就少不了这三步操作,那么我们不可能在每个方法内都手动去加上这些代码,太浪费时间了,所以AOP就闪亮登场了;

AOP怎么做呢,它其实是去定义了一下需要对哪些类,哪些方法进行增强,比如说上面这个需要添加事务的方法,那AOP就会定义在方法开始时启动事务,在方法结束时进行事务提交;

定义完之后呢,Spring在运行的时候,会使用动态代理(这是AOP的核心),动态代理后的MyServiceImpl类就是增强之后的,类似于下面这样:

public class ProxyMyServiceImpl implements MyService {

    private MyService myService;

    public void doService(){
        //事务启动

		//调用原先的MyServiceImpl中的doService方法
        myService.doService();
        
        //根据是否抛异常选择是回滚还是提交
    }

}

动态代理其实就是创建一个新的类,然后注入旧的类,在方法中将增强的代码加上之后,在去调用旧的方法,所以接下来所有使用到doServie方法的地方全部都会去调用ProxyMyServiceImpl中的,也就是代理之后的方法;

总结一下:AOP先定义了一下对哪些类,哪些方法进行增强,包括怎么增强,然后在Spring运行时会使用动态代理模式,这是AOP的核心技术,对定义的类进行改造,后面所有的地方有使用到定义的类或方法时都是调用改造后的了。

关于如何使用AOP编程,大家可以自行在百度上搜索,案例非常多,也很简单。

三、了解过cglib动态代理吗?他跟jdk动态代理的区别是什么?

动态代理在上面咱们又提了一下,现在咱们再来详细讲解一下;

动态代理其实就是动态的创建一个代理类出来,在这个代理类的实例对象中会引用被代理的类,所有的方法调用,都是先走代理类,它负责做一些代码上的增强,在去调用被代理类的方法;

动态代理又有两种,分别是jdk动态代理和cglib动态代理:

  • jdk动态代理:如果被代理的类实现了某个接口,那么AOP就会使用jdk动态代理,生成一个跟被代理类实现相同接口的代理类;
  • cglib动态代理:很多时候需要被代理的类是没有实现接口的,那这时AOP就会改用cglib动态代理,生成一个被代理类的子类,然后覆盖被代理类的方法,在方法中加入增强的代码

总结:两者的区别就是看被代理类是否有实现接口,有则使用jdk动态代理,没有,则使用cglib动态代理;

四、能说说Spring中的Bean是线程安全的吗?

想要回答这个问题咱们需要先知道Bean的作用域,分别是以下几种:

  • singleton:默认,每个容易中只有一个bean的实例(即单例)
  • prototype:每个bean请求都会提供一个新实例(即多例)
  • request:为每一个网络请求创建一个实例,在请求完成以后,bean会失效并被辣鸡回收期回收
  • session:与request范围类似,确保每个session中有一个bean实例,在session过期后,bean会随之失效
  • global-session:一般用于Portlet应用环境,该作用域仅适用于WebApplicationContext环境;

除了singleton和prototype,其他几种基本在开发时不会去使用到,并且99.99%都是使用singleton;

所以答案已经很明显了,Bean并不是线程安全的,如果在bean中定义了一个可修改的变量(这种做法只有笨蛋才会用),那么多个线程同时操作这个变量肯定是会出现问题的,但是我们基本上不会这么操作,所以即使bean是线程不安全,其实也没有多大的影响,因为他们几乎不会并发去访问内存里的共享数据,顶多就是并发访问数据库。

五、Spring的事务实现原理是什么?能聊聊你对事务传播机制的理解吗?

咱们在用spring添加事务时,只要在方法上添加一个@Transactional(propagation = Propagation.REQUIRED)注解即可,在联想上面讲的AOP机制,是不是就可以明白他的原理啦;

原理其实很简单,通过注解的方式,为方法定义上增强事务功能,然后通过AOP机制添加上事务的相关代码即可;

那什么是事务的传播机制呢,就是@Transactional(propagation = Propagation.REQUIRED)里面这个propagation 参数对应的值,默认是Propagation.REQUIRED,咱们接下来讲讲事务的传播机制一共有几种:

  • PROPAGATION_REQUIRED(默认):如果当前没有事务,那就创建一个新事物,如果当前存在事务,就加入该事务,该设置是最常用的也是默认的
  • PROPAGATION_SUPPORTS:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就以非事务执行
  • PROPAGATION_MANDATORY:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就抛出异常,非常傲娇,自己就是不创建新事务,就用别人的;
  • PROPAGATION_REQUIRES_NEW:创建新事务,无论当前存不存在事务,都会去创建新的事务;
  • PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起;
  • PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常;
  • PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务则按REQUIRED属性执行,这是啥意思呢,就说假设A方法调用了B,如果B发生异常,那么只会回滚B自己,不会把A也回滚了;如果A发生异常,那么会连同B一起回滚,即内层不影响外层,外层会影响内层;

用的比较多的就是PROPAGATION_REQUIRED、PROPAGATION_REQUIRES_NEW和PROPAGATION_NESTED;

六、能画一张图说说Spring的核心架构吗?

在这里插入图片描述

七、能说说Spring中都使用了哪些设计模式吗?

在这咱们提几个比较常见的设计模式:

  • 工厂模式:咱们在使用一个bean时都是直接使用注入的方式,并没有通过new的方式,所以IOC容器其实就是一个大工厂,为我们提供了各种各样咱们所需的bean;
  • 单例模式:在第4节咱们已经说了,Spring中的bean默认是单例的,所以单例模式?不用说了吧;
  • 代理模式:上面两个模式其实比较简单,这个才有点含金量,代理模式最多应用在AOP中,其实在第二节咱们也说过了,AOP会动态创建一个代理类出来,http请求时先访问代理类的代码,再去访问被代理类的代码;

当然,Spring中还远不止这些设计模式,还有建造者模式等等,这些还需要大家自行去搜索了。

八、能说说Spring_Web_MVC的核心架构吗?

所谓的核心架构其实也就是指MVC处理一个请求的核心流程是怎么样的:

  1. tomcat的工作线程将请求转交给spring mvc框架的DispatcherServlet;
  2. DispatcherServlet查找@controller注解的controller,我们一般会给controller加上@RequestMapping的注解,标注说哪些controller用来处理哪些请求,此时根据请求的uri,去定位到哪个controller来进行处理;
  3. 根据@requestMapping去查找,使用这个controller内的哪个方法来进行请求的处理,对每个方法一般也会加@requestMapping的注解;
  4. 他会直接调用我们的controller里面的某个方法来进行请求的处理;
  5. 我们的controller的方法会有一个返回值,在以前,一般来说还是走jsp或者模板技术的时候,我们会把前端页面放在后端的工程里面,返回一个页面模板的名字,spring mvc的框架使用模板技术,对html页面做一个渲染;不过现在大部分项目都是使用前后端分离,在这一步我们只要返回json数据就可以了;
  6. 再把渲染以后的html页面返回给浏览器去进行显示;前后端分离项目则是前端负责把html页面渲染给浏览器就可以了,所以如果是前后端分离的,后端的工作到第5步就结束了;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值