一、说说你对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处理一个请求的核心流程是怎么样的:
- tomcat的工作线程将请求转交给spring mvc框架的DispatcherServlet;
- DispatcherServlet查找@controller注解的controller,我们一般会给controller加上@RequestMapping的注解,标注说哪些controller用来处理哪些请求,此时根据请求的uri,去定位到哪个controller来进行处理;
- 根据@requestMapping去查找,使用这个controller内的哪个方法来进行请求的处理,对每个方法一般也会加@requestMapping的注解;
- 他会直接调用我们的controller里面的某个方法来进行请求的处理;
- 我们的controller的方法会有一个返回值,在以前,一般来说还是走jsp或者模板技术的时候,我们会把前端页面放在后端的工程里面,返回一个页面模板的名字,spring mvc的框架使用模板技术,对html页面做一个渲染;不过现在大部分项目都是使用前后端分离,在这一步我们只要返回json数据就可以了;
- 再把渲染以后的html页面返回给浏览器去进行显示;前后端分离项目则是前端负责把html页面渲染给浏览器就可以了,所以如果是前后端分离的,后端的工作到第5步就结束了;