Spring部分面试知识
对Spring的理解
spring是一个轻量级的开源框架,贯穿持久层、业务逻辑层、控制层。让每一个功能模块都可以独立的分开,降低耦合度,提高代码复用度。spring通过控制反转降低耦合性,一个对象的依赖通过被动的注入而非主动的new。spring还包括面向切面、MVC整合等等。以上是我对spring的浅显认识。
Spring IOC的理解
控制反转,指由Spring来控制对象的生命周期和对象间的关系。以前对象的创建时机是由自己把握的,开发人员主动创建对象,现在由IOC容器创建,然后注入。所有的类都会在IOC容器中注册,告诉spring你是什么,你需要什么,spring容器在合适的时机将你所需要的东西给你,控制对象生命周期的不再是引用它的对象而是spring容器。
spring先加载xml文件,Bean先在spring容器中注册,然后会进行初始化Bean,再将Bean存到容器的缓存区(Map),谁需要就给它注入,而且缓存区的对象还在,一直在,这属于单例,直到关闭spring。(scope见下面)
DI:依赖注入,动态的向某个对象注入它所需要的对象。
SpringAOP(拦截器的实现原理)
http://www.cnblogs.com/xiaolovewei/p/7919763.html
Spring事务
http://www.cnblogs.com/xiaolovewei/p/9418874.html
Spring 中的scope ,也就是Bean的作用域
scope有Singleton、Prototype、request、session、global session。其中主要的是singleton和prototype。
singleton指的是IOC容器中只存在一个实例,所有对该对象的引用都要共享该实例。该对象自从第一次被创建以后,直到容器退出才会被销毁。就像上面说的,容器中有一个缓存区(MAP)保管这个单例。
prototype:IOC容器接收到对该对象的请求时,就会新建一个对象实例给对方。返回给对方以后,IOC容器就不在持有该对象的引用,也就是IOC只负责创建该对象实例,置于销毁,就不管了。
request:XmlWebApplicationContext会为每个HTTP请求创建一个对象,当请求结束,该对象也就被销毁。
session:会为每个session创建一个对象,存活时间为session
Spring常见创建对象的注解?
@Component@Controller@ Service@ Repository <context:compenent-scan base-package="">
xml:<bean>无参构造器、静态工厂(get方法)。
对象(属性)注入的方式
xml:set方法(<property name value>)、构造器(<constructor-arg name value>)
注解:Autowired、Resource
Spring中用到的设计模式
答:简单工厂、工厂方法、单例模式、适配器、包装器、代理、观察者、策略、模板方法
Spring的优点?
答:1.降低了组件之间的耦合性 ,实现了软件各层之间的解耦
2.可以使用容易提供的众多服务,如事务管理,消息服务等
3.容器提供单例模式支持
4.容器提供了AOP技术,利用它很容易实现如权限拦截,运行期监控等功能
5.容器提供了众多的辅助类,能加快应用的开发
6.spring对于主流的应用框架提供了集成支持,如hibernate,JPA,Struts等
7.spring属于低侵入式设计,代码的污染极低
8.独立于各种应用服务器
9.spring的DI机制降低了业务对象替换的复杂性
10.Spring的高度开放性,并不强制应用完全依赖于Spring,开发者可以自由选择spring 的部分或全部
Spring 的自动装配
https://www.cnblogs.com/xiaolovewei/p/9424804.html
byName/byType/constructor
我们在xml中注入对象,使用<property>属于手动装配,自动装配不需要写这个。如byName,类中对象的属性名与bean的名字一样(id)则直接注入。
Autowired和Resource
https://www.cnblogs.com/xiaolovewei/p/9424856.html
Autowired默认使用byType,单例没问题,Spring的注解。如果想使用byName,则和Qualifier("")一起使用。
Resource(name="")默认byName。J2EE的注解
Spring保证安全性
首先,Controller、Dao、service都是单例的,就有可能出现多线程的安全问题----有类成员变量,这样多线程访问就会使用到共享变量了。
避免:不要使用类成员变量,这样就不会有共享变量了。或者使用ThreadLocal
使用多例,scope="property"。这样每个线程都有自己的对象,就不会出现问题。
SpringMVC理解
spring MVC 其实就是 spring 自己做了一套很合适的 controller层 框架。结合性更好。 这个东西的核心就是 Dispatcher(可以理解成一个servlet),根据配置映射的JSP文件路径进行跳转。controller层也可以使用annotation(注解)的方式来描述。MVC的中的C。
SpringMVC流程(原理)
1 用户发送请求至前端控制器DispatcherServlet;
2 前端控制器调用处理器映射器HandlerMapping,处理器映射器根据URL找到具体的处理器(Handler,也就是Controller),并返回给前端控制器。
3 前端控制器通过处理器适配器HandlerAdapter调用处理器。
4 执行处理器(Controller),执行完后返回给前端控制器一个ModelAndView
5 前端控制器调用视图解析器ViewResolver解析视图,并返回View给前端控制器。
6 前端控制器渲染并显示视图。
SpringMVC优点
1. 可以任意使用各种视图技术,而不仅仅局限于JSP
2. 支持各种请求资源的映射策略
3 .它应是易于扩展的
SpringMVC对请求的拦截方式
<servlet-mapping> 中的<url-pattern>/<url-pattern>。/代表拦截所有请求,包括静态资源。 .action拦截对应action结尾的路径,不会拦截静态资源。
对于/,解决静态资源不被拦截的方法:<mvc:resource location="/WEB-INF/js/" mapping="/js/**"> 所有对mapping的访问,都转到location位置。
<mvc:annotation-driven>
springmvc需要配置HandlerMapping、HandlerAdapter、ViewResolver。而<mvc:annotation-driven>会自动配置RequestMappingHandlerMapping和RequestMaappingHandlerAdapter。
MyBatis
MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注 SQL 本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码。
Mybatis通过xml或注解的方式将要执行的各种statement(statement、preparedStatemnt、CallableStatement)配置起来,并通过java对象和statement中的sql进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射成java对象并返回。
Mybatis解决jdbc编程的问题
1、 数据库链接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库链接池可解决此问题。
解决:在SqlMapConfig.xml中配置数据链接池,使用连接池管理数据库链接。
2、 Sql语句写在代码中造成代码不易维护,实际应用sql变化的可能较大,sql变动需要改变java代码。
解决:将Sql语句配置在XXXXmapper.xml文件中与java代码分离。
3、 向sql语句传参数麻烦,因为sql语句的where条件不一定,可能多也可能少,占位符需要和参数一一对应。
解决:Mybatis自动将java对象映射至sql语句,通过statement中的parameterType定义输入参数的类型。
4、 对结果集解析麻烦,sql变化导致解析代码变化,且解析前需要遍历,如果能将数据库记录封装成pojo对象解析比较方便。
解决:Mybatis自动将sql执行结果映射至java对象,通过statement中的resultType定义输出结果的类型。
Mapper接口开发的一些规范
1.mapper.xml中的namespace和mapper接口类路径相同;
2.mapper.xml中的SQL对应的id与mapper接口的方法名相同;
3.mapper.xml中的每个sql的parameterType和接口的输入参数类型相同;
4.mapper.xml中的每个sql的resultType要与接口的返回参数类型相同
#{name}获取parameterType中的属性的值,若输入对象,name就是对应的字段,输入hashmap,name就是key。
resultType总结:
resultType中对象的字段名和查询出来的结果的字段名相同。
返回单个pojo对象要保证sql查询出来的结果集为单条,内部使用sqlsession.selectOne方法调用,mapper接口使用pojo对象作为方法返回值。
返回pojo列表表示查询出来的结果集可能为多条,内部使用sqlsession.selectList方法,mapper接口使用List<pojo>对象作为方法返回值。
resultMap
如果sql查询字段名和对象的属性名不一致,可以通过resultMap将字段名和属性名作一个对应关系 ,resultMap实质上还需要将查询结果映射到pojo对象中。
resultMap处理关联查询返回的结果
一对一:类中除了基本的属性,还包含其他对象,orders中含有User,使用association标签
<resultMap type="cn.itcast.mybatis.po.Orders" id="userordermap"> <!-- 这里的id,是mybatis在进行一对一查询时将user字段映射为user对象时要使用,必须写 --> <id property="id" column="id"/> <result property="user_id" column="user_id"/> <result property="number" column="number"/> <association property="user" javaType="cn.itcast.mybatis.po.User"> <!-- 这里的id为user的id,如果写上表示给user的id属性赋值 --> <id property="id" column="user_id"/> <result property="username" column="username"/> <result property="address" column="address"/> </association> </resultMap>
一对多:类中除了基本的属性外,还包含对象的集合,orders中含有List<Orderdetail>。使用collection标签
<resultMap type="cn.itcast.mybatis.po.Orders" id="userorderdetailmap"> <id property="id"column="id"/> <result property="user_id" column="user_id"/> <result property="number" column="number"/> <collection property="orderdetails" ofType="cn.itcast.mybatis.po.Orderdetail"> <id property="id" column="orderdetail_id"/> <result property="items_id" column="items_id"/> <result property="items_num" column="items_num"/> </collection> </resultMap>
多对多:User中包含List<Orders>,Orders中包含List<Orderdetail>。collection中嵌套collection。
MyBatis延迟加载
查询关联信息时(需要关联对象,要查关联表),首次查询只查询主要信息(单表查询),关联信息等用户获取时再查询(需要查询关联表),大大缓解了数据库压力。association和collection都具备延迟加载的功能。
这个跟 自己在做项目时一样,先查询单表,如果还需要其他表关联信息,再查询其他表。
sqlmapconfig.xml中
<settings> <!--开启延迟加载--> <setting name="lazyLoadingEnabled" value="true"/> <!--关闭积极加载--> <setting name="aggressiveLazyLoading" value="false"/> </settings>
<!--查询订单和创建订单的用户,使用延迟加载--> <resultMap id="OrderAndUserLazyLoad" type="Orders"> <id column="id" property="id"/> <result column="user_id" property="userId" /> <result column="number" property="number" /> <result column="createtime" property="createtime" /> <result column="note" property="note" /> <!-- select:要延迟加载的statement的id colunm:关联两张表的那个列的列名 --> <association property="user" javaType="User" select="findUser" column="user_id"> <--select中就是延迟加载再去执行的sql--> </association> </resultMap>
<select id="findOrdersByLazyLoad" resultMap="OrderAndUserLazyLoad"> SELECT * FROM orders </select> <select id="findUser" parameterType="int" resultType="User"> SELECT * FROM User WHERE id = #{value} </select>
从上面看,其实就是单表查询两次。
Mybatis缓存
Mybatis一级缓存的作用域是同一个SqlSession,在同一个sqlSession中两次执行相同的sql语句,第一次执行完毕会将数据库中查询的数据写到缓存(内存),第二次会从缓存中获取数据将不再从数据库查询,从而提高查询效率。当一个sqlSession结束后该sqlSession中的一级缓存也就不存在了。当遇到增删改时会清空缓存。Mybatis默认开启一级缓存。
Mybatis二级缓存是多个SqlSession共享的,其作用域是mapper的同一个namespace,不同的sqlSession两次执行相同namespace下的sql语句且向sql中传递参数也相同即最终执行相同的sql语句,第一次执行完毕会将数据库中查询的数据写到缓存(内存),第二次会从缓存中获取数据将不再从数据库查询,从而提高查询效率。当遇到增删改时会清空缓存。Mybatis默认没有开启二级缓存需要在setting全局参数中配置开启二级缓存。
#{}和${}的区别
#{}是预编译处理,${}是字符串替换。 Mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值; Mybatis在处理${}时,就是把${}替换成变量的值。 使用#{}可以有效的防止SQL注入,提高系统安全性。
当实体类中的属性名和表中的字段名不一样 ,怎么办 ?
1。查询语句中,给字段名取别名。
2.。resultMap
模糊查询like语句该怎么写?
1.在Java代码中写。string wildcardname = “%smi%”; list<name> names = mapper.selectlike(wildcardname);
2.Java代码中传入变量,SQL语句中拼接通配符,会引起SQL注入。select * from foo where bar like "%"${value}"%"
mapper如何传递多个参数
1.包装成pojo对象。
2.map
Mybatis的Xml映射文件中,不同的Xml映射文件,id是否可以重复?
不同的Xml映射文件,如果配置了namespace,那么id可以重复;如果没有配置namespace,那么id不能重复;毕竟namespace不是必须的,只是最佳实践而已。
通常一个Xml映射文件,都会写一个Dao接口与之对应,请问,这个Dao接口的工作原理是什么?Dao接口里的方法,参数不同时,方法能重载吗?
Dao接口,就是人们常说的Mapper接口,接口的全限名,就是映射文件中的namespace的值,接口的方法名,就是映射文件中MappedStatement的id值,接口方法内的参数,就是传递给sql的参数。Mapper接口是没有实现类的,当调用接口方法时,接口全限名+方法名拼接字符串作为key值,可唯一定位一个MappedStatement,举例:com.mybatis3.mappers.StudentDao.findStudentById,可以唯一找到namespace为com.mybatis3.mappers.StudentDao下面id = findStudentById的MappedStatement。在Mybatis中,每一个<select>、<insert>、<update>、<delete>标签,都会被解析为一个MappedStatement对象。
Dao接口里的方法,是不能重载的,因为是全限名+方法名的保存和寻找策略。
Dao接口的工作原理是JDK动态代理,Mybatis运行时会使用JDK动态代理为Dao接口生成代理proxy对象,代理对象proxy会拦截接口方法,转而执行MappedStatement所代表的sql,然后将sql执行结果返回。