1. aop、ioc原理

控制反转的概念和依赖注入是分不开的。
控制反转的意思就是,从原先的对象由java代码控制,变为了由spring容器来统一管理
(具体的控制方式就是applicationContext等配置文件或注释)。这就是所谓的控制反转,被容器管理的对象被成为 bean 。


        AOP 实现的关键就在于 AOP 框架自动创建的 AOP 代理,AOP 代理则可分为静态代理和动态代理两大类。

        其中静态代理是指使用 AOP 框架提供的命令进行编译,从而在编译阶段就可生成 AOP 代理类,因此也称为编译时增强;而动态代理则在运行时借助于 JDK 动态代理、CGLIB 等在内存中“临时”生成 AOP 动态代理类,因此也被称为运行时增强。

        Spring AOP采用的是动态代理,在运行期间对业务方法进行增强,所以不会生成新类,
对于动态代理技术,Spring AOP提供了对JDK动态代理的支持以及CGLib的支持。前者是基于反射技术的实现,后者是基于继承的机制实现。如果目标对象有实现接口,使用jdk代理。如果目标对象没有实现接口,则使用Cglib代理。

        JDK 动态代理只需要实现 InvocationHandler 接口,重写 invoke 方法便可以完成代理的实现。

        CGLib 采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑,来完成动态代理的实现。

 2. 对象的浅拷贝和深拷贝

浅拷贝是指拷贝对象时仅仅拷贝对象本身(包括对象中的基本变量),而不拷贝对象包含的引用指向的对象。
深拷贝不仅拷贝对象本身,而且拷贝对象包含的引用指向的所有对象。


举例来说更加清楚:对象A1中包含对B1的引用,B1中包含对C1的引用。
浅拷贝A1得到A2,A2 中依然包含对B1的引用,B1中依然包含对C1的引用。
深拷贝则是对浅拷贝的递归,深拷贝A1得到A2,A2中包含对B2(B1的copy)的引用,B2 中包含对C2(C1的copy)的引用。

3. linkedHashMap为什么能做到插入有序

LinkedHashMap采用的hash算法和HashMap相同,但是它重新定义了数组中保存的元素Entry,该Entry除了保存当前对象的引用外,还保存了其上一个元素before和下一个元素after的引用,从而在哈希表的基础上又构成了双向链接列表。这样就能按照插入的顺序遍历原本无序的HashMap。

4. spring的作用域有哪些

singleton:在 Spring 容器中仅存在一个 Bean 实例, Bean 以单例的形式存在。
prototype:每次从容器中调用 Bean 时,都会返回一个新的实例,即相当于执行 new XxxBean() 的实例化操作。
request: 每次 http 请求都会创建一个新的 Bean , 仅用于 WebApplicationContext 环境。
session: 同一个 http Session 共享一个 Bean ,不同的 http Session 使用不同的 Bean,仅用于 WebApplicationContext 环境。
globalSession: 同一个全局 Session 共享一个 bean, 用于 Porlet, 仅用于 WebApplication 环境。 

5. springmvc具体的流程

<1>用户请求前端控制器DispatcherServlet
<2>DispatcherServlet收到请求调用HandlerMapping处理器映射器,返回处理器
<3>DispatcherServlet调用处理器适配器找到具体的处理器
<4>处理器Controller执行完成返回ModelAndView
<5>处理器适配器收到ModelAndView返回给DispatcherServlet
<6>DispatcherServlet调用视图解析器返回View
<7>DispatcherServlet根据view进行渲染试图,将模型数据填充到视图
<8>DispatcherServlet响应用户 

6. spring循环依赖的解决方式 

        在xml中注入bean并且设置为set的注入方式,spring注入bean默认为单例模式,而spring为了解决单例的循环依赖问题.设置了三级缓存,非单例则不被允许。

        

        singletonObjects指单例对象的cache。
        earlySingletonObjects指提前曝光的单例对象的cache。
        singletonFactories指单例对象工厂的cache。


当一个对象A初始化第一步(需要执行构造方法)完成,这样在初始化第二步的时候,发现B没有被创建,去创建B的时候去前两级缓存去查A发现没有,
去三级缓存查找的时候,由于A将自己通过ObjectFactory提前曝光了,B就能找到A,B初始化成功,返回给A,然后A也能初始化成功。

7. springboot 启动流程

springboot启动流程主要分为三个部分,第一部分进行SpringApplication的初始化模块,配置一些基本的环境变量、资源、构造器、监听器,第二部分实现了应用具体的启动方案,包括启动流程的监听模块、加载配置环境模块、及核心的创建上下文环境模块,第三部分是自动化配置模块,该模块作为springboot自动配置核心,在后面的分析中会详细讨论。在下面的启动程序中我们会串联起结构中的主要功能。


