Spring篇
Spring框架中用到了哪些设计模式
单例模式:Bean默认为单例模式。
工厂模式:BeanFactory是一个简单工厂模式,用来创建对象实例。
代理模式:Spring的AOP功能用到了JDK的动态代理和CGLIB动态代理。
模板方法模式:用来解决代码重复的问题。比如. RestTemplate, JmsTemplate, JpaTemplate。
观察者模式:当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知被自动更新。例如ApplicationListener。
Spring IOC和DI是什么?
IOC:控制反转。将对象的创建、初始、销毁和对象间的关系交给Spring来管理。
DI:依赖注入。由容器动态的将某种依赖关系注入到组件中。
注:Spring DI是通过反射实现注入的,因为反射允许程序在运行时动态的生成对象、执行对象的方法、修改对象的属性。
Spring如何解决循环依赖⭐
spring中产生循环依赖有三种情况:
- 构造器注入形成循环依赖:beanA需要在beanB的构造函数中完成初始化,beanB也需要在beanA的构造函数中完成初始化。这种情况会导致两个bean都无法完成初始化,循环依赖难以解决。
- prototype作用域bean的循环依赖:这种循环依赖同样无法解决,因为spring不会缓存 prototype 作用域的bean,而spring中循环依赖的解决正是通过缓存来实现的。
- setter注入形成循环依赖:beanA需要在beanB的setter方法中完成初始化,beanB也需要在beanA的setter方法中完成初始化。
Spring解决setter注入形成的循环依赖方案:
- beanA进行初始化,并将自己进行初始化的状态记录下来,向外暴露一个方法,使其他bean能引用到该bean。
- beanA中有beanB的依赖,开始初始化beanB
- 初始化beanB的过程中又发现beanB依赖了beanA,于是双进行beanA的初始化,此时发现beanA已经初始化了,程序发现了存在的循环依赖,然后通过beanA暴露的方法拿到beanA的引用,完成注入,完成初始化。
请谈一谈Spring中自动装配的方式有哪些?
no
:不进行自动装配,手动设置Bean对象的依赖关系
byName
:根据Bean对象的名字进行自动装配
byType
:根据Bean对象的类型进行自动装配
constructor
:类似于byType,不过是应用于构造器的参数,若正好有一个Bean对象与构造器的参数类型相同,则可以自动装配,否则 会导致错误
autodetect
:如果有默认的构造器,则通过constructor方式进行自动装配;否则 使用byType的方式进行自动装配
SpringMVC篇
SpringMVC的加载流程⭐
用户发送请求到前端控制器(DispatcherServlet)。
DispatcherServlet接收到请求后,调用处理器映射器(HandlerMapping)。
HandlerMapping根据请求的url获取具体的Handler,并返回给DispatcherServlet。
DispatcherServlet调用处理器适配器(HandlerAdapter)。
HandlerAdapter经过适配调用具体的处理器(Handler)。
Handler执行完后,返回ModelAndView。
HandlerAdapter将ModelAndView返回给DispatcherServlet。
DispatcherServlet将ModelAndView传给视图解析器(ViewResolver)进行解析。
ViewResolver解析后返回具体的视图(View)。
DispatchServlet对View进行视图渲染,最后响应用户。
SpringMVC中函数的返回值有哪些?
- Spring
- void
- ModelAndView
SpringMVC用什么对象从后台向前台传递数据?
- Model 对象
- ModeMap 对象
Spring MVC的控制器是不是单例模式,如果是,有什么问题,怎么解决?
是单例模式,所以在多线程访问的时候有线程安全问题,不要用同步,会影响性能的,解决方案是在控制器里面不能写字段。
注解原理
注解本质上是一个继承了 Annotation接口,其具体实现类是Java运行时生成的动态代理类。通过反射获取注解时,返回的是Java运行时生成的动态代理对象
。通过代理对象调用自定义注解的方法,
最终调用AnnotationInvocaitonHandle的invoke方法。
MyBatis篇
#{}和${}的区别
#{}是预编译处理,${}是字符串替换
- MyBatis处理 #{} 时,会将 SQL语句中的
#{}
替换成? 号
,调用 PreparedStatement的set方法来进行赋值; - MyBatis处理 时,只是把 ‘ {} 时,只是把 ` 时,只是把‘{}`替换成变量的值;
注:#{} 可以防止SQL注入,提交系统安全性。
动态sql的作用?简述一下动态sql的执行原理
动态SQL是以标签的形式编写SQL,完成逻辑判断和动态拼接SQL的功能;
常用的标签:if|where|trim|foreach|choose|otherwise|when|bind|set;
执行原理:使用 OGNL 从SQL参数对象中计算表达式的值,根据表达式的值动态拼接SQL,以此完成动态SQL的功能。
当实体类中的属性名和表中的字段名不一样,怎么处理?
- 定义字段名的别名,让字段名的别名和实体类的属性名一致。
- 通过resultMap来映射字段名和属性名一一对应
通常⼀个Xml 映射文件,都会写一个Dao接口与之对应,请问,这个 Dao 接口的工作原理是什么?Dao 接口里的方法,参数不同时,方法能重载吗?
Dao接口的全限名就是映射文件中的 namespace 属性的值;接口的方法名,就是映射文件是 Dao 的 Statement的 id 属性值,接口方法内的参数就是传递给 SQL的参数。
Dao接口是没有实现类的,当调用接口时,接口全限名和方法名拼接字符串作为key值,可唯一定位一个 MappedStatement对象。
例: com.m3.dao.UserDao.findUserById ,可以唯⼀找到 namespace 值为com.m3.dao.UserDao 下⾯ id 值为 findUserById 的 MappedStatement 。 在 Mybatis 中,每⼀个 <select>
、 <insert>
、 <update>
、 <delete>
标签,都会被解析为⼀个 MappedStatement 对象。
Dao接口的工作原理
MyBatis运行时会使用JDK动态代理为Dao接口生成代理Proxy对象,代理对象会拦截接口方法,转而执行MappedStatement所代表的SQL,然后将SQL执行结果返回。
Dao接口中的方法,是不能重载的,因为MyBatis通过全限名+方法名的保存和寻找策略。
Mybatis的XML映射文件中,不同的XML映射文件,id是否可以重复?
不同的XML映射文件,若配置了namespace,那么id可以重复;若没有配置,则id不可以重复;
因为namespace+id是作为
Map<String, MappedStatement>
的key使用的,若没有namespace,那么id重复会导致数据互相覆盖。反之,namespace不同,namespace+id也就不同
使用MyBatis的Dao接口调用时有哪些要求
- 接口中的方法名与XML中定义的每个SQL的id相同;
- 接口中的方法名的参数类型与XML中定义的每个SQL的parameterType的类型相同;
- 接口中的方法名的返回值类型与XML中定义的每个SQL的resultType的类型相同;
- XML中的namespace值就是接口的全路径;
MyBatis中的一级缓存和二级缓存
一级缓存:基于PerpetualCache 的 HashMap本地缓存,其存储作用域为 SqlSession,当SqlSession调用flush或close 后,该SqlSession中的所有Cache将清空。默认打开一级缓存。
二级缓存:也是采用 PerpetualCache的HashMap本地存储,不同在于其存储作用域为 SQLSessionFactory,并且可自定义存储源,如 Ehcache。默认不打开二级缓存,要开启二级缓存,使用二级缓存属性类需要实现Serializable序列化接口(可用来保存对象的状态),可在它的映射文件中配置 <cache/>
;
缓存数据更新机制:当某一个作用域(一级缓存 SqlSession/二级缓存SqlSessionFactory)的进行了CUD操作后,默认该作用域下所有select中的缓存将被清除
。