一、Spring AOP与IOC的实现原理
1.IOC
IOC(控制反转)就是依赖倒置原则的一种代码设计思路。就是把原先在代码里面需要实现的对象创建、对象之间的依赖,反转给容器来帮忙实现。
Spring IOC容器通过xml,注解等其它方式配置类及类之间的依赖关系,完成了对象的创建和依赖的管理注入。实现IOC的主要设计模式是工厂模式。
使用IOC的好处
1、集中管理,实现类的可配置和易管理。
2、降低了类与类之间的耦合度。

2.AOP
AOP(面向切面)是一种编程范式,提供从另一个角度来考虑程序结构以完善面向对象编程(OOP)。
AOP为开发者提供了一种描述横切关注点的机制,并能够自动将横切关注点织入到面向对象的软件系统中,从而实现了横切关注点的模块化。
AOP能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任,例如事务处理、日志管理、权限控制等,封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。
使用AOP的好处
1、降低模块的耦合度
2、使系统容易扩展
3、提高代码复用性
AOP的基本概念
切面(Aspect):共有功能的实现。如日志切面、权限切面、验签切面等。在实际开发中通常是一个存放共有功能实现的标准Java类。当Java类使用了@Aspect注解修饰时,就能被AOP容器识别为切面。

通知(Advice):切面的具体实现。就是要给目标对象织入的事情。以目标方法为参照点,根据放置的地方不同,可分为前置通知(Before)、后置通知(AfterReturning)、异常通知(AfterThrowing)、最终通知(After)与环绕通知(Around)5种。在实际开发中通常是切面类中的一个方法,具体属于哪类通知,通过方法上的注解区分。

连接点(JoinPoint):程序在运行过程中能够插入切面的地点。例如,方法调用、异常抛出等。Spring只支持方法级的连接点。一个类的所有方法前、后、抛出异常时等都是连接点。

切入点(Pointcut):用于定义通知应该切入到哪些连接点上。不同的通知通常需要切入到不同的连接点上,这种精准的匹配是由切入点的正则表达式来定义的。

比如,在上面所说的连接点的基础上,来定义切入点。我们有一个类,类里有10个方法,那就产生了几十个连接点。但是我们并不想在所有方法上都织入通知,我们只想让其中的几个方法,在调用之前检验下入参是否合法,那么就用切点来定义这几个方法,让切点来筛选连接点,选中我们想要的方法。切入点就是来定义哪些类里面的哪些方法会得到通知。

目标对象(Target):那些即将切入切面的对象,也就是那些被通知的对象。这些对象专注业务本身的逻辑,所有的共有功能等待AOP容器的切入。

代理对象(Proxy):将通知应用到目标对象之后被动态创建的对象。可以简单地理解为,代理对象的功能等于目标对象本身业务逻辑加上共有功能。代理对象对于使用者而言是透明的,是程序运行过程中的产物。目标对象被织入共有功能后产生的对象。

织入(Weaving):将切面应用到目标对象从而创建一个新的代理对象的过程。这个过程可以发生在编译时、类加载时、运行时。Spring是在运行时完成织入,运行时织入通过Java语言的反射机制与动态代理机制来动态实现。
AOP 底层是动态代理,如果是接口采用 JDK 动态代理,如果是类采用
CGLIB 方式实现动态代理。
二、Spring中BeanFactory和FactoryBean的区别

  1. BeanFactory
    BeanFactory是一个factory,是spring的IOC的工场,而FactoryBean是个bean,它们两个只是名字很相似。
    BeanFactory是一个IOC工场,用于管理和创建Bean,它是IOC最基本的接口,为其他的IOC工场提供规范,很多其他的spring容器都实现了它,如ApplicationContext、XMLBeanFactory等。它提供了通过bean的名字获取实例、判断bean是否在工场中、判断是否为单例等方法。
  2. FactoryBean
    FactoryBean是一个bean,也是一个接口。用户可以通过实现该接口定制实例化Bean的逻辑。该接口中定义了三个方法,getObject(),返回实现了FactoryBean接口的类创建的bean实例,getObjectType返回该实例的类型,isSingleton判断该实例是否为单例。当一个类实现了FactoryBean后,如ABean实现了FactoryBean,通过容器使用getBean(String beanName),即applicationContext.getBean(“aBean”)返回的不是aBean对象,而是aBean实现getObject中生成的实例。

