京东2面成功后的spring面试总结

京东二面后整理的spring面试题

Q:ioc是什么,有什么用?

A:Ioc全称Inversion of Control意思为控制反转,是程序设计的一种思想,或者目标。spring通过DI(依赖注入)来实现IOC,把对象的实例化过程的控制权给到了容器(spring容器);怎么理解呢?

用大白话来说就是以前一个对象产生的控制权全部是程序员自己控制的,比如产生时机、使用哪个构造方法;但是如果反转给容器则由容器决定时机和使用哪个构造方法(spring源码中有通过BeanPostProcessor来推断构造方法的)

Q:bean作用域有哪些,说一下各种使用场景?

A:bean的作用域比较多,可以参考spring官网文档对bean的scope的定义

下面给出截图


这里的生命周期常用的就是singleton和prototype,singleton指的是单例,prototype指的是原型,spring所有创建出来的bean都是单例的,比如controller和service、dao;但是有的时候我们需要bean是一个原型的,比如在类里面有全局变量。

Q:aop是什么,有哪些实现方式?

A:参考spring官方文档:Aop叫做面向切面编程,在实际开发中我们的程序是一个自上而下的执行流程,比如一个登陆逻辑,用户发送HTTP请求,controller接受请求,封装参数,传给service、继而调用dao操作db然后返回。这整个逻辑当中会出现一些横切性的问题,比如进入controller的时候我们需要记录日志,比如调用dao的db操作时候需要进行事务操作,比如进入service的方法之前需要进行权限验证等等。。。这种和主逻辑无关不影响程序执行结果的问题称之为横切性问题,AOP的产生就是为了来解决这种横切性问题。 Aop编程不关心主业务逻辑,只关心这些横切性问题,比如他们的执行时机,执行的地方、执行顺序等等

Aop的实现方式可以从两个方面来回答

第一Aop的编程风格,spring提供两种编程风格,官网有解释一种是xml,一种是基于aspectj的注解风格来的

第二Aop的底层技术实现原理,spring里面提供jdk动态代理的技术和cglib的技术原理来实现AOP

Q:拦截器是什么,什么场景使用?

A:spring当中实现拦截的接口HandlerInterceptor,拦截器主要是让请求进入controller之前进行拦截处理逻辑,主要用在和相关权限的业务上

Q:bean的各种作用域是怎么样实现的?

A:工厂设计模式实现bean的作用域

Q:工具类中如何注入bean?具体使用场景?

A:通过实现Aware接口注入ApplicationContext对象,然后对外提供方位ApplicationContext对象的接口,工具类安装继而调用提供的接口获取ApplicationContext的getBean方法就能获取bean

使用场景分析:比如某个工具类A当中需要调用某个service B,但是A并不是bean,只是一个普通类,故而无法直接注入,需要用到上述方法

public static ApplicationContext applicationContext;供外部访问、得到这个对象

Q:注入的bean存在多份的时候有哪些解决办法?

A:@Quilifier可以解决,其实spring的@autowired已经非常智能了,会先根据type找,如果找到多个,在根据名字找,但是如果名字没有找到就会报错,找到了就用这个bean。

Q:aop里面的cglib原理是什么?

A:ASM字节码技术,动态产生一个子类的类(该子类继承了目标对象),然后实例该子类的对象,返回代理对象,完成代理

Q:aop切方法的方法的时候,哪些方法是切不了的?为什么?

A:最显而易见的便是私有方法,因为AOP的底层是代理、不管是JDK还是cglib都是不能代理私有的。很简单jdk是基于接口的,接口是没有私有的,cglib是基于继承,就是代理对象继承了目标对象,假设你的目标对象里面有一个私有方法是无法继承的,无法继承也就无法代理

Q:同类调用为什么无法切?怎么样解决(AOPContext)?

这个问题我看了很久无法看懂,估计面试官表达有问题,其实这个问题分场景,如果jdk动态代理是有问题的

参考JDK动态代理导致事务失效的原因(可以自行百度,当然你也看我这里对JDK原理的分析)

这里写个例子分析一下

比如我有接口I

public interface I { void f1(); void f2();}然后由实现类Apublic class A implements I { @Override public void f1() { } @Override public void f2() { }}

假设我现在产生一个代理对象(代理I接口),那么产生后的代理对象到底长什么样呢?假设你对jdk动态代理的原理比较清楚就知道JDK是通过动态产生字节码来产生代理对象的,那么我们直接把动态产生的字节码拿出来看看就知道代理对象长什么样子了。