每个SpringBoot程序都有一个主入口,也就是main方法,main里面调用SpringApplication.run()启动整个spring-boot程序,
该方法所在类需要使用@SpringBootApplication注解,@SpringBootApplication包括三个注解,功能如下:

@EnableAutoConfiguration:SpringBoot根据应用所声明的依赖来对Spring框架进行自动配置该配置模块的主要使用到了SpringFactoriesLoader,即Spring工厂加载器,该对象提供了loadFactoryNames方法,入参为factoryClass和classLoader,即需要传入上图中的工厂类名称和对应的类加载器,方法会根据指定的classLoader,
加载该类加器搜索路径下的指定文件,即spring.factories文件,传入的工厂类为接口,而文件中对应的类则是接口的实现类,或最终作为实现类,所以文件中一般为如下图这种一对多的类名集合,获取到这些实现类的类名后,loadFactoryNames方法返回类名集合,
方法调用方得到这些集合后,再通过反射获取这些类的类对象、构造方法,最终生成实例。


注:AutoConfigurationImportSelector的selectImports方法
该方法中的getCandidateConfigurations方法,通过方法注释了解到,其返回一个自动配置类的类名列表,方法调用了loadFactoryNames方法,自动加载

@SpringBootConfiguration(内部为@Configuration):被标注的类等于在spring的XML配置文件中(applicationContext.xml),装配所有bean事务,提供了一个spring的上下文环境Springboot的启动,主要创建了配置环境(environment)、事件监听(listeners)、应用上下文(applicationContext),并基于以上条件,在容器中开始实例化我们需要的Bean,至此,通过SpringBoot启动的程序已经构造完成,接下来我们来探讨自动化配置是如何实现。


@ComponentScan:组件扫描,可自动发现和装配Bean,默认扫描SpringApplication的run方法里的Booter.class所在的包路径下文件,所以最好将该启动类放到根包路径下


8. java的NIO/零拷贝技术

 java的NIO本质上使用了零拷贝技术,减少cpu的切换次数,其中transferTo()方法调用了底层的sendFile,避免了内核缓冲区和用户缓冲区的拷贝,零拷贝技术还有一个重要的点就是DMA,它本质上是主板上的一颗独立的芯片,允许外设设备和内存存储器进行数据传输。

 9. spring的生命周期

实例化 Instantiation  createBeanInstance
属性赋值 populateBean
初始化 Initialization  InitializingBean#afterPropertiesSet
销毁 Destruction

10. spring的事务传播机制

REQUIRED(Spring默认的事务传播类型):如果当前没有事务,则自己新建一个事务,如果当前存在事务,则加入这个事务
SUPPORTS:当前存在事务,则加入当前事务,如果当前没有事务,就以非事务方法执行
MANDATORY:当前存在事务,则加入当前事务,如果当前事务不存在,则抛出异常
REQUIRES_NEW:创建一个新事务,如果存在当前事务,则挂起该事务
NOT_SUPPORTED:以非事务方式执行,如果当前存在事务,则挂起当前事务
NEVER:不使用事务,如果当前事务存在,则抛出异常
NESTED:如果当前事务存在,则在嵌套事务中执行,否则REQUIRED的操作一样(开启一个事务) 

11.  几种类型的类加载器

1.启动类加载器(Bootstrap ClassLoader):这个类加载器复杂将存放在 JAVA_HOME/lib 目录中的,或者被-Xbootclasspath 参数所指定的路径种的,并且是虚拟机识别的(仅按照文件名识别,如rt.jar,名字不符合的类库即使放在lib目录下也不会重载)。


2.扩展类加载器(Extension ClassLoader):这个类加载器由sun.misc.Launcher$ExtClassLoader实现,它负责夹杂JAVA_HOME/lib/ext 目录下的,或者被java.ext.dirs 系统变量所指定的路径种的所有类库。开发者可以直接使用扩展类加载器。

3.应用程序类加载器(Application ClassLoader):这个类加载器由sun.misc.Launcher$AppClassLoader 实现。由于这个类加载器是ClassLoader 种的getSystemClassLoader方法的返回值,所以也成为系统类加载器。它负责加载用户类路径(ClassPath)上所指定的类库。开发者可以直接使用这个类加载器,如果应用中没有定义过自己的类加载器,一般情况下这个就是程序中默认的类加载器。

12. 双亲委派模型

双亲委派模型要求除了顶层的启动类加载器之外,其余的类加载器都应当由自己的父类加载器加载。


双亲委派模型的工作过程是:如果一个类加载器收到了类加载的请求,他首先不会自己去尝试加载这个类,而是把这个请求委派父类加载器去完成。
每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有当父加载器反馈自己无法完成这个请求(他的搜索范围中没有找到所需的类)时,子加载器才会尝试自己去加载。