三、为什么CGLIG方式可以对接口实现代理?
CGLib代理的原理是通过二进制流生成一个动态class,该class继承被代理类以实现动态代理。那么就提供了一个代理无实现类的接口的可能。
四、RMI与代理模式
RMI简介
Java RMI是Remote Method Invocation的简称,即 远程方法调用(Remote Method Invocation),一种用于实现远程过程调用(RPC)(Remote procedure call)的Java API, 能直接传输序列化后的Java对象和分布式垃圾收集。它的实现依赖于Java虚拟机(JVM),因此它仅支持从一个JVM到另一个JVM的调用。
一个RMI对象是一个远 程Java对象,可以从另一个Java虚拟机上(甚至跨过网络)调用它的方法,可以像调用本地Java对象的方法一样调用远程对象的方法,使分布在不同的JVM中的对象的外表和行为都 像本地对象一样。
RMI提供了客户辅助对象(Stub)和服务辅助对象(Skeleton),为客户辅助对象创建和服务对象相同的方法。
RMI将客户辅助对象称为Stub(桩),服务辅助对象称为skeleton(骨架)
RMI需要注意的三个点:
1.启动远程服务绑定设备前,要先启动rmiregistry。如果使用Naming.rebind()注册服务的话。如果使用LocateRegistry创建registry的话,那么不需要
2.记得把变量和返回值类型定为可序列化。
3.记得给客户提供stub类,在服务端的时候要用rmic工具创建

RMI的好处:

不必写任何网络或I/O代码。

客户程序调用远程方法(即真正的服务所在)就和在运行本地JVM上对象进行正常方法调用一样。

lookup service 这个服务用来寻找和访问远程对象。

注意:I/O 和网络 是有网险的,容易失败,所以必须随时抛出异常。

五、Spring的事务隔离级别,实现原理

ISOLATION_DEFAULT:用底层数据库的默认隔离级别,数据库管理员设置什么就是什么
ISOLATION_READ_UNCOMMITTED(未提交读):最低隔离级别、事务未提交前,就可被其他事务读取(会出现幻读、脏读、不可重复读)
ISOLATION_READ_COMMITTED(提交读):一个事务提交后才能被其他事务读取到(该隔离级别禁止其他事务读取到未提交事务的数据、所以还是会造成幻读、不可重复读)、sql server默认级别
ISOLATION_REPEATABLE_READ(可重复读):可重复读,保证多次读取同一个数据时,其值都和事务开始时候的内容是一致,禁止读取到别的事务未提交的数据(该隔离基本可防止脏读,不可重复读(重点在修改),但会出现幻读(重点在增加与删除))(MySql默认级别,更改可通过set transaction isolation level 级别)
ISOLATION_SERIALIZABLE(序列化):代价最高最可靠的隔离级别(该隔离级别能防止脏读、不可重复读、幻读)
丢失更新:两个事务同时更新一行数据,最后一个事务的更新会覆盖掉第一个事务的更新,从而导致第一个事务更新的数据丢失,这是由于没有加锁造成的;
幻读:同样的事务操作过程中,不同时间段多次(不同事务)读取同一数据,读取到的内容不一致(一般是行数变多或变少)。
脏读:一个事务读取到另外一个未提及事务的内容,即为脏读。
不可重复读:同一事务中,多次读取内容不一致(一般行数不变,而内容变了)。
幻读与不可重复读的区别:幻读的重点在于插入与删除,即第二次查询会发现比第一次查询数据变少或者变多了,以至于给人一种幻象一样,而不可重复读重点在于修改,即第二次查询会发现查询结果比第一次查询结果不一致,即第一次结果已经不可重现了。

