面试还不懂这10道Spring问题,回去等通知了
最近有一位朋友和我说,他做了开发 3 年了,最近去面试时,Spring 被面试官问得哑口无言,他总结了下面几道被问到的关于 Spring 的面试题,可以参考下。
参考问题
参考解析
1.Spring IoC、AOP 原理
1.1.定义
1.1.1.IoC
1.1.2.AOP
Aspect Oriented Programming,面向切面编程。通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP 是 OOP 的延续,是软件开发中的一个热点,也是 Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。其中,最常用的使用场景一般有日志模块、权限模块、事物模块。
1.2.原理
1.2.1.IoC

还有其他的类不一一列举出来,都在 java.lang.reflect 包下。说到这个模块的时候,那么面试官可能会考察相关的知识,主要是考察你是否真的有去了解过反射的使用。举两个例子:
这里其实就是里面的重要考察点就是反射对私有属性的处理。
/**
* 通过反射获取私有的成员变量.
*/
private Object getPrivateValue(Person person, String fieldName)
{
try
{
Field field = person.getClass().getDeclaredField(fieldName);
// 主要就是这里,需要将属性的 accessible 设置为 true
field.setAccessible(true);
return field.get(person);
}
catch(Exception e)
{
e.printStackTrace();
}
return null;
}
使用默认构造函数(无参)创建的话:
Class.newInstance() Constroctor constroctor = clazz.getConstructor(String.class,Integer.class); Object obj = constroctor.newInstance("name", 18);
AOP 的内部原理其实就是动态代理和反射了。主要涉及到的反射类:
JDK 动态代理
使用 CGLIB 动态代理,被代理类不需要强制实现接口。CGLIB 不能对声明为 final的方法进行代理,因为 CGLIB 原理是动态生成被代理类的子类。
2.Spring Bean 生命周期
3.Spring Bean 注入是如何解决循环依赖问题的
循环依赖就是 N 个类中循环嵌套引用,这样会导致内存溢出。循环依赖主要分两种:
- 构造器循环依赖
- setter 循环依赖
- 构造器循环依赖问题
- setter 循环依赖问题
Spring 初始化单例对象大体是分为如下三个步骤的:
- createBeanInstance:调用构造函数创建对象
- populateBean:调用类的 setter 方法填充对象属性
- initializeBean:调用定义的 Bean 初始化 init 方法
- singletonObjects:Cache of singleton objects: bean name --> bean instance,完成初始化的单例对象的 cache(一级缓存)
- earlySingletonObjects:Cache of early singleton objects: bean name--> bean instance ,完成实例化但是尚未初始化的,提前暴光的单例对象的 cache (二级缓存)
- singletonFactories : Cache of singleton factories: bean name -->ObjectFactory,进入实例化阶段的单例对象工厂的 cache (三级缓存)
protected Object getSingleton(String beanName, boolean allowEarlyReference)
{
Object singletonObject = this.singletonObjects.get(beanName);
// isSingletonCurrentlyInCreation:判断当前单例 bean 是否正在创建中
if(singletonObject == null && isSingletonCurrentlyInCreation(beanName))
{
synchronized(this.singletonObjects)
{
singletonObject = this.earlySingletonObjects.get(beanName);
// allowEarlyReference:是否允许从 singletonFactories 中通过 getObject 拿到
对象
if(singletonObject == null && allowEarlyReference)
{
ObjectFactory <? > singletonFactory = this.singletonFactories.get(beanName);
if(singletonFactory != null)
{
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return(singletonObject != NULL_OBJECT ? singletonObject : null);
}
protected void addSingletonFactory(String beanName, ObjectFactory <? > singletonFactory)
{
Assert.notNull(singletonFactory, "Singleton factory must not be null");
synchronized(this.singletonObjects)
{
if(!this.singletonObjects.containsKey(beanName))
{
this.singletonFactories.put(beanName, singletonFactory);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
}
4.Spring 事务为何失效了
可能的原因:
- MySQL 使用的是 MyISAM 引擎,而 MyISAM 是不支持事务的。需要支持使用可以使用 InnoDB 引擎
- 如果使用了 Spring MVC ,context:component-scan 重复扫描问题可能会引起事务失败
- @Transactional 注解开启配置放到 DispatcherServlet 的配置里了。
- @Transactional 注解只能应用到 public 可见度的方法上。 在其他可见类型上声明,事务会失效。
- 在接口上使用 @Transactional 注解,只能当你设置了基于接口的代理时它才生效。所以如果强制使用了 CGLIB,那么事物会实效。
- @Transactional 同一个类中无事务方法 a() 内部调用有事务方法 b(),那么此时事物不生效。
5.怎样用注解的方式配置 Spring?
<beans>
<context:annotation-config/>
<!-- bean definitions go here -->
</beans>
下面是几种比较重要的注解类型:
- @Required:该注解应用于设值方法。
- @Autowired:该注解应用于有值设值方法、非设值方法、构造方法和变量。
- @Qualifier:该注解和@Autowired 注解搭配使用,用于消除特定 bean 自动装配的歧义。
- JSR-250 Annotations:Spring 支持基于 JSR-250 注解的以下注解,@Resource、@PostConstruct 和@PreDestroy。
6、SpringMVC 的流程?
- 用户发送请求至前端控制器 DispatcherServlet;
- DispatcherServlet 收到请求后,调用 HandlerMapping 处理器映射器,请求获取Handle
- 处理器映射器根据请求 url 找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给 DispatcherServlet;
- DispatcherServlet 调用 HandlerAdapter 处理器适配器;
- HandlerAdapter 经过适配调用 具体处理器(Handler,也叫后端控制器);
- Handler 执行完成返回 ModelAndView;
- HandlerAdapter 将 Handler 执 行 结 果 ModelAndView 返 回 给DispatcherServlet ;
- DispatcherServlet 将 ModelAndView 传 给ViewResolver 视图解析器进行解析;
- ViewResolver 解析后返回具体View;
- DispatcherServlet 对 View 进行渲染视图(即将模型数据填充至视图中)
- DispatcherServlet 响应用户。
7、Springmvc 的优点:
- 可以支持各种视图技术,而不仅仅局限于 JSP;
- 与 Spring 框架集成(如 IoC 容器、AOP 等);
- 清 晰 的 角 色 分 配 : 前 端 控 制 器 (dispatcherServlet) , 请 求 到处理器映射(handlerMapping), 处理器适配器(HandlerAdapter), 视图解析器(ViewResolver)。
- 支持各种请求资源的映射策略。
8. Spring 通知类型使用场景分别有哪些?
9.IoC 控制反转设计原理?
10.Spring 如何处理线程并发问题?
ThreadLocal 和线程同步机制都是为了解决多线程中相同变量的访问冲突问题。在同步机制中,通过对象的锁机制保证同一时间只有一个线程访问变量。这时该变量是多个线程共享的,使用同步机制要求程序慎密地分析什么时候对变量进行读写,什么时候需要锁定某个对象,什么时候释放对象锁等繁杂的问题,程序设计和编写难度相对较大。而 ThreadLocal 则从另一个角度来解决多线程的并发访问。 ThreadLocal 会为每一个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。因为每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。 ThreadLocal 提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的变量封装进 ThreadLocal。
由于 ThreadLocal 中可以持有任何类型的对象,低版本 JDK 所提供的 get()返回的是 Object 对象,需要强制类型转换。但 JDK 5.0 通过泛型很好的解决了这个问题,在一定程度地简化 ThreadLocal 的使用。概括起来说,对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式,而 ThreadLocal采用了“以空间换时间”的方式。前者仅提供一份变量,让不同的线程排队访问,而后者为每一个线程都提供了一份变量,因此可以同时访问而互不影响。
最后
欢迎大家一起交流,喜欢文章记得关注我点个赞哟,感谢支持!
欢迎大家关注我的公众号【以Java架构赢天下】,2019年多家公司java面试笔记整理了500多页pdf文档,文章都会在里面更新,整理的资料也会放在里面。
转载自:https://juejin.cn/post/6844904036777345037