1.Mybatis

1.1 谈一谈你对Mybatis框架的理解

  • Mybatis是一个半ORM框架,它内部封装了JDBC,使用它可以简化持久层的操作,使程序员在开发时只需要关注SQL语句即可。

1.2 在mybatis中,${} 和 #{} 的区别是什么?

  1. Mybatis中#{}是预编译处理,${}是字符串替换
  2. Mybatis在处理#{}时,会将sql中的#{}替换为?号,然后调用PreparedStatement进行数据库操作,此方式不存在sql注入问题
    Mybatis在处理${}时,就是把它替换成变量的值,然后调用Statement进行数据库操作,此方式存在sql注入问题
  3. 如果使用#{}接收一个简单类型的参数,{}中可以随便写;如果使用${}接收一个简单类型的参数,{}中只能写value

1.3 在mybatis中,resultType和ResultMap的区别是什么?

  • 如果数据库结果集中的列名和要封装实体的属性名完全一致的话用 resultType 属性
  • 如果数据库结果集中的列名和要封装实体的属性名有不一致的情况用 resultMap 属性,通过resultMap手动建立对象关系映射

1.4 在Mynbatis中你知道的动态SQL的标签有哪些?作用分别是什么?

  1. <if>if是为了判断传入的值是否符合某种规则,比如是否不为空.</if>
  2. <where> where标签可以用来做动态拼接查询条件,当和if标签配合的时候,不用显示的声明类型where 1 = 1这种无用的条件</where>
  3. <foreach> foreach标签可以把传入的集合对象进行遍历,然后把每一项的内容作为参数传到sql语句中.</foreach>
  4. <include> include可以把大量的重复代码整理起来,当使用的时候直接include即可,减少重复代码的编写;</include>
  5. <set>适用于更新中,当匹配某个条件后,才会对该字段进行跟新操作</set>

1.5 在mybatis中,Dao接口中的方法支持重载吗? 为什么?

  • 不支持。
    在Mybatis中,要求接口的方法名要跟映射文件中的ID一致,而ID又是不能重复的;如果接口中的方法重载了,就意味着映射文件中的ID会出现重复的情况,会出异常。

1.6 谈一下你对mybatis缓存机制的理解?

  • Mybatis有两级缓存,一级缓存是SqlSession级别的,默认开启,无法关闭;二级缓存是Mapper级别的,默认开启,但是可以关闭
    1. 一级缓存:基础PerpetualCache的HashMap本地缓存,其存储作用域为Session,当Session flush或close之后,Session中的所有Cache就将清空
    2. 二级缓存默认也是采用PerpetualCache的HashMap存储,不同在于其存储作用域为Mapper(Namespace),使用二级缓存属性类需要实现Serializable序列化接口
    3. 对于缓存数据更新机制,当某一个作用域(一级缓存Session/二级缓存Namespaces)的进行了C/U/D操作后,默认该作用域下所有select中的缓存将被clear.

2.Spring

2.1 Spring的两大核心是什么?谈一谈你对IOC的理解? 谈一谈你对DI的理解? 谈一谈你对AOP的理解?

  1. Spring的两大核心是:IOC(依赖注入)和AOP(面向切面编程)

  2. IOC的意思是控制反转,是指创建对象的控制权的转移,以前创建对象的主动权和时机是由自己把控的,而现在这种权力转移到Spring容器中,并由容器根据配置文件去创建实例和管理各个实例之间的依赖关系,对象与对象之间松散耦合,也利于功能的复用。最直观的表达就是,IOC让对象的创建不用去new了,可以由spring根据我们提供的配置文件自动生产,我们需要对象的时候,直接从Spring容器中获取即可.
    c

  3. DI的意思是依赖注入,和控制反转是同一个概念的不同角度的描述,即应用程序在运行时依赖Ioc 容器来动态注入对象需要的外部资源。

  4. AOP,一般称为面向切面编程,作为面向对象的一种补充,用于将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块,这个模块被命名为“切面”(Aspect). SpringAOP使用的动态代理,所谓的动态代理就是说AOP框架不会去修改字节码,而是每次运行时在内存中临时为方法生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法。

2.2 你能说出Spring的详细生命周期吗?

  1. 实例化一个Bean,也就是我们通常说的new

  2. 按照Spring上下文对实例化的Bean进行配置,也就是IOC注入

  3. 如果这个Bean实现dao的BeanNameAware接口,会调用它实现的setBeanName(String beanId)方法,此处传递的是Spring配置文件中Bean的ID

  4. 如果这个Bean实现了BeanFactoryAware接口,会调用它实现的setBeanFactory(),传递的是Spring工厂本身(可以用这个方法获取到其他Bean)

  5. 如果这个Bean实现了ApplicationContextAware接口,会调用setApplicationContext(ApplicationContext)方法,传入Spring上下文,该方式同样可以实现步骤4,但比4更好,因为ApplicationContext是BeanFactory的子接口,有更多的实现方法

  6. 如果这个Bean关联了BeanPostProcessor接口,将会调用postProcessBeforeInitialization(Object obj, String s)方法,BeanPostProcessor经常被用做对Bean内容的更改,并且由于这个是在Bean初始化结束时调用After方法,也可用于内存或缓存技术

  7. 如果这个Bean在Spring配置文件中配置了init-method属性会自动调用其配置的初始化方法

    注意:以上工作完成以后就可以用这个Bean了,那这个Bean是一个single的,所以一般情况下我们调用同一个ID的Bean会是在内容地址相同的实例

  8. 当Bean不再需要时,会经过清理阶段,如果Bean实现了DisposableBean接口,会调用其实现的destroy方法

  9. 最后,如果这个Bean的Spring配置中配置了destroy-method属性,会自动调用其配置的销毁方法