数据库隔离级别越高,执行代价越高,并发执行能力越差,因此在实际项目开发使用时要综合考虑,为了考虑并发性能一般使用提交读隔离级别,它能避免丢失更新和脏读,尽管不可重复读和幻读不能避免,但可以在可能出现的场合使用悲观锁或乐观锁来解决这些问题。
六、对Spring 的理解,非单例注入的原理?他的生命周期?循环注入的原理,aop的实现原理,说说aop的几个术语 怎么相互工作的
Spring 是一个开源框架,为简化企业级应用开发而生。Spring 可以是使简单的 JavaBean 实现以前只有 EJB 才能实现的功能。Spring 是一个 IOC 和 AOP 容器框架。
Spring 容器的主要核心是:
控制反转(IOC),传统的 java 开发模式中,当需要一个对象时,我们会自己使用 new 或者 getInstance 等直接或者间接调用构造方法创建一个对象。而在 spring 开发模式中,spring 容器使用了工厂模式为我们创建了所需要的对象,不需要我们自己创建了,直接调用 spring 提供的对象就可以了,这是控制反转的思想。
依赖注入(DI),spring 使用 javaBean 对象的 set 方法或者带参数的构造方法为我们在创建所需对象时将其属性自动设置所需要的值的过程,就是依赖注入的思想。
面向切面编程(AOP),在面向对象编程(oop)思想中,我们将事物纵向抽成一个个的对象。而在面向切面编程中,我们将一个个的对象某些类似的方面横向抽成一个切面,对这个切面进行一些如权限控制、事物管理,记录日志等公用操作处理的过程就是面向切面编程的思想。AOP 底层是动态代理,如果是接口采用 JDK 动态代理,如果是类采用
CGLIB 方式实现动态代理。
七、MyBatis的底层实现原理

  1. Mybatis 读取XML配置文件后会将内容放在一个Configuration类中,Configuration类会存在整个Mybatis生命周期,以便重复读取。SqlSessionFactoryBuilder会读取Configuration类中信息创建SqlSessionFactory。
  2. Mybatis中SqlSessionFactiory、SqlSession等都为接口,Mybatis默认使用的实现类为DefaultSqlSessionFactory和DefaultSqlSession类。
  3. SqlSession用途主要有两种

①. 获取对应的Mapper,让映射器通过命名空间和方法名称找到对应的SQL,发送给数据库执行后返回结果。

②. 直接使用SqlSession,通过命名信息去执行SQL返回结果,该方式是IBatis版本留下的,SqlSession通过Update、Select、Insert、Delete等方法操作。

针对Mapper方式,Mybatis底层利用JDK动态代理技术实现该接口,底层最后还是使用的IBatis中SqlSession通过Update、Select、Insert、Delete等方法操作。

4.关于对象的生命周期:

①. SqlSessionFactoryBuilder的作用是创建SqlSessionFactiory,在创建完成后就会被回收,所以它的生命周期只存在于局部方法。

②.SqlSessionFactiory是单例的,作用就是创建SqlSession,每次访问数据库都需要一个SqlSession,所以SqlSessionFactiory的生命周期是贯穿整个Mybatis生命周期的,SqlSessionFactiory采用单例的原因是减少数据库连接资源。

③. SqlSession是一个会话,类似于jdbc的connection,它的生命周期是在请求数据库处理事务过程中,他是一个线程不安全的对象。多线程操作时因多注意他的隔离级别和数据库锁等。SqlSession使用需及时关闭。

④. Mapper是一个接口,它的作用是发送SQL,返回结果,因此他的生命周期不会大于SqlSession

  1. 关于SqlSessionFactory的创建,Mybatis采用构造模式来完成创建。

第一步:XMLConfigBuilder解析XML配置,读出配置参数,存入Configuration类中。

第二步:Configuration类创建SqlSessionFactory。(DefaultSqlSessionFactory的构造函数传入Configuration类)

SqlSessionFactoryBuilder.builder(inputStream) inputStream为读取配置文件的流;该方法.builder中的主要内容:

XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
 SqlSessionFactory localSqlSessionFactory = build(parser.parse());

build(parser.parse())方法实则为:

public SqlSessionFactory build(Configuration config) {
 return new DefaultSqlSessionFactory(config);
 }
  1. 映射器由MappedStatement、SqlSource、BoundSql三部分组成。

①. MappedStatement,它保存着映射器的一个节点(select|update|insert|delete)。包括许多我们配置的SQL、SQL的ID、缓存信息、resultMap、parameterType、resultType等配置内容。

②. SqlSource,它提供BoundSql对象。是MappedStatement的一个属性。、

③. BoundSql,它是建立SQL和参数的地方,常用的三个属性:SQL、parameterObject、parameterMappings;

parameterObject就是我们传入的参数;

