最近有一位朋友和我说,他作了开发 3 年了,最近去面试时,Spring 被面试官问得哑口无言,他总结了下面几道被问到的关于 Spring 的面试题,能够参考下。前端
1.1.定义java
1.1.1.IoC面试
1.1.2.AOP编程
Aspect Oriented Programming,面向切面编程。经过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP 是 OOP 的延续,是软件开发中的一个热点,也是 Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用 AOP 能够对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度下降,提升程序的可重用性,同时提升了开发的效率。其中,最经常使用的使用场景通常有日志模块、权限模块、事物模块。后端
1.2.原理缓存
1.2.1.IoC安全
还有其余的类不一一列举出来,都在 java.lang.reflect 包下。说到这个模块的时候,那么面试官可能会考察相关的知识,主要是考察你是否真的有去了解过反射的使用。举两个例子: bash
这里其实就是里面的重要考察点就是反射对私有属性的处理。多线程
/**
* 经过反射获取私有的成员变量.
*/
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 原理是动态生成被代理类的子类。
循环依赖就是 N 个类中循环嵌套引用,这样会致使内存溢出。循环依赖主要分两种:
Spring 初始化单例对象大致是分为以下三个步骤的:
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);
}
}
}复制代码
可能的缘由:
<beans>
<context:annotation-config/>
<!-- bean definitions go here -->
</beans>复制代码
下面是几种比较重要的注解类型:
ThreadLocal 和线程同步机制都是为了解决多线程中相同变量的访问冲突问题。在同步机制中,经过对象的锁机制保证同一时间只有一个线程访问变量。这时该变量是多个线程共享的,使用同步机制要求程序慎密地分析何时对变量进行读写,何时须要锁定某个对象,何时释放对象锁等繁杂的问题,程序设计和编写难度相对较大。而 ThreadLocal 则从另外一个角度来解决多线程的并发访问。 ThreadLocal 会为每个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。由于每个线程都拥有本身的变量副本,从而也就没有必要对该变量进行同步了。 ThreadLocal 提供了线程安全的共享对象,在编写多线程代码时,能够把不安全的变量封装进 ThreadLocal。
因为 ThreadLocal 中能够持有任何类型的对象,低版本 JDK 所提供的 get()返回的是 Object 对象,须要强制类型转换。但 JDK 5.0 经过泛型很好的解决了这个问题,在必定程度地简化 ThreadLocal 的使用。归纳起来讲,对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式,而 ThreadLocal采用了“以空间换时间”的方式。前者仅提供一份变量,让不一样的线程排队访问,然后者为每个线程都提供了一份变量,所以能够同时访问而互不影响。
欢迎你们一块儿交流,喜欢文章记得关注我点个赞哟,感谢支持!
欢迎你们关注个人公众号【以Java架构赢天下】,2019年多家公司java面试笔记整理了500多页pdf文档,文章都会在里面更新,整理的资料也会放在里面。