SSM基础重难点
本文内容纲要:
- {}是预编译处理,${}是字符串替换。
1、Mybatis
1.1 概念
MyBatis 是一个持久层框架,实现了对JDBC操作的封装,主要用于简化JDBC操作中的一些相对繁琐的步骤,例如参数的映射,结果集的映射等。可以简单快速地连接和操作数据库,同时把操作数据库的结果集封装为Java对象返回
1.2 Mybatis优点
Mybatis的优点:
(1)Mybatis对JDBC进行封装,在实际开发中不用花费时间和精力去处理对数据库连接等的处理;
(2)Mybatis自身支持连接池,也可以配置其他的连接池,如c3p0、druid,提高了程序的效率;
(3)Mybatis是将SQL配置在mapper.xml文件中,当需求发生变更时只修改xml配置文件就可以了,类不需要重新编译。
(4)执行SQL后返回的ResultSet结果对象,Mybatis会帮我们处理,转换成Java对象,方便我们对结果的处理。
1.3 Mybatis架构
(1)sqlMapConfig.xml是Mybatis的核心配置文件,通过其中的配置可以生成SqlSessionFactory,也就是SqlSession工厂
(2)基于SqlSessionFactory可以生成SqlSession对象
(3)SqlSession是一个既可以发送SQL去执行,并返回结果,类似于JDBC中的Connection对象,也是Mybatis中至关重要的一个对象。
(4)Executor是SqlSession底层的对象,用于执行SQL语句
(5)MapperStatement对象也是SqlSession底层的对象,用于接收输入映射(SQL语句中的参数),以及做输出映射(即将SQL查询的结果映射成相应的结果)
1.4 底层原理
1、工作原理图
工作原理解析
mybatis应用程序通过SqlSessionFactoryBuilder从mybatis-config.xml配置文件(也可以用Java文件配置(注解)的方式,需要添加@Configuration)中构建出SqlSessionFactory(SqlSessionFactory是线程安全的);
然后,SqlSessionFactory的实例直接开启一个SqlSession,再通过SqlSession实例获得Mapper对象并运行Mapper映射的SQL语句,完成对数据库的CRUD和事务提交,之后关闭SqlSession。
说明:SqlSession是单线程对象,因为它是非线程安全的,是持久化操作的独享对象,类似jdbc中的Connection,底层就封装了jdbc连接。
详细流程如下
1、加载mybatis全局配置文件(数据源、mapper映射文件等),解析配置文件,MyBatis基于XML配置文件生成Configuration,和一个个MappedStatement(包括了参数映射配置、动态SQL语句、结果映射配置),其对应着<select | update | delete | insert>标签项。
2、SqlSessionFactoryBuilder通过Configuration对象生成SqlSessionFactory,用来开启SqlSession。
3、SqlSession对象完成和数据库的交互:
a、用户程序调用mybatis接口层api(即Mapper接口中的方法)
b、SqlSession通过调用api的Statement ID找到对应的MappedStatement对象
c、通过Executor(负责动态SQL的生成和查询缓存的维护)将MappedStatement对象进行解析,sql参数转化、动态sql拼接,生成jdbc Statement对象
d、JDBC执行sql。
e、借助MappedStatement中的结果映射关系,将返回结果转化成HashMap、JavaBean等存储结构并返回。
mybatis层次图:
1.5 Mybatis缓存
Mybatis的一级缓存是SqlSession级别。第一次执行select时候会发现sqlsession缓存没有记录,会去数据库查找,然后把结果保存到缓存,第二次同等条件查询下,就会从缓存中查找到结果。另外为了避免脏读,每次执行更新新增删除时候会清空当前sqlsession缓存。
二级缓存是namespace级别的。同一个namespace下的搜寻语句共享一个二级缓存。如果开启了二级缓存,则先从二级缓存中查找,查找不到则委托为SimpleExecutor查找,而它则会先从一级缓存中查找,查找不到则从数据库查找。
mybaits的二级缓存一般不怎么使用,默认一级缓存是开启的。
1.6 常见面试题
1、什么是Mybatis?
(1)Mybatis是一个半ORM(对象关系映射)框架,它内部封装了JDBC,开发时只需要关注SQL语句本身,不需要花费精力去处理加载驱动、创建连接、创建statement等繁杂的过程。程序员直接编写原生态sql,可以严格控制sql执行性能,灵活度高。
(2)MyBatis 可以使用 XML 或注解来配置和映射原生信息,将 POJO映射成数据库中的记录,避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。
(3)通过xml 文件或注解的方式将要执行的各种 statement 配置起来,并通过java对象和 statement中sql的动态参数进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射为java对象并返回。(从执行sql到返回result的过程)。
2、Mybaits的优点:
(1)基于SQL语句编程,相当灵活,不会对应用程序或者数据库的现有设计造成任何影响,SQL写在XML里,解除sql与程序代码的耦合,便于统一管理;提供XML标签,支持编写动态SQL语句,并可重用。
(2)与JDBC相比,减少了50%以上的代码量,消除了JDBC大量冗余的代码,不需要手动开关连接;
(3)很好的与各种数据库兼容(因为MyBatis使用JDBC来连接数据库,所以只要JDBC支持的数据库MyBatis都支持)。
(4)能够与Spring很好的集成;
(5)提供映射标签,支持对象与数据库的ORM字段关系映射;提供对象关系映射标签,支持对象关系组件维护。
3、MyBatis框架的缺点:
(1)SQL语句的编写工作量较大,尤其当字段多、关联表多时,对开发人员编写SQL语句的功底有一定要求。
(2)SQL语句依赖于数据库,导致数据库移植性差,不能随意更换数据库。
4、MyBatis框架适用场合:
(1)MyBatis专注于SQL本身,是一个足够灵活的DAO层解决方案。
(2)对性能的要求很高,或者需求变化较多的项目,如互联网项目,MyBatis将是不错的选择。
5、MyBatis与Hibernate有哪些不同?
(1)Mybatis和hibernate不同,它不完全是一个ORM框架,因为MyBatis需要程序员自己编写Sql语句。
(2)Mybatis直接编写原生态sql,可以严格控制sql执行性能,灵活度高,非常适合对关系数据模型要求不高的软件开发,因为这类软件需求变化频繁,一但需求变化要求迅速输出成果。但是灵活的前提是mybatis无法做到数据库无关性,如果需要实现支持多种数据库的软件,则需要自定义多套sql映射文件,工作量大。
(3)Hibernate对象/关系映射能力强,数据库无关性好,对于关系模型要求高的软件,如果用hibernate开发可以节省很多代码,提高效率。
6、#{}和${}的区别是什么?
{}是预编译处理,${}是字符串替换。
Mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值;
Mybatis在处理${}时,就是把${}替换成变量的值。
使用#{}可以有效的防止SQL注入,提高系统安全性。
7、当实体类中的属性名和表中的字段名不一样怎么办 ?
第1种: 通过在查询的sql语句中定义字段名的别名,让字段名的别名和实体类的属性名一致。
第2种: 通过 来映射字段名和实体类属性名的一一对应的关系。
8、模糊查询like语句该怎么写?
SQL语句中的like模糊查询 select * from table where name like‘%张%’,
但实际开发中经常用到 select * from table where name like concat('%',#{name},'%')
9、通常一个Xml映射文件,都会写一个Dao接口与之对应,请问,这个Dao接口的工作原理是什么?Dao接口里的方法,参数不同时,方法能重载吗?
Dao接口即Mapper接口。接口的全限名,就是映射文件中的namespace的值;接口的方法名,就是映射文件中Mapper的Statement的id值;接口方法内的参数,就是传递给sql的参数。
Mapper接口是没有实现类的,当调用接口方法时,接口全限名+方法名拼接字符串作为key值,可唯一定位一个MapperStatement。在Mybatis中,每一个、、、标签,都会被解析为一个MapperStatement对象。 Mapper接口里的方法,是不能重载的,因为是使用 全限名+方法名 的保存和寻找策略。Mapper 接口的工作原理是JDK动态代理,Mybatis运行时会使用JDK动态代理为Mapper接口生成代理对象proxy,代理对象会拦截接口方法,转而执行MapperStatement所代表的sql,然后将sql执行结果返回。 10、Mybatis是如何进行分页的?分页插件的原理是什么? Mybatis使用RowBounds对象进行分页,它是针对ResultSet结果集执行的内存分页,而非物理分页。可以在sql内直接书写带有物理分页的参数来完成物理分页功能,也可以使用分页插件来完成物理分页。 分页插件的基本原理是使用Mybatis提供的插件接口,实现自定义插件,在插件的拦截方法内拦截待执行的sql,然后重写sql,根据dialect方言,添加对应的物理分页语句和物理分页参数。 11、Mybatis是如何将sql执行结果封装为目标对象并返回的?都有哪些映射形式? 第一种是使用标签,逐一定义数据库列名和对象属性名之间的映射关系。 第二种是使用sql列的别名功能,将列的别名书写为对象属性名。 有了列名与属性名的映射关系后,Mybatis通过反射创建对象,同时使用反射给对象的属性逐一赋值并返回,那些找不到映射关系的属性,是无法完成赋值的。 12、如何执行批量插入? 首先,创建一个简单的insert语句: insert into names (name) values (#{value}) 然后在java代码中像下面这样执行批处理插入: list names = new arraylist(); names.add(“fred”); names.add(“barney”); names.add(“betty”); names.add(“wilma”); 13、如何获取自动生成的(主)键值? insert 方法总是返回一个int值 ,这个值代表的是插入的行数。 如果采用自增长策略,自动生成的键值在 insert 方法执行完后可以被设置到传入的参数对象中。 示例: insert into names (name) values (#{name}) name name = new name(); name.setname(“fred”); int rows = mapper.insertname(name); // 完成后,id已经被设置到对象中 system.out.println(“rows inserted = ” + rows); system.out.println(“generated key value = ” + name.getid()); 14、在mapper中如何传递多个参数? (1)第一种: Public UserselectUser(String name,String area); <select id="selectUser"resultMap="BaseResultMap"> select * fromuser_user_t whereuser_name = #{0} anduser_area=#{1}
(2)第二种: 使用 @param 注解:
public interface usermapper {
user selectuser(@param(“username”) string username,@param(“hashedpassword”) string hashedpassword);
}
然后,就可以在xml像下面这样使用(推荐封装为一个map,作为单个参数传递给mapper):
select id, username, hashedpassword from some_table where username = #{username} and hashedpassword = #{hashedpassword}
(3)第三种:多个参数封装成map
try{
//映射文件的命名空间.SQL片段的ID,就可以调用对应的映射文件中的SQL
//由于我们的参数超过了两个,而方法中只有一个Object参数收集,因此我们使用Map集合来装载我们的参数
Map<String, Object> map = new HashMap();
map.put("start", start);
map.put("end", end);
return sqlSession.selectList("StudentID.pagination", map);
}catch(Exception e){
e.printStackTrace();
sqlSession.rollback();
throw e; }
finally{
MybatisUtil.closeSqlSession();
}
15、Mybatis动态sql有什么用?执行原理?有哪些动态sql?
Mybatis动态sql可以在Xml映射文件内,以标签的形式编写动态sql,执行原理是根据表达式的值完成逻辑判断并动态拼接sql的功能。
Mybatis提供了9种动态sql标签:trim | where | set | foreach | if | choose | when | otherwise | bind。
16、Xml映射文件中,除了常见的select|insert|updae|delete标签之外,还有哪些标签?
答: 、 、 、 、 ,加上动态sql的9个标签,其中 为sql片段标签,通过 标签引入sql片段, 为不支持自增的主键生成策略标签。
17、Mybatis的Xml映射文件中,不同的Xml映射文件,id是否可以重复?
不同的Xml映射文件,如果配置了namespace,那么id可以重复;如果没有配置namespace,那么id不能重复;
原因就是namespace+id是作为Map<String, MapperStatement>的key使用的,如果没有namespace,就剩下id,那么,id重复会导致数据互相覆盖。有了namespace,自然id就可以重复,namespace不同,namespace+id自然也就不同。
18、为什么说Mybatis是半自动ORM(对象映射模型)映射工具?它与全自动的区别在哪里?
Hibernate属于全自动ORM映射工具,使用Hibernate查询关联对象或者关联集合对象时,可以根据对象关系模型直接获取,所以它是全自动的。而Mybatis在查询关联对象或关联集合对象时,需要手动编写sql来完成,所以,称之为半自动ORM映射工具。
19、 一对一、一对多的关联查询 ?
select * from class c,teacher t where c.teacher_id=t.t_id and c.c_id=#{id}
<!--collection 一对多关联查询 --> <select id="getClass2" parameterType="int" resultMap="ClassesResultMap2">
select * from class c,teacher t,student s where c.teacher_id=t.t_id and c.c_id=s.class_id and c.c_id=#{id}
</select>
<resultMap type="com.lcb.user.Classes" id="ClassesResultMap2">
<id property="id" column="c_id"/>
<result property="name" column="c_name"/>
<association property="teacher" javaType="com.lcb.user.Teacher">
<id property="id" column="t_id"/>
<result property="name" column="t_name"/>
</association>
<collection property="student" ofType="com.lcb.user.Student">
<id property="id" column="s_id"/>
<result property="name" column="s_name"/>
</collection>
</resultMap>
20、MyBatis实现一对一有几种方式?具体怎么操作的?
有联合查询和嵌套查询,联合查询是几个表联合查询,只查询一次,通过在resultMap里面配置association节点配置一对一的类就可以完成;
嵌套查询是先查一个表,根据这个表里面的结果的 外键id,去再另外一个表里面查询数据,也是通过association配置,但另外一个表的查询通过select属性配置。
22、Mybatis是否支持延迟加载?如果支持,它的实现原理是什么?
答:Mybatis仅支持association关联对象和collection关联集合对象的延迟加载,association指的就是一对一,collection指的就是一对多查询。在Mybatis配置文件中,可以配置是否启用延迟加载lazyLoadingEnabled=true|false。
它的原理是,使用CGLIB创建目标对象的代理对象,当调用目标方法时,进入拦截器方法,比如调用a.getB().getName(),拦截器invoke()方法发现a.getB()是null值,那么就会单独发送事先保存好的查询关联B对象的sql,把B查询上来,然后调用a.setB(b),于是a的对象b属性就有值了,接着完成a.getB().getName()方法的调用。这就是延迟加载的基本原理。
不光是Mybatis,几乎所有的包括Hibernate,支持延迟加载的原理都是一样的。
23、Mybatis的一级、二级缓存:
一级缓存: 基于 PerpetualCache 的 HashMap 本地缓存,其存储作用域为 Session,当 Session flush 或 close 之后,该 Session 中的所有 Cache 就将清空,默认打开一级缓存。
二级缓存与一级缓存其机制相同,默认也是采用 PerpetualCache,HashMap 存储,不同在于其存储作用域为 Mapper(Namespace),并且可自定义存储源,如 Ehcache。默认不打开二级缓存,要开启二级缓存,使用二级缓存属性类需要实现Serializable序列化接口(可用来保存对象的状态),可在它的映射文件中配置 ;
24、什么是MyBatis的接口绑定?有哪些实现方式?
接口绑定,就是在MyBatis中任意定义接口,然后把接口里面的方法和SQL语句绑定, 我们直接调用接口方法就可以,这样比起原来了SqlSession提供的方法我们可以有更加灵活的选择和设置。
接口绑定有两种实现方式,一种是通过注解绑定,就是在接口的方法上面加上 @Select、@Update等注解,里面包含Sql语句来绑定;另外一种就是通过xml里面写SQL来绑定, 在这种情况下,要指定xml映射文件里面的namespace必须为接口的全路径名。当Sql语句比较简单时候,用注解绑定, 当SQL语句比较复杂时候,用xml绑定,一般用xml绑定的比较多。
25、使用MyBatis的mapper接口调用时有哪些要求?
①Mapper接口方法名和mapper.xml中定义的每个sql的id相同;
②apper接口方法的输入参数类型和mapper.xml中定义的每个sql 的parameterType的类型相同;
③Mapper.xml文件中的namespace即是mapper接口的类路径。
27、简述Mybatis的插件运行原理,以及如何编写一个插件。
答:Mybatis仅可以编写针对ParameterHandler、ResultSetHandler、StatementHandler、Executor这4种接口的插件,Mybatis使用JDK的动态代理,为需要拦截的接口生成代理对象以实现接口方法拦截功能,每当执行这4种接口对象的方法时,就会进入拦截方法,具体就是InvocationHandler的invoke()方法,当然,只会拦截那些你指定需要拦截的方法。
编写插件:实现Mybatis的Interceptor接口并复写intercept()方法,然后在给插件编写注解,指定要拦截哪一个接口的哪些方法即可,记住,别忘了在配置文件中配置你编写的插件。
2、Spring
2.1 概念
1、Spring是一个开源的轻量级的应用开发框架,其目的是用于简化企业级应用程序开发,降低开发者的开发难度;
2、Spring提供的IoC和AOP应用,可以将组件的耦合度降至最低(即解耦),便于系统日后的维护和升级;
3、Spring为系统提供了一个整体的解决方案,开发者可以利用它本身提供的功能外,也可以与第三方框架和技术整合应用,可以自由选择采用哪种技术进行开发。(比如Spring整合SpringMVC、Spring整合MyBatis、Spring整合Struts2、Spring整合Hibernate、Spring整合Quartz[定时任务处理])
2.2 Spring优点
1).方便解耦,简化开发
通过Spring提供的IoC容器,可以将对象之间的依赖关系交由Spring进行控制,避免硬编码所造成的过度程序耦合。
2).AOP编程的支持
通过Spring提供的AOP功能,方便进行面向切面的编程,如性能监测、事务管理、日志记录等。
3).声明式事务的支持
4).方便集成各种优秀框架
5).降低Java EE API的使用难度,如对JDBC,JavaMail,远程调用等提供了简便封装
2.3 Spring架构
Spring 最初的目标就是要整合一切优秀资源,然后对外提供一个统一的服务。Spring 模块构建在核心容器之上,核心容器定义了创建、配置和管理 bean 的方式,如下图所示:
- 核心容器Spring Core核心容器,提供Spring框架的基本功能。核心容器的主要组件是BeanFactory,它是工厂模式的实现。BeanFactory 使用控制反转(IOC)模式,将应用程序的配置和依赖性规范与实际的应用程序代码分开。
2.Spring Context Spring 上下文,是一个配置文件,向 Spring 框架提供上下文信息。Spring 上下文包括企业服务,例如 JNDI、EJB、电子邮件、国际化、校验和调度功能。
3.Spring AOP通过配置管理特性,Spring AOP 模块直接将面向切面的编程功能集成到了 Spring 框架中。可以很容易地使 Spring框架管理的任何对象支持AOP。Spring AOP模块为基于Spring 的应用程序中的对象提供了事务管理服务。通过使用Spring AOP,就可以将声明性事务管理集成到应用程序中。
- Spring DAO JDBC DAO 抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理和不同数据库供应商抛出的错误消息。异常层次结构简化了错误处理,并且极大地降低了需要编写的异常代码数量(例如打开和关闭连接)。Spring DAO 的面向 JDBC 的异常遵从通用的 DAO 异常层次结构。
5.Spring ORM Spring 框架插入了若干个 ORM 框架,从而提供了 ORM 的对象关系工具,其中包括JDO、Hibernate和iBatis SQL Map。所有这些都遵从 Spring 的通用事务和 DAO 异常层次结构。
6.Spring Web Web上下文模块建立在应用程序上下文模块之上,为基于Web 的应用程序提供了上下文。所以Spring 框架支持与Jakarta Struts的集成。Web模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。
7.Spring MVC框架:MVC 框架是一个全功能的构建 Web 应用程序的 MVC 实现。通过策略接口,MVC 框架变成为高度可配置的,MVC 容纳了大量视图技术,其中包括 JSP、Velocity、Tiles、iText 和 POI。
2.4 控制反转(IOC)
控制反转,就是指将对象的创建,对象的存储(map),对象的管理(依赖查找,依赖注入)交给了spring容器。(spring容器是spring中的一个核心模块,用于管理对象)
只需要将类提前配置在spring配置文件中,就可以将对象的创建交给spring容器,当需要对象时,不需要自己创建,而是直接通过spring获取即可,省去了new对象,可以降低代码之间的耦合性。
IOC如何实例化对象?
Spring容器执行过程:
当tomcat服务器启动时会加载Spring容器的配置文件.当程序解析到Bean标签时.通过反射机制实例化对象.对象最终保存到了Spring容器自身维护的Map<Id,Object对象>
知识点:反射机制调用对象的无参构造实例化对象.
2.5 DI依赖注入
依赖注入,即组件之间的依赖关系由容器在应用系统运行期来决定,也就是由容器动态地将某种依赖关系的目标对象实例注入到应用系统中的各个关联的组件之中。
简单来说,所谓的依赖注入其实就是,在创建对象的同时或之后,如何给对象的属性赋值。
set方式注入:
1、创建User类,声明name和age属性,并添加对应的setter和getter方法,以及toString方法
2、在applicationContext.xml中声明User类的bean实例
3、修改applicationContext.xml中User实例的声明,为User实例注入属性(或者在applicationContext.xml中,将UserInfo对象作为值,赋值给User对象的userInfo属性)
构造方法注入:
1、为User类声明构造函数
2、修改applicationContext.xml文件,将set方式修改为构造方法注入。
2.6 底层原理(常见面试题)
1、什么是 Spring 框架?Spring 框架有哪些主要模块?
Spring框架是一个为 Java 应用程序的开发提供了综合、广泛的基础性支持的 Java 平台。Spring帮助开发者解决了开发中基础性的问题,使得开发人员可以专注于应用程序的开发。Spring 框架本身亦是按照设计模式精心打造,这使得我们可以在开发环境中安心的集成 Spring框架,不必担心Spring 是如何在后台进行工作的。
Spring 框架至今已集成了 20 多个模块。这些模块主要被分如下图所示的核心容器、数据访问/集成,、Web、AOP(面向切面编程)、工具、消息和测试模块。
3、使用 Spring 框架能带来哪些好处?
下面列举了一些使用 Spring 框架带来的主要好处:
1、Dependency Injection(DI) 方法使得构造器和 JavaBean properties 文件中的依赖关系一目了然。
2、与 EJB 容器相比较,IOC 容器更加趋向于轻量级。这样一来 IOC 容器在有限的内存和 CPU资源的情况下进行应用程序的开发和发布就变得十分有利。
3、Spring 并没有闭门造车,Spring 利用了已有的技术比如 ORM 框架、logging 框架、J2EE、
Quartz 和 JDK Timer,以及其他视图技术。
4、Spring 框架是按照模块的形式来组织的。由包和类的编号就可以看出其所属的模块,开发者仅仅需要选用他们需要的模块即可。
5、要测试一项用 Spring 开发的应用程序十分简单,因为测试相关的环境代码都已经囊括在框架中了。更加简单的是,利用 JavaBean 形式的 POJO 类,可以很方便的利用依赖注入来写入测试数据。
6、Spring 的 Web 框架亦是一个精心设计的 Web MVC 框架,为开发者们在 web 框架的选择上提供了一个除了主流框架比如 Struts、过度设计的、不流行 web 框架的以外的有力选项。
7、Spring 提供了一个便捷的事务管理接口,适用于小型的本地事务处理(比如在单 DB 的环境下)和复杂的共同事务处理(比如利用 JTA 的复杂 DB 环境)。
4、请解释下 Spring 框架中的 IOC?
Spring 中的 org.springframework.beans 包和 org.springframework.context 包构成了
Spring 框架 IOC 容器的基础。BeanFactory 接口提供了一个先进的配置机制,使得任何类型的对象的配置成为可能。
ApplicationContex 接口对 BeanFactory(是一个子接口)进行了扩展,在 BeanFactory 的基础上添加了其他功能,比如与 Spring 的 AOP 更容易集成,也提供了处理 message resource的机制(用于国际化)、事件传播以及应用层的特别配置,比如针对 Web 应用的
WebApplicationContext。
5、BeanFactory 和 ApplicationContext 有什么区别?
BeanFactory 可以理解为含有 bean 集合的工厂类。BeanFactory 包含了种 bean 的定义,以便在接收到客户端请求时将对应的 bean 实例化。BeanFactory 还能在实例化对象时生成协作类之间的关系。此举将 bean 自身与 bean 客户端的配置中解放出来。BeanFactory 还包含了 bean 生命周期的控制,调用客户端的初始化方法(initialization methods)和销毁方法(destruction methods)。从表面上看,application context 如同 bean factory 一样具有 bean 定义、bean 关联关系的设置,根据请求分发 bean 的功能。但 application context 在此基础上还提供了其他的功能。
1.提供了支持国际化的文本消息
2.统一的资源文件读取方式
3.已在监听器中注册的 bean 的事件
以下是三种较常见的 ApplicationContext 实现方式:
1、ClassPathXmlApplicationContext:从 classpath 的 XML 配置文件中读取上下文,并生成上下文定义。应用程序上下文从程序环境变量中取得。
ApplicationContext context = new ClassPathXmlApplicationContext(“application.xml”);
2、FileSystemXmlApplicationContext :由文件系统中的 XML 配置文件读取上下文。
ApplicationContext context = new FileSystemXmlApplicationContext(“application.xml”);
3、XmlWebApplicationContext:由 Web 应用的 XML 文件读取上下文。
6、Spring 提供几种配置方式来设置元数据?
将 Spring 配置到应用开发中有以下三种方式:
1.基于 XML 的配置
2.基于注解的配置
3.基于 Java 的配置
7、如何使用 XML 配置的方式配置 Spring?
在 Spring 框架中,依赖和服务需要在专门的配置文件来实现,常用 XML 格式的配置文件。这些配置文件的格式通常用开头,然后一系列的 bean 定义和专门的应用配置选项组成。SpringXML配置的主要目的时候是使所有的Spring组件都可以用xml文件的形式来进行配置。这意味着不会出现其他的 Spring 配置类型(比如声明的方式或基于 Java Class 的配置方式)Spring 的 XML 配置方式是使用被 Spring 命名空间的所支持的一系列的 XML 标签来实现的。
Spring 有以下主要的命名空间:context、beans、jdbc、tx、aop、mvc 和 aso。
8、如何用基于 Java 配置的方式配置 Spring?
Spring 对 Java 配置的支持是由@Configuration 注解和@Bean 注解来实现的。由@Bean注解的方法将会实例化、配置和初始化一个新对象,这个对象将由 Spring 的 IOC 容器来管理。@Bean 声明所起到的作用与 元素类似。被@Configuration 所注解的类则表示这个类的主要目的是作为 bean 定义的资源。被@Configuration 声明的类可以通过在同一个类的内部调用@bean 方法来设置嵌入 bean 的依赖关系。
9、怎样用注解的方式配置 Spring?
Spring 在 2.5 版本以后开始支持用注解的方式来配置依赖注入。可以用注解的方式来替代 XML方式的 bean 描述,可以将 bean 描述转移到组件类的内部,只需要在相关类上、方法上或者字段声明上使用注解即可。注解注入将会被容器在 XML 注入之前被处理,所以后者会覆盖掉前者对于同一个属性的处理结果。
注解装配在 Spring 中是默认关闭的。所以需要在 Spring 文件中配置一下才能使用基于注解的装配模式。如果你想要在你的应用程序中使用关于注解的方法的话,请参考如下的配置。
context:annotation-config/
在标签配置完成以后,就可以用注解的方式在 Spring 中向属性、方法和构造方法中自动装配变量。 下面是几种比较重要的注解类型: 1.@Required:该注解应用于设值方法。 2.@Autowired:该注解应用于有值设值方法、非设值方法、构造方法和变量。 3.@Qualifier:该注解和@Autowired 注解搭配使用,用于消除特定 bean 自动装配的歧义。 4.JSR-250 Annotations :Spring 支持 基于 JSR-250 注解 的以下 注解 ,@Resource、 @PostConstruct 和 @PreDestroy。
10、请解释 Spring Bean 的生命周期?
Spring Bean 的生命周期简单易懂。在一个 bean 实例被初始化时,需要执行一系列的初始化操作以达到可用的状态。同样的,当一个 bean 不在被调用时需要进行相关的析构操作,并从 bean容器中移除。Spring bean factory 负责管理在 spring 容器中被创建的 bean 的生命周期。Bean 的生命周期由两组回调(call back)方法组成。
1.初始化之后调用的回调方法。
2.销毁之前调用的回调方法。
Spring 框架提供了以下四种方式来管理 bean 的生命周期事件:
1、InitializingBean 和 DisposableBean 回调接口
2、针对特殊行为的其他 Aware 接口
3、Bean 配置文件中的 Custom init()方法和 destroy()方法
4、@PostConstruct 和@PreDestroy 注解方式
使用 customInit()和 customDestroy()方法管理 bean 生命周期的代码样例如下:
11、Spring Bean 作用域之间的区别?
Spring 容器中的 bean 可以分为 5 个范围。所有范围的名称都是自说明的,但是为了避免混淆,
还是让我们来解释一下:
1.singleton:这种 bean 范围是默认的,这种范围确保不管接受到多少个请求,每个容器中只有一个 bean 的实例,单例的模式由 bean factory 自身来维护。
2.prototype:原形范围与单例范围相反,为每一个 bean 请求提供一个实例。
3.request:在请求 bean 范围内会每一个来自客户端的网络请求创建一个实例,在请求完成以后,bean 会失效并被垃圾回收器回收。
4.Session:与请求范围类似,确保每个 session 中有一个 bean 的实例,在 session 过期后,bean 会随之失效。
5.global-session:global-session 和 Portlet 应用相关。当你的应用部署在 Portlet 容器中工作时,它包含很多 portlet。如果你想要声明让所有的 portlet 共用全局的存储变量的话,那么这全局变量需要存储在 global-session 中。全局作用域与 Servlet 中的 session 作用域效果相同。
12、什么是 Spring inner beans?
在 Spring 框架中,无论何时 bean 被使用时,当仅被调用了一个属性。一个明智的做法是将这个 bean 声明为内部 bean。内部 bean 可以用 setter 注入“属性”和构造方法注入“构造参数”的方式来实现。比如,在我们的应用程序中,一个 Customer 类引用了一个 Person 类,我们的要做的是创建一个 Person 的实例,然后在 Customer 内部使用。
public class Customer{
private Person person;
}
public class Person{
private String name;
private String address;
private int age;
//Setters and Getters
}
内部 bean 的声明方式如下:
13、Spring 框架中的单例 Beans 是线程安全的么?
Spring 框架并没有对单例 bean 进行任何多线程的封装处理。关于单例 bean 的线程安全和并发问题需要开发者自行去搞定。但实际上,大部分的 Spring bean 并没有可变的状态(比如Serview类和DAO类),所以在某种程度上说Spring的单例bean是线程安全的。如果你的bean有多种状态的话(比如 View Model 对象),就需要自行保证线程安全。
最浅显的解决办法就是将多态 bean 的作用域由“singleton”变更为“prototype”。
14、请举例说明如何在 Spring 中注入一个 Java 集合?
Spring 提供了以下四种集合类的配置元素:
1、该标签用来装配可重复的 list 值。
2、该标签用来装配没有重复的 set 值。
3、该标签可用来注入键和值可以为任何类型的键值对。
4、该标签支持注入键和值都是字符串类型的键值对。
下面看一下具体的例子:
INDIA Pakistan USA UKINDIA Pakistan USA UKadmin@gupaoedu.com support@gupaoedu.com
15、如何向 Spring Bean 中注入 java.util.Properties?
第一种方法是使用如下面代码所示的 标签:
admin@gupaoedu.com support@gupaoedu.com
也可用”util:”命名空间来从 properties 文件中创建出一个 propertiesbean,然后利用 setter方法注入 bean 的引用。
16、请解释 Spring Bean 的自动装配?
在 Spring 框架中,在配置文件中设定 bean 的依赖关系是一个很好的机制,Spring 容器还可以自动装配合作关系 bean 之间的关联关系。这意味着 Spring 可以通过向 Bean Factory 中注入的方式自动搞定 bean 之间的依赖关系。自动装配可以设置在每个 bean 上,也可以设定在特定的 bean 上。
下面的 XML 配置文件表明了如何根据名称将一个 bean 设置为自动装配:
除了 bean 配置文件中提供的自动装配模式,还可以使用@Autowired 注解来自动装配指定的bean。在使用@Autowired 注解之前需要在按照如下的配置方式在 Spring 配置文件进行配置才可以使用。
<context:annotation-config />
也可以通过在配置文件中配置 AutowiredAnnotationBeanPostProcessor 达到相同的效果。
配置好以后就可以使用@Autowired 来标注了。
@Autowired
public EmployeeDAOImpl ( EmployeeManager manager ) {
this.manager = manager;
}
17、请解释各种自动装配模式的区别?
在 Spring 框架中共有 5 种自动装配,让我们逐一分析。
1.no:这是 Spring 框架的默认设置,在该设置下自动装配是关闭的,开发者需要自行在 bean定义中用标签明确的设置依赖关系。
2.byName:该选项可以根据 bean 名称设置依赖关系。当向一个 bean 中自动装配一个属性时,容器将根据 bean 的名称自动在在配置文件中查询一个匹配的 bean。如果找到的话,就装配这个属性,如果没找到的话就报错。
3.byType:该选项可以根据 bean 类型设置依赖关系。当向一个 bean 中自动装配一个属性时,容器将根据 bean 的类型自动在在配置文件中查询一个匹配的 bean。如果找到的话,就装配这个属性,如果没找到的话就报错。
4.constructor:造器的自动装配和 byType 模式类似,但是仅仅适用于与有构造器相同参数的bean,如果在容器中没有找到与构造器参数类型一致的 bean,那么将会抛出异常。
5.autodetect:该模式自动探测使用构造器自动装配或者 byType 自动装配。首先,首先会尝试
找合适的带参数的构造器,如果找到的话就是用构造器自动装配,如果在 bean 内部没有找到相
应的构造器或者是无参构造器,容器就会自动选择 byTpe 的自动装配方式。
18、如何开启基于注解的自动装配?
要使用 @Autowired,需要注册 AutowiredAnnotationBeanPostProcessor,可以有以下两
种方式来实现:
1、引入配置文件中的下引入
<context:annotation-config />
2、在 bean 配置文件中直接引入 AutowiredAnnotationBeanPostProcessor
19 、自动装配有哪些局限性?
自动装配有如下局限性:
重写:你仍然需要使用 和< property>设置指明依赖,这意味着总要重写自动装配。
原生数据类型:你不能自动装配简单的属性,如原生类型、字符串和类。
模糊特性:自动装配总是没有自定义装配精确,因此,如果可能尽量使用自定义装配。
20、在 Spring 中可以注入 null 或空字符串吗?
完全可以。
21、请举例解释@Required Annotation?
在产品级别的应用中,IOC 容器可能声明了数十万了 bean,bean 与 bean 之间有着复杂的依赖关系。设值注解方法的短板之一就是验证所有的属性是否被注解是一项十分困难的操作。可以通过在中设置“dependency-check”来解决这个问题。在应用程序的生命周期中,你可能不大愿意花时间在验证所有 bean 的属性是否按照上下文文件正 确 配 置 。 或 者 你 宁 可 验 证 某 个 bean 的 特 定 属 性 是 否 被 正 确 的 设 置 。 即 使 是 用“dependency-check”属性也不能很好的解决这个问题,在这种情况下,你需要使用@Required 注解。
需要用如下的方式使用来标明 bean 的设值方法。
public class EmployeeFactoryBean extends AbstractFactoryBean{
private String designation;
public String getDesignation() {
return designation;
}
@Required
public void setDesignation(String designation) {
this.designation = designation;
}
}
RequiredAnnotationBeanPostProcessor 是 Spring 中的后置处理用来验证被@Required 注解的 bean 属性是否被正确的设置了。在使用 RequiredAnnotationBeanPostProcesso 来验证bean 属性之前,首先要在 IOC 容器中对其进行注册:
但 是 如 果 没 有 属 性 被 用 @Required 注 解 过 的 话 , 后 置 处 理 器 会 抛 出 一 个BeanInitializationException 异常。
22、请举例解释@Autowired 注解?
@Autowired 注解对自动装配何时何处被实现提供了更多细粒度的控制。@Autowired 注解可
以像@Required 注解、构造器一样被用于在 bean 的设值方法上自动装配 bean 的属性,一个参数或者带有任意名称或带有多个参数的方法。
比如,可以在设值方法上使用@Autowired 注解来替代配置文件中的 元素。当 Spring 容器在setter 方法上找到@Autowired 注解时,会尝试用 byType 自动装配。
当然我们也可以在构造方法上使用@Autowired 注解。带有@Autowired 注解的构造方法意味
着在创建一个 bean 时将会被自动装配,即便在配置文件中使用 元素。
public class TextEditor {
private SpellChecker spellChecker;
@Autowired
public TextEditor(SpellChecker spellChecker){
System.out.println("Inside TextEditor constructor." );
this.spellChecker = spellChecker;
}
public void spellCheck(){
spellChecker.checkSpelling();
}
}
下面是没有构造参数的配置方式:
context:annotation-config/
23、请举例说明@Qualifier 注解?
@Qualifier 注解意味着可以在被标注 bean 的字段上可以自动装配。Qualifier 注解可以用来取消 Spring 不能取消的 bean 应用。
下面的示例将会在 Customer 的 person 属性中自动装配 person 的值。
public class Customer{
@Autowired
private Person person;
}
下面我们要在配置文件中来配置 Person 类。
Spring 会知道要自动装配哪个 person bean 么?不会的,但是运行上面的示例时,会抛出下面的异常:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException:
No unique bean of type [com.gupaoedu.common.Person] is defined:
expected single matching bean but found 2: [personA, personB]
要解决上面的问题,需要使用 @Quanlifier 注解来告诉 Spring 容器要装配哪个 bean:
public class Customer{
@Autowired
@Qualifier("personA")
private Person person;
}
24、构造方法注入和设值注入有什么区别?
请注意以下明显的区别:
1.在设值注入方法支持大部分的依赖注入,如果我们仅需要注入 int、string 和 long 型的变量,我们不要用设值的方法注入。对于基本类型,如果我们没有注入的话,可以为基本类型设置默认值。在构造方法注入不支持大部分的依赖注入,因为在调用构造方法中必须传入正确的构造参数,否则的话为报错。
2.设值注入不会重写构造方法的值。如果我们对同一个变量同时使用了构造方法注入又使用了设
置方法注入的话,那么构造方法将不能覆盖由设值方法注入的值。很明显,因为构造方法尽在对
象被创建时调用。
3.在使用设值注入时有可能还不能保证某种依赖是否已经被注入,也就是说这时对象的依赖关系
有可能是不完整的。而在另一种情况下,构造器注入则不允许生成依赖关系不完整的对象。
4. 在 设 值 注 入 时 如 果 对 象 A 和 对 象 B 互 相 依 赖 , 在 创 建 对 象 A 时 Spring 会 抛 出
sObjectCurrentlyInCreationException 异常,因为在 B 对象被创建之前 A 对象是不能被创建
的,反之亦然。所以 Spring 用设值注入的方法解决了循环依赖的问题,因对象的设值方法是在
对象被创建之前被调用的。更多面试资料在群619881427免费获取(JVM/并发编程/分布式/微服务/等面试疑难解答都可以群里免费获取)
25、Spring 框架中有哪些不同类型的事件?
Spring 的 ApplicationContext 提供了支持事件和代码中监听器的功能。
我们可以创建 bean 用来监听在 ApplicationContext 中发布的事件。ApplicationEvent 类和
在 ApplicationContext 接口中处理的事件,如果一个 bean 实现了 ApplicationListener 接口,
当一个 ApplicationEvent 被发布以后,bean 会自动被通知。
public class AllApplicationEventListener implements ApplicationListener <
ApplicationEvent > {
@Override
public void onApplicationEvent(ApplicationEvent applicationEvent)
{
//process event
}
}
Spring 提供了以下5种标准的事件:
1.上下文更新事件(ContextRefreshedEvent):该事件会在 ApplicationContext 被初始化或
者更新时发布。也可以在调用 ConfigurableApplicationContext 接口中的 refresh()方法时被
触发。
2.上下文开始事件(ContextStartedEvent):当容器调用 ConfigurableApplicationContext
的 Start()方法开始/重新开始容器时触发该事件。
3.上下文停止事件(ContextStoppedEvent):当容器调用 ConfigurableApplicationContext
的 Stop()方法停止容器时触发该事件。
4.上下文关闭事件(ContextClosedEvent):当 ApplicationContext 被关闭时触发该事件。
容器被关闭时,其管理的所有单例 Bean 都被销毁。
5.请求处理事件(RequestHandledEvent):在 Web 应用中,当一个 http 请求(request)
结束触发该事件。
除了上面介绍的事件以外,还可以通过扩展 ApplicationEvent 类来开发自定义的事件。
public class CustomApplicationEvent extends ApplicationEvent{
public CustomApplicationEvent ( Object source, final String msg ){
super(source);
System.out.println("Created a Custom event");
}
}
为了监听这个事件,还需要创建一个监听器:
public class CustomEventListener implements ApplicationListener <
CustomApplicationEvent >{
@Override
public void onApplicationEvent(CustomApplicationEvent applicationEvent) {
//handle event
}
}
之后通过 applicationContext 接口的 publishEvent()方法来发布自定义事件。
CustomApplicationEvent customEvent = new CustomApplicationEvent(applicationContext,
“Test message”);
applicationContext.publishEvent(customEvent);
26、FileSystemResource 和 ClassPathResource 有何区别?
在 FileSystemResource 中需要给出 spring-config.xml 文件在你项目中的相对路径或者绝对
路径。在 ClassPathResource 中 spring 会在 ClassPath 中自动搜寻配置文件,所以要把
ClassPathResource 文件放在 ClassPath 下。
如果将 spring-config.xml 保存在了 src 文件夹下的话,只需给出配置文件的名称即可,因为 src
文件夹是默认。
简而言之,ClassPathResource 在环境变量中读取配置文件,FileSystemResource 在配置文件
中读取配置文件。
27、Spring 框架中都用到了哪些设计模式?
Spring 框架中使用到了大量的设计模式,下面列举了比较有代表性的:
1、代理模式—在 AOP 和 remoting 中被用的比较多。
2、单例模式:在 spring 配置文件中定义的 bean 默认为单例模式。
3、模板模式:用来解决代码重复的问题。
比如. RestTemplate, JmsTemplate, JpaTemplate。
4、委派模式:Spring 提供了 DispatcherServlet 来对请求进行分发。
5、工厂模式:BeanFactory 用来创建对象的实例,贯穿于 BeanFactory / ApplicationContext
接口的核心理念。
6、代理模式:AOP 思想的底层实现技术,Spring 中采用 JDK Proxy 和 CgLib 类库。
28、在 Spring 框架中如何更有效的使用 JDBC?
使用Spring JDBC框架,资源管理以及错误处理的代价都会减轻。开发人员只需通过statements
和 queries 语句从数据库中存取数据。Spring 框架中通过使用模板类能更有效的使用 JDBC,
也就是所谓的 JdbcTemplate。
29、Spring5 新特性
1、依赖 JDK 8+和 Java EE7+以上版本
2、首次采用反应式编程模型
3、支持使用注解进行编程
4、新增函数式编程
5、支持使用 REST 断点执行反应式编程
6、支持 HTTP 2.0
7、新增 Kotlin 和 Spring WebFlux
8、可使用 Lambda 表达式注册 Bean
9、Spring WebMVC 支持最新的 API
10、使用 JUnit5 执行条件和并发测试
11、使用 Spring WebFlux 执行集成测试
12、核心容器优化
2.7 Spring事务管理
事务就是对一系列的数据库操作(比如插入多条数据)进行统一的提交或回滚操作,如果插入成功,那么一起成功,如果中间有一条出现异常,那么回滚之前的所有操作。这样可以防止出现脏数据,防止数据库数据出现问题。
开发中为了避免这种情况一般都会进行事务管理。Spring中也有自己的事务管理机制,一般是使用TransactionMananger进行管 理,可以通过Spring的注入来完成此功能。
Spring支持如下两种方式的事务管理:
编程式事务管理:这意味着你可以通过编程的方式管理事务,这种方式带来了很大的灵活性,但很难维护。
声明式事务管理:这种方式意味着你可以将事务管理和业务代码分离。你只需要通过注解或者XML配置管理事务。
一般选择声明式事务管理,因为这种方式和应用程序的关联较少
(事务的注解为@Transactional)
2.8 AOP
2.8.1 概念
AOP 是软件设计领域中的面向切面编程,它是面向对象编程(OOP)的一种补充和完善实际项目中我们通常将面向对象理解为一个静态过程(例如一个系统有多少模块,一个模块有哪些对象,对象有哪些属性),面向切面中包含一个一个动态过程(在对象运行时动态织入一些功能。)
AOP就是要在基于OCP(开闭原则)在不改变原有系统核心业务代码的基础上动态添加一些扩展功能并可以控制对象的执行(例如添加日志、权限控制等)。
什么是AOP? 面向切面编程(AOP)完善spring的依赖注入(DI),面向切面编程在spring中主要表现为两个方面
1.面向切面编程提供声明式事务管理
2.spring支持用户自定义的切面 面向切面编程(aop)是对面向对象编程(oop)的补充, 面向对象编程将程序分解成各个层次的对象,面向切面编程将程序运行过程分解成各个切面。 AOP从程序运行角度考虑程序的结构,提取业务处理过程的切面,oop是静态的抽象,aop是动态的抽象, 是对应用执行过程中的步骤进行抽象,,从而获得步骤之间的逻辑划分。
aop框架具有的两个特征:
1.各个步骤之间的良好隔离性
2.源代码无关性
前提:要实现AOP的模拟就要知道动态代理,Spring中使用了两种动态代理方式,一种是基于JDK的动态代理,一种是基于CGlib的动态代理。为什么会有两种,那是因为JDK的动态代理只能是针对接口。
2.8.2 实现AOP
@Aspect 注解用于标识此类为一个AOP横切面对象
@Pointcut 注解用于定义本类中的切入点,本案例中切入点表达式用的是bean表达式,这个表达式以bean开头,bean括号中的内容为一个spring管理的某个bean对象的id。
@Around用于定义一个环绕通知(满足切入点表达式的核心业务方法执行之前和之后执行的一个操作)
在AOP编程中有五种类型的通知:
1)前置通知 (@Before) 方法执行之前执行
2)返回通知 (@AfterReturning) 方法return之后执行
3)异常通知 (@AfterThrowing) 方法出现异常之后执行
4)后置通知 (@After) : 又称之为最终通知(finally)
5)环绕通知 (@Around) :重点掌握(优先级最高)
AOP总结:
1.AOP中环绕通知使用是最多.因为可以控制目标方法是否执行.
2.除了环绕通知,另外四大通知类型 只做记录.不做修改.
2.9 单例模式和多例模式
什么是单例多例:
所谓单例就是所有的请求都用一个对象来处理,比如我们常用的service和dao层的对象通常都是单例的,而多例则指每个请求用一个新的对象来处理,比如action;
如何产生单例多例:
在通用的SSH中,单例在spring中是默认的,如果要产生多例,则在配置文件的bean中添加scope=“prototype”;
为什么用单例多例:
之所以用单例,是因为没必要每个请求都新建一个对象,这样子既浪费CPU又浪费内存;
之所以用多例,是为了防止并发问题;即一个请求改变了对象的状态,此时对象又处理另一个请求,而之前请求对对象状态的改变导致了对象对另一个请求做了错误的处理;
用单例和多例的标准只有一个:
当对象含有可改变的状态时(更精确的说就是在实际应用中该状态会改变),则多例,否则单例;
何时用单例?何时用多例?
对于struts2来说,action必须用多例,因为action本身含有请求参数的值,即可改变的状态;
而对于STRUTS1来说,action则可用单例,因为请求参数的值是放在actionForm中,而非action中的;
另外要说一下,并不是说service或dao一定是单例,标准同第3点所讲的,就曾见过有的service中也包含了可改变的状态,同时执行方法也依赖该状态,但一样用的单例,这样就会出现隐藏的BUG,而并发的BUG通常很难重现和查找;
3、SpringMVC
3.1 概念
Springmvc是spring框架的一个模块,spring和springmvc无需中间整合层整合,
Springmvc是一个基于mvc的web框架
3.2 MVC设计模式
MVC设计模式是一种通用的软件编程思想
在MVC设计模式中认为, 任何软件都可以分为三部分组成:
(1)控制程序流转的控制器(Controller)
(2)封装数据处理数据的模型(Model)
(3)负责展示数据的视图(view)
并且在MVC设计思想中要求一个符合MVC设计思想的软件应该保证上面这三部分相互独立,互不干扰,每一个部分只负责自己擅长的部分。
如果某一个模块发生变化,应该尽量做到不影响其他两个模块。这样做的好处是,软件的结构会变得更加的清晰,可读性强。有利于后期的扩展和维护,并且代码可以实现复用。
3.3 SpringMVC执行原理
(1).用户发送请求 至 前端控制器(DispatcherServlet);
提示:DispatcherServlet的作用:接收请求,调用其它组件处理请求,响应结果,相当于转发器、中央处理器,是整个流程控制的中心
(2).前端控制器(DispatcherServlet)收到请求后调用处理器映射器(HandlerMapping)
处理器映射器(HandlerMapping)找到具体的Controller(可以根据xml配置、注解进行查找),并将Controller返回给DispatcherServlet;
(3).前端控制器(DispatcherServlet)调用处理器适配器(HandlerAdapter)。处理器适配器经过适配调用具体的Controller;(Controller--> service --> Dao --> 数据库)
Controller执行完成后返回ModelAndView,
提示:Model(模型数据,即Controller处理的结果,Map) View(逻辑视图名,即负责展示结果的JSP页面的名字)
处理器适配器(HandlerAdapter)将controller执行的结果(ModelAndView)返回给前端控制器(DispatcherServlet);
(4).前端控制器(DispatcherServlet)将执行的结果(ModelAndView)传给视图解析器(ViewReslover)
视图解析器(ViewReslover)根据View(逻辑视图名)解析后返回具体JSP页面
(5).前端控制器(DispatcherServlet)根据Model对View进行渲染(即将模型数据填充至视图中);
(6).前端控制器(DispatcherServlet)将填充了数据的网页响应给用户。
其中整个过程中需要开发人员编写的部分有 Controller、Service、Dao、View;
常见面试题
1、什么是Spring MVC ?简单介绍下你对springMVC的理解?
Spring MVC是一个基于Java的实现了MVC设计模式的请求驱动类型的轻量级Web框架,通过把Model,View,Controller分离,将web层进行职责解耦,把复杂的web应用分成逻辑清晰的几部分,简化开发,减少出错,方便组内开发人员之间的配合。
2、SpringMVC的流程?
(1)用户发送请求至前端控制器DispatcherServlet;
(2) DispatcherServlet收到请求后,调用HandlerMapping处理器映射器,请求获取Handle;
(3)处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet;
(4)DispatcherServlet 调用 HandlerAdapter处理器适配器;
(5)HandlerAdapter 经过适配调用 具体处理器(Handler,也叫后端控制器);
(6)Handler执行完成返回ModelAndView;
(7)HandlerAdapter将Handler执行结果ModelAndView返回给DispatcherServlet;
(8)DispatcherServlet将ModelAndView传给ViewResolver视图解析器进行解析;
(9)ViewResolver解析后返回具体View;
(10)DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中)
(11)DispatcherServlet响应用户。
3、Springmvc的优点:
(1)可以支持各种视图技术,而不仅仅局限于JSP;
(2)与Spring框架集成(如IoC容器、AOP等);
(3)清晰的角色分配:前端控制器(dispatcherServlet) , 请求到处理器映射(handlerMapping), 处理器适配器(HandlerAdapter), 视图解析器(ViewResolver)。
(4)支持各种请求资源的映射策略。
4、Spring MVC的主要组件?
(1)前端控制器 DispatcherServlet(不需要程序员开发)
作用:接收请求、响应结果,相当于转发器,有了DispatcherServlet 就减少了其它组件之间的耦合度。
(2)处理器映射器HandlerMapping(不需要程序员开发)
作用:根据请求的URL来查找Handler
(3)处理器适配器HandlerAdapter
注意:在编写Handler的时候要按照HandlerAdapter要求的规则去编写,这样适配器HandlerAdapter才可以正确的去执行Handler。
(4)处理器Handler(需要程序员开发)
(5)视图解析器 ViewResolver(不需要程序员开发)
作用:进行视图的解析,根据视图逻辑名解析成真正的视图(view)
(6)视图View(需要程序员开发jsp)
View是一个接口, 它的实现类支持不同的视图类型(jsp,freemarker,pdf等等)
5、springMVC和struts2的区别有哪些?
(1)springmvc的入口是一个servlet即前端控制器(DispatchServlet),而struts2入口是一个filter过虑器(StrutsPrepareAndExecuteFilter)。
(2)springmvc是基于方法开发(一个url对应一个方法),请求参数传递到方法的形参,可以设计为单例或多例(建议单例),struts2是基于类开发,传递参数是通过类的属性,只能设计为多例。
(3)Struts采用值栈存储请求和响应的数据,通过OGNL存取数据,springmvc通过参数解析器是将request请求内容解析,并给方法形参赋值,将数据和视图封装成ModelAndView对象,最后又将ModelAndView中的模型数据通过reques域传输到页面。Jsp视图解析器默认使用jstl。
6、SpringMVC怎么样设定重定向和转发的?
(1)转发:在返回值前面加"forward:",譬如"forward:user.do?name=method4"
(2)重定向:在返回值前面加"redirect:",譬如"redirect:http://www.baidu.com"
7、SpringMvc怎么和AJAX相互调用的?
通过Jackson框架就可以把Java里面的对象直接转化成Js可以识别的Json对象。具体步骤如下 :(springmvc底层会将结果封装成json格式返回)
(1)加入Jackson.jar
(2)在配置文件中配置json的映射
(3) 在接受Ajax方法里面可以直接返回Object,List等,但方法前面要加上@ResponseBody注解。
8、如何解决POST请求中文乱码问题,GET的又如何处理呢?
(1)解决post请求乱码问题:
在web.xml中配置一个CharacterEncodingFilter过滤器,设置成utf-8;
(2)get请求中文参数出现乱码解决方法有两个:
①修改tomcat配置文件添加编码与工程编码一致,如下:
<ConnectorURIEncoding="utf-8" connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>
②另外一种方法对参数进行重新编码:
String userName = new String(request.getParamter("userName").getBytes("ISO8859-1"),"utf-8")
ISO8859-1是tomcat默认编码,需要将tomcat编码后的内容按utf-8编码。
9、Spring MVC的异常处理?
答:可以将异常抛给Spring框架,由Spring框架来处理;我们只需要配置简单的异常处理器,在异常处理器中添视图页面即可。
10、SpringMvc的控制器是不是单例模式,如果是,有什么问题,怎么解决?
答:是单例模式,所以在多线程访问的时候有线程安全问题,不要用同步,会影响性能的,解决方案是在控制器里面不能写字段。
11、 SpringMVC常用的注解有哪些?
@RequestMapping:用于处理请求 url 映射的注解,可用于类或方法上。用于类上,则表示类中的所有响应请求的方法都是以该地址作为父路径。
@RequestBody:注解实现接收http请求的json数据,将json转换为java对象。
@ResponseBody:注解实现将conreoller方法返回对象转化为json对象响应给客户。
12、SpingMvc中的控制器的注解一般用那个,有没有别的注解可以替代?
答:一般用@Conntroller注解,表示是表现层,不能用别的注解代替。
13、如果在拦截请求中,我想拦截get方式提交的方法,怎么配置?
答:可以在@RequestMapping注解里面加上method=RequestMethod.GET。
14、怎样在方法里面得到Request,或者Session?
答:直接在方法的形参中声明request,SpringMvc就自动把request对象传入。
15、如果想在拦截的方法里面得到从前台传入的参数,怎么得到?
答:直接在形参里面声明这个参数就可以,但必须名字和传过来的参数一样。
16、如果前台有很多个参数传入,并且这些参数都是一个对象的,那么怎么样快速得到这个对象?
答:直接在方法中声明这个对象,SpringMvc就自动会把属性赋值到这个对象里面。
17、SpringMvc中函数的返回值是什么?
答:返回值可以有很多类型,有String, ModelAndView。ModelAndView类把视图和数据都合并的一起的,但一般用String比较好。
18、SpringMvc用什么对象从后台向前台传递数据的?
答:通过ModelMap对象,可以在这个对象里面调用put方法,把对象加到里面,前台就可以通过el表达式拿到。
19、怎么样把ModelMap里面的数据放入Session里面?
答:可以在类上面加上@SessionAttributes注解,里面包含的字符串就是要放入session里面的key。
20、SpringMvc里面拦截器是怎么写的:
有两种写法,一种是实现HandlerInterceptor接口,另外一种是继承适配器类,接着在接口方法当中,实现处理逻辑;然后在SpringMvc的配置文件中配置拦截器即可:
mvc:interceptors
mvc:interceptor
<mvc:mapping path="/modelMap.do" />
</mvc:interceptor>
</mvc:interceptors>
21、注解原理:
注解本质是一个继承了Annotation的特殊接口,其具体实现类是Java运行时生成的动态代理类。我们通过反射获取注解时,返回的是Java运行时生成的动态代理对象。通过代理对象调用自定义注解的方法,会最终调用AnnotationInvocationHandler的invoke方法。该方法会从memberValues这个Map中索引出对应的值。而memberValues的来源是Java常量池。
SSM常见面试题
1、SpringMVC与Struts2的主要区别?
①springmvc的入口是一个servlet即前端控制器,而struts2入口是一个filter过虑器。
②springmvc是基于方法开发,传递参数是通过方法形参,可以设计为单例或多例(建议单例),struts2是基于类开发,传递参数是通过类的属性,只能设计为多例。
③Struts采用值栈存储请求和响应的数据,通过OGNL存取数据, springmvc通过参数解析器是将request对象内容进行解析成方法形参,将响应数据和页面封装成ModelAndView对象,最后又将模型数据通过request对象传输到页面。 Jsp视图解析器默认使用jstl。
2、Spring中用到哪些设计模式?
1.工厂模式(BeanFactory中)
2.单例模式(Spring中默认bean为单例)
3.适配器模式(HandlerAdater)
4.装饰者模式
5.代理模式(AOP中用到JDK动态代理)
6.观察者模式(listener的实现,例如ApplicationListener)
7.策略模式(定义一系列的算法,把它们一个个的封装起来,并且使它们可以相互替换。在实例化对象时用到)
8.模板模式(jdbcTemplate)
1.SpringMVC的工作流程?
用户发送请求至前端控制器DispatcherServlet
DispatcherServlet收到请求调用HandlerMapping处理器映射器。
处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。
DispatcherServlet通过HandlerAdapter处理器适配器调用处理器
执行处理器(Controller,也叫后端控制器)。
Controller执行完成返回ModelAndView
HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet
DispatcherServlet将ModelAndView传给ViewReslover视图解析器
ViewReslover解析后返回具体View
DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中)。
DispatcherServlet响应用户
2.Spring在SSM起什么作用?
Spring是一个轻量级框架,也是一个容器,Spring实质上讲就是一个Bean工厂,主要用来管理Bean的生命周期和框架集成。有IOC控制反转,DI依赖注入,控制反转是把dao依赖注入到servic层,然后service层反转给action层,Spring的顶层容器为BeanFactory,常用的ApplicationContext为它的子接口,实现了工厂模式,Spring还提供了AOP的支持,方便在切面级开发,
3. 怎么样理解IOC和DI
在使用Spring框架的过程中、一定会用到控制反转、但是往往所需要的资源还需要其他资源的支持、这个过程就需要依赖注入的支持
4. Spring的事务,事务的作用
编程式事务管理:这意味你通过编程的方式管理事务,给你带来极大的灵活性,但是难维护。
声明式事务管理:这意味着你可以将业务代码和事务管理分离,你只需用注解和XML配置来管理事务。
5.Spring的IOC你在项目中是怎么使用的?
IOC主要来解决对象之间的依赖问题,把所有的bean的依赖关系通过配置文件或者注解关联起来,降低了耦合度
6.Spring的配置文件有哪些内容?
开启事务注解驱动
事务管理器
开启注解功能,并配置扫描包
配置数据源
配置SQL会话工厂、别名、映射文件
不用编写DAO层的实现类(代理模式)
7.说下Spring的注解?
@Controller
@Service
@Component
@RequestMapping
@Resource、@Autowired
@ResponseBody
@Transactional
8.Spring DI的几种方式?
(1)构造器注入:通过构造方法初始化
<constructor-arg name=”dao”
(2)setter注入:通过setter方法初始化注入
注意:在实际开发中常用setter注入。
9.@RequestMapping注解用在类上面有什么作用?
该注解是用来映射一个URL到一个类或一个特定的方处理方法上。
10.SpringMVC怎么样设定重定向和转发的
在返回值前面加”forward:”就可以让结果转发,譬如”forward:user.do?name=method4” 在返回值前面加”redirect:”就可以让返回值重定向,譬如”redirect:http://www.uu456.com”
11. MyBatis怎么配置一对多?
一对多的关系 :property: 指的是集合属性的值, ofType:指的是集合中元素的类型
MyBatis怎样配置多对一?
多对一的关系:property: 指的是属性的值, javaType:指的是属性的类型
13.简单介绍下你对mybatis的理解?
mybatis配置
SqlMapConfig.xml,此文件作为mybatis的全局配置文件,配置了mybatis的运行环境等信息。
mapper.xml文件即sql映射文件,文件中配置了操作数据库的sql语句。此文件需要在SqlMapConfig.xml中加载。
通过mybatis环境等配置信息构造SqlSessionFactory即会话工厂
由会话工厂创建sqlSession即会话,操作数据库需要通过sqlSession进行。
mybatis底层自定义了Executor执行器接口操作数据库,Executor接口有两个实现,一个是基本执行器、一个是缓存执行器。
Mapped Statement也是mybatis一个底层封装对象,它包装了mybatis配置信息及sql映射信息等。mapper.xml文件中一个sql对应一个Mapped Statement对象,sql的id即是Mapped statement的id。
Mapped Statement对sql执行输入参数进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped Statement在执行sql前将输入的java对象映射至sql中,输入参数映射就是jdbc编程中对preparedStatement设置参数。
Mapped Statement对sql执行输出结果进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped Statement在执行sql后将输出结果映射至java对象中,输出结果映射过程相当于jdbc编程中对结果的解析处理过程。
14、springmvc是线程安全的吗
springmvc是单例模式的框架,但它是线程安全的,因为springmvc没有成员变量,所有参数的封装都是基于方法的,属于当前线程的私有变量. 因此是线程安全的框架
本文内容总结:{}是预编译处理,${}是字符串替换。,
原文链接:https://www.cnblogs.com/liangxr/p/13888294.html
以上是 SSM基础重难点 的全部内容, 来源链接: utcz.com/z/295929.html