parameterMappings实则是List,ParameterMapping描述了我们的参数,包括属性、名称、表达式、javaType、jdbcType、typeHandler等重要信息,通过它实现参数和SQL的结合,以便PreparedStatement能够通过它找到parameterObject对象的属性并设置参数。

SQL则为我们写的SQL语句。

八、MVC框架原理,他们都是怎么做url路由的

a. 用户向服务器发送请求,请求被 springMVC 前端控制器 DispatchServlet 捕获;
b. DispatcherServle 对请求 URL 进行解析,得到请求资源标识符(URL),然后根据该 URL 调用 HandlerMapping
将请求映射到处理器 HandlerExcutionChain;
c. DispatchServlet 根据获得 Handler 选择一个合适的 HandlerAdapter 适配器处理;
d. Handler 对数据处理完成以后将返回一个 ModelAndView()对象给 DisPatchServlet;
e. Handler 返回的 ModelAndView() 只是一个逻辑视图并不是一个正式的视图, DispatcherSevlet 通过
ViewResolver 试图解析器将逻辑视图转化为真正的视图 View;
h. DispatcherServle 通过 model 解析出 ModelAndView()中的参数进行解析最终展现出完整的 view 并返回给客户端;

mvc框架中路由的原理:

所谓路由,就是程序根据浏览器上的url来进行程序分发处理(跳转)的功能代码。

我们使用框架的时候会发现一般的url请求是这样的:localhost/user/login/1 ,在这个url中我们不难发现:user为控制器的名字,而login为当前的控制器方法名,1为传入的参数(可能为用户类别)。
路由的原理:程序用$_SERVER获取url上的请求参数,获取相应位置的参数,然后加载相应的控制器方法并执行。
九、SpringBoot 特性,优势,适用场景
springboot主要特性
1、遵循习惯优于配置的原则。使用springboot我们只需要很少的配置,大多数使用默认配置即可
2、项目快速搭建。springboot帮助开发者快速搭建spring框架,可无需配置的自动整合第三方框架
3、可以完全不使用xml配置,只需要自动配置和Java config
4、内嵌servlet容器,降低了对环境的要求,可用命令直接执行项目
5、提供了starter POM,能够非常方便的进行包管理
6、对主流框架无配置集成
7、与云计算天然集成
优点:

1.去除了大量的xml配置文件

  2.简化复杂的依赖管理

  3.配合各种starter使用,基本上可以做到自动化配置

  4.快速启动容器

  5. 配合Maven或Gradle等构件工具打成Jar包后,Java -jar 进行部署运行还是蛮简单的

   创建独立Spring应用程序,嵌入式Tomcat,Jetty容器,无需部署WAR包,简化Maven及Gradle配置,尽可能的自动化配置Spring,直接植入产品环境下的实用功能,比如度量指标、健康检查及扩展配置等,无需代码生成及XML配置。

缺点:
1.从原来的xml配置方式转换到JAVA配置方式变化有点大,不太适应
2.Spring Boot 比较适合做微服务,不适合做比较大型的项目。
使用场景:
1.有spring的地方
2. J2ee应用
3. 3.微服务
十、quartz和timer对比

  1. 精确度和功能 Quartz可以通过cron表达式精确到特定时间执行,而TimerTask不能。Quartz拥有TimerTask所有的功能,而 TimerTask则没有。
    2 . Quartz每次执行任务都创建一个新的任务类对象,而TimerTask则每次使用同一个任务类对象。3. 3. Quartz的某次执行任务过程中抛出异常,不影响下一次任务的执行,当下一次执行时间到来时,定时器会再次执行任务;而TimerTask则不同,一旦某个任务在执行过程中抛出异常,则整个定时器生命周期就结束,以后永远不会再执行定时器任务。

十一、Spring 的controller 是单例还是多例,怎么保证并发的安全
controller默认是单例的,不要使用非静态的成员变量,否则会发生数据逻辑混乱。
正因为单例所以不是线程安全的。
解决方案
1、不要在controller中定义成员变量。
2、万一必须要定义一个非静态成员变量时候,则通过注解@Scope(“prototype”),将其设置为多例模式。这样每次请求调用的类都是重新生成的(每次生成会影响效率)
3、在Controller中使用ThreadLocal来保存类变量,将类变量保存在线程的变量域中,让不同的请求隔离开来。