public static void main(String[] args) throws IOException {//获得到产生I接口的代理对象的字节码 byte[] proxyClassFile = ProxyGenerator.generateProxyClass( "xx", new Class[]{I.class});//下面代码比较简单,就是把字节码写到本地  File file = new File("d:\\\xx.class"); FileOutputStream fileOutputStream =new FileOutputStream(file); fileOutputStream.write(proxyClassFile); fileOutputStream.flush(); fileOutputStream.close();}

现在我们已经在D盘有了一个class文件了,那么这个字节码文件我们看不懂啊,其实很简单,直接扔到idea当中(记得要扔到target下面,就是编译输出class的目录,不能放到包下面),idea反编译后的代码如下:

//// Source code recreated from a .class file by IntelliJ IDEA// (powered by Fernflower decompiler)//import com.spring.boot.I;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import java.lang.reflect.UndeclaredThrowableException;public final class xx extends Proxy implements I { private static Method m1; private static Method m4; private static Method m3; private static Method m2; private static Method m0; public xx(InvocationHandler var1) throws { super(var1); } public final boolean equals(Object var1) throws { try { return (Boolean)super.h.invoke(this, m1, new Object[]{var1}); } catch (RuntimeException | Error var3) { throw var3; } catch (Throwable var4) { throw new UndeclaredThrowableException(var4); } } public final void f2() throws { try { super.h.invoke(this, m4, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } }  public final void f1() throws { try { super.h.invoke(this, m3, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final String toString() throws { try { return (String)super.h.invoke(this, m2, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final int hashCode() throws { try { return (Integer)super.h.invoke(this, m0, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } static { try { m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object")); m4 = Class.forName("com.spring.boot.I").getMethod("f2"); m3 = Class.forName("com.spring.boot.I").getMethod("f1"); m2 = Class.forName("java.lang.Object").getMethod("toString"); m0 = Class.forName("java.lang.Object").getMethod("hashCode"); } catch (NoSuchMethodException var2) { throw new NoSuchMethodError(var2.getMessage()); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); } }}

比如我看f1方法去掉无用的代码里面就一行代码

super.h.invoke(this, m3, (Object[])null);

这里的super就是Proxy类,这里JDK动态代理已经默认为你继承了一个类,现在你知道为什么JDK只能用接口了吧?因为java不允许多继承。

然后在Proxy类里面有一个h属性,这个h属性就是InvocatonHandler接口,是程序员提供的一个接口。在springAop的源码中:


当然这里我先不讨论springAop;说回上面的这个InvocatonHandler接口,里面有一个invoker方法,这个方法里面的逻辑是由程序员自己提供,那么我们的代理逻辑就是写在这个方法里面,并且这个方法还负责调用目标方法的逻辑,怎么调用的呢?就是把目标对象传给这个InvocatonHandler,然后反射调用,所以你在f1里面调用f2其实是调用目标对象的f2并不是代理对象的f2。故而会导致代理失效,也是上面说的不能切本类。

Q:有没有用过BeanFactory?场景?

A:用的不多,曾经通过BeanFactory动态往spring容器当中注入一个bean,什么意思呢?假设我一个bean最开始并不要求被spring实例化,在某个时机(某个条件成了、比如你获取了一个别人传给你的对象)需要自己实例化,实例化好之后通过BeanFactory添加到spring容器当中,代码如下:

AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(Appconfig.class);ac.getBeanFactory().registerSingleton("bname",你的对象);

Q:说说aop和ioc关系

A:其实这个题目本身意义不大,IOC和AOP都是编程目标和spring没有关系,就算没有spring也能实现AOP,比如大名鼎鼎的Aspectj技术也能实现Aop。如果硬是要说关系应该说spring的IOC和springAop有什么关系。其实意义也不大,无非springAop当中的对象必须在IOC容器当中。比如Aspectj就可以脱离IOC单独使用,但是springAop就不能脱离IOC

Q:说说DispatcherServlet做了什么

这个问题可复杂了,简单说DispatcherServlet的init方法里面load了springmvc的配置信息,然后初始化了spring容器(调用了refresh方法),把controller的信息缓存了,比如映射信息;然后DispatcherServlet会拦截所有的请求,根据用户的请求信息通过缓存的映射信息找到对应的controller的对应方法,然后反射调用(其实底层的源码就是反射调用controller的方法),然后视图裁决、解析等等工作,可以参考springMVC的工作原理去回答。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,546评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,224评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,911评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,737评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,753评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,598评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,338评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,249评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,696评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,888评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,013评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,731评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,348评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,929评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,048评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,203评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,960评论 2 355

推荐阅读更多精彩内容

  • IoC 容器 Bean 的作用域 自定义作用域实现 org.springframework.beans.facto...
    Hsinwong阅读 2,473评论 0 7
  • 一. Java基础部分.................................................
    wy_sure阅读 3,811评论 0 11
  • 姥姥今年84岁了,现如今躺在医院的病床上,疾病无情地折磨着她,食道里恶化的肿瘤使她咽不下些许食物,回想起到医院看望...
    草蝶阅读 156评论 0 0
  • 文件目录系统管理磁盘管理
    和蔼的zhxing阅读 155评论 0 0
  • 【文/武立之】 忽听寒鸦噪,凌云列序飞。 回旋空见影,往复早知机。 偏在此时去,更从何处归? 难堪扰人世,毕竟与心违。
    雪窗_武立之阅读 480评论 1 6