2.3 你知道Spring支持bean的作用域有几种吗?每种作用域是什么样的?
Spring支持如下5种作用域:

  • singleton:单例模式(默认作用域),在整个Spring IoC容器中,使用singleton定义的Bean将只有一个实例
  • prototype:原型模式,每次通过容器的getBean方法获取Bean时,都将产生一个新的Bean实例
  • request:对于每次HTTP请求,使用request定义的Bean都将产生一个新实例,即每次HTTP请求将会产生不同的Bean实例。只有在Web应用中使用Spring时,该作用域才有效
  • session:对于每次HTTP Session,使用session定义的Bean豆浆产生一个新实例。同样只有在Web应用中使用Spring时,该作用域才有效
  • globalsession:每个全局的HTTP Session,使用session定义的Bean都将产生一个新实例。同样只有在Web应用中使用Spring时,该作用域才有效

2.4 BeanFactory和ApplicationContext有什么区别

  • BeanFactory:
    Spring最顶层的接口,实现了Spring容器的最基础的一些功能, 调用起来比较麻烦, 一般面向Spring自身使用
    BeanFactory在启动的时候不会去实例化Bean,中有从容器中拿Bean的时候才会去实例化
  • ApplicationContext:
    BeanFactory的子接口,扩展了其功能, 一般面向程序员身使用
    ApplicationContext在启动的时候就把所有的Bean全部实例化了

2.5 Spring框架中都用到了哪些设计模式?

  1. 工厂模式:BeanFactory就是简单工厂模式的体现,用来创建对象的实例
  2. 单例模式:Bean默认为单例模式
  3. 代理模式:Spring的AOP功能用到了JDK的动态代理和CGLIB字节码生成技术
  4. 模板方法:用来解决代码重复的问题。比如. RestTemplate, JmsTemplate, JpaTemplate
  5. 观察者模式:定义对象键一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知被制动更新,如Spring中listener的实现--ApplicationListener

2.6 Spring事务的实现方式和实现原理
Spring事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring是无法提供事务功能的。真正的数据库层的事务提交和回滚是通过binlog或者redo log实现的。

spring事务实现主要有两种方法
1、编程式,beginTransaction()、commit()、rollback()等事务管理相关的方法
2、声明式,利用注解Transactional 或者aop配置

参考面试宝典5.14

2.7 你知道的Spring的通知类型有哪些,分别在什么时候执行?

  • Spring的通知类型有四种,分别为:
    前置通知[]before]:在切点运行之前执行
    后置通知[after-returning]:在切点正常结束之后执行
    异常通知[after-throwing]:在切点发生异常的时候执行
    最终通知[after]:在切点的最终执行
  • Spring还有一种特殊的通知,叫做环绕通知
    环绕通知运行程序员以编码的方式自己定义通知的位置, 用于解决其他通知时序问题

2.8 Spring的对象默认是单例的还是多例的? 单例bean存不存在线程安全问题呢?

  1. 在spring中的对象默认是单例的,但是也可以配置为多例。
  2. 单例bean对象对应的类存在可变的成员变量并且其中存在改变这个变量的线程时,多线程操作该bean对象时会出现线程安全问题。
    原因是:多线程操作如果改变成员变量,其他线程无法访问该bean对象,造成数据混乱。
    解决办法:
    (1) 在bean对象中避免定义可变成员变量;
    (2) 在bean对象中定义一个ThreadLocal成员变量,将需要的可变成员变量保存在ThreadLocal中。

2.9 @Resource和@Autowired依赖注入的区别是什么? @Qualifier使用场景是什么?

  • @Resource
    只能放在属性上,表示先按照属性名匹配IOC容器中对象id给属性注入值若没有成功,会继续根据当前属性的类型匹配IOC容器中同类型对象来注入值
    若指定了name属性@Resource(name = "对象id"),则只能按照对象id注入值。
  • @Autowird
    放在属性上:表示先按照类型给属性注入值如果IOC容器中存在多个与属性同类型的对象,则会按照属性名注入值
    也可以配合@Qualifier("IOC容器中对象id")注解直接按照名称注入值。
    放在方法上:表示自动执行当前方法,如果方法有参数,会自动从IOC容器中寻找同类型的对象给参数传值
    也可以在参数上添加@Qualifier("IOC容器中对象id")注解按照名称寻找对象给参数传值。
  • @Qualifier使用场景:
    @Qualifier("IOC容器中对象id")可以配合@Autowird一起使用, 表示根据指定的id在Spring容器中匹配对象