框架面试题
一、Mybatis
1、谈谈你对框架的理解,框架有什么好处?
1、啥是框架
框架就是一个架子,表演节目,舞台已经搭建好,表演什么节目,看自己的需求了。
框架是一个半成品,对于Java语言来说,框架就是封装了别人的代码。在框架的基础上我们在进一步开发,拿来主义。(你想啊,在二阶段我们都手动去用request.getParameter()获取参数、在dao手动去写sql,不管啥业务,这些东西都是一样的,框架就将这些给你封装好啦)
2、解决的问题
解决的是技术整合问题。软件开发环境和规模都很大,不可能任何一个项目的代码都从零开始,此时就需要一个非常优秀的框架把基础技术整合完毕,我们在他的基础上进一步开发。提高性能,易扩展,易维护,最终提高整个团队的开发效率
3、怎么用框架呢?
(1) 导入相关坐标(jar包)
(2) 框架运行细节定义,编写配置文件(每个框架都有自己的配置文件呀)
(3) 调用框架中的API
2、Mybatis框架的好处
1、原先使用jdbc时
每次CRUD都要写那六大步骤,太冗余了吧
而且:
(1)频繁连接,释放数据库资源,降低系统性能
(2)SQL语句硬编码,难以维护(sql都写到.java里了)
(3)参数和占位符对应问题
(4)结果集解析复杂,列名硬编码
2、mybatis框架
是一个very优秀的持久层(dao)框架,对JDBC进行了封装,使得开发者只需要关注Sql语句(业务)本身即可,无需开发者处理加载驱动、获取连接、创建Statement等繁琐的过程。
实现了ORM思想
3、如何理解ORM思想呢?
对象关系映射
将数据库中的关系数据表映射为JAVA中的对象,把对数据表的操作转换为对对象的操作,实现面向对象编程。因此ORM的目的是使得开发人员以面向对象的思想来操作数据库。
Mybatis框架是一个半自动的ORM持久层框架,也可以在Java中实现类似 insert(User)的操作最终操作数据库,但是需要我们自己写Sql语句。Mybatis是目前比较流行的Dao层框架。
4、Mybatis的编程步骤
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FzpbauxZ-1639100484220)(img/2.png)]
//1、加载核心配置文件
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
//2、创建构建器
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
//3、构建SqlSession工厂
SqlSessionFactory sqlSessionFactory = builder.build(inputStream);
//4、生产SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
//5、执行业务
User user = sqlSession.selectOne("test.queryUserById",2);
System.out.println(user);
//6、释放资源
sqlSession.close();
5、#{} 和 ${} 的区别
1. #{}是预编译处理,${}是字符串替换。
2. Mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值;
3. Mybatis在处理${}时,就是把${}替换成变量的值,相当于字符串拼接
4. 使用#{}可以有效的防止SQL注入,提高系统安全性。
6、动态代理开发方式的好处以及规范是什么
定义一个Mapper接口,这个接口其实和我们UserDao接口是一样的,从Mybatis框架中拿到一个代理对象(代理的是这个Mapper接口),通过代理对象调用接口当中的方法完成业务。
四大规范:
1、sql映射文件的namespace必须和mapper接口的全限定类名保持一致
2、mapper接口的接口方法名必须和xml中的sql语句id保持一致
3、mapper接口的接口方法形参类型必须和sql语句的输入参数类型保持一致
4、mapper接口的接口方法返回类型必须和sql语句的resultType保持一致
7、mybatis的配置文件有哪些?作用是啥
-
SqlMapperConfig.xml:
主配置文件
1、enviroments配置数据源环境:
数据源、事务管理器的配置
2、全局typeAliases配置:
别名配置
3、mappers:加载指定的配置文件
<mappers>
<mapper resource="mapper/UserMapper.xml" />
<mapper class="com.ujiuye.mapper.UserMapper"></mapper>
<package name="com.ujiuye.mapper"></package>
</mappers>
-
写sql的配置文件
比如: <select>、<update>、<insert>、<delete>
8、MyBatis应用动态SQL解决了什么问题?
有时候,固定的sql语句不能够满足我们的应用需求。这个时候需要在 标准的基础上建立动态的查询语句。
Mybatis提供了多种注解,可以提供动态查询语言。
比如说在开发的时候,遇到这样的场景,界面提供了多种查询,但是都是非必填写,在选择查询条件时可以选中任意几种组合作为查询条件,如果在使用jdbc的时候,需要判断参数为空,自己组装sql,但是mybatis提供动态sql机制,依靠标签。
应用场景:
比如模块的多条件查询时
9、Mybatis的缓存
缓存作用:提升查询效率
1.mybatis 一级缓存是 SqlSession 级别的缓存,默认支持一级缓存,不需要在配置文件去配 置。
2.mybaits 的二级缓存是 mapper 范围级别,除了在 SqlMapConfig.xml 设置二级缓存的总开关 <settingname='cacheEnabled'value='true'/>,还要在具体的 mapper.xml 中开启二级缓存:<mappernamespace='cn.hpu.mybatis.mapper.UserMapper'>
10、Mybatis如何处理多对多关系?举一个多对多的例子
比如说学生表和课程表,一个学生可以选择多门课程, 一门课程都能被多个学生选择,这 样两张表的关系就是多对多的关系, 怎么处理多对多的情况? 遇到这种情况我们得创建一 张中间的桥表,关联后就是 课程表对桥表就是一对多,学生表对桥表也是一对多,就可以了
11、Mybatis是否支持延迟加载?如果支持,它的实现原理是什么?
(1)Mybatis仅支持association关联对象和collection关联集合对象的延迟加载,association指的就是一对一,collection指的就是一对多查询。在Mybatis配置文件中,可以配置是否启用延迟加载lazyLoadingEnabled=true|false。
(2)它的原理是,使用CGLIB创建目标对象的代理对象,当调用目标方法时,进入拦截器方法,比如调用a.getB().getName(),拦截器invoke()方法发现a.getB()是null值,那么就会单独发送事先保存好的查询关联B对象的sql,把B查询上来,然后调用a.setB(b),于是a的对象b属性就有值了,接着完成a.getB().getName()方法的调用。这就是延迟加载的基本原理。
12、Mybatis是如何将sql执行结果封装为目标对象并返回的?都有哪些映射形式?
第一种是使用<resultMap>标签,逐一定义列名和对象属性名之间的映射关系。
第二种是使用sql列的别名功能,将列别名书写为对象属性名,比如T_NAME AS NAME,对象属性名一般是name,小写,但是列名不区分大小写,Mybatis会忽略列名大小写,智能找到与之对应对象属性名,你甚至可以写成T_NAME AS NaMe,Mybatis一样可以正常工作。
13、Mybatis都有哪些Executor执行器?它们之间的区别是什么?
Mybatis有三种基本的Executor执行器,SimpleExecutor、ReuseExecutor、BatchExecutor。
1.SimpleExecutor:每执行一次update或select,就开启一个Statement对象,用完立刻关闭Statement对象。
2.ReuseExecutor:执行update或select,以sql作为key查找Statement对象,存在就使用,不存在就创建,用完后,不关闭Statement对象,而是放置于Map<String, Statement>内,供下一次使用。简言之,就是重复使用Statement对象。
3.BatchExecutor:执行update(没有select,JDBC批处理不支持select),将所有sql都添加到批处理中(addBatch()),等待统一执行(executeBatch()),它缓存了多个Statement对象,每个Statement对象都是addBatch()完毕后,等待逐一执行executeBatch()批处理。与JDBC批处理相同。
作用范围:Executor的这些特点,都严格限制在SqlSession生命周期范围内。
二、Spring
1、你觉得Spring框架有什么优势?
-
方便解耦,简化开发
通过 Spring 提供的 IoC 容器,可以将对象间的依赖关系交由 Spring 进行控制,避免硬编码所造成的过度程序耦合。用户也不必再为单例模式类、属性文件解析等这些很底层的需求编写代码,可以更专注于上层的应用。 UserService{ //硬编码 private UserDao userDao = new UserDaoImpl(); }
-
AOP编程的支持
通过 Spring 的 AOP 功能,方便进行面向切面的编程,许多不容易用传统 OOP 实现的功能可以通过 AOP 轻松应付
-
声明式事务的支持
可以将我们从单调烦闷的事务管理代码中解脱出来,通过声明式方式灵活的进行事务的管理,提高开发效率和质量。
-
方便程序的测试
可以用非容器依赖的编程方式进行几乎所有的测试工作,测试不再是昂贵的操作,而是随手可做的事情。
- 方便集成各种优秀框架
Spring 可以降低各种框架的使用难度,提供了对各种优秀框架( Struts、 Hibernate、 Hessian、 Quartz
等)的直接支持。
- 降低 JavaEE API 的使用难度
Spring 对 JavaEE API(如 JDBC、 JavaMail、远程调用等)进行了薄薄的封装层,使这些 API 的使用难度大为降低。
- Java 源码是经典学习范例
Spring 的源代码设计精妙、结构清晰、匠心独用,处处体现着大师对 Java 设计模式灵活运用以及对 Java 技术的高深造诣。它的源代码无意是 Java 技术的最佳实践的范例。
2、如何理解Spring的IOC思想
1、想了解IOC,先看下该概念
解耦合
软件设计原则:高内聚,低耦合
内聚:一个模块内各个元素彼此结合的紧密程度,描述的是模块内的功能联系
耦合:是软件结构中各模块之间相互连接的一种度量
简而言之:
高内聚,低耦合,其实就是同一个模块内的各个元素之间要高度紧密,但是各个模块之间的相互依存度却不要那么紧密
2、IOC
全称是Inversion Of Control,意为控制反转,不是一个技术,而是一种思想
其作用是用于削减代码间的耦合。它的实现思想就是利用了工厂设计模式,把创建对象代码从具体类中剥离出去,交由工厂来完成,从而降低代码间的依赖关系。
作用:
它是用于降低我们代码间的依赖关系,削减程序中的耦合。
3、如何理解Spring中的依赖注入(DI)
1、什么是依赖注入
就是让spring框架给Bean对象的属性进行赋值. 它是 spring 框架核心 ioc 的具体实现
我们的程序在编写时, 通过控制反转,把对象的创建交给了 spring,但是代码中不可能出现没有依赖的情况。ioc 解耦只是降低他们的依赖关系,但不会消除。 例如:我们的业务层仍会调用持久层的方法。那这种业务层和持久层的依赖关系, 在使用 spring 之后, 就让 spring 来维护了。
简单的说,依赖注入(DI)就是坐等框架把持久层对象传入业务层,而不用我们自己去获取
2、依赖注入的几种方式
(1)使用构造函数方式注入
(2)使用set方法方式注入 p名称空间
(3)静态工厂的方法注入
(4)实例工厂的方法注入
4、Spring框架的常用注解有哪些?
1、@Component :将普通pojo实例化到spring容器中,相当于配置文件中的
<bean id="" class="">
以及三个衍生注解
@Controller:控制器层用
@Service:服务层用
@Repository:dao层用
2、依赖注入注解
@Autowired注解:按类型注入
@Qualifier("id") 注解 按照id注入
@Resource注解
3、@Configuration标识当前类是Spring的一个配置类
@ComponentScan替代xml中的`<context:component-scan/>`
@Import引入其他配置类,被引入的配置类可以不加@Configuration注解 @PropertySource:引入外部properties文件,注意加classpath:
@Value对成员变量赋值
@Bean将一个方法的返回值对象加入到Spring的容器当中管理
@Qualifier可以使用在方法参数上,表明对应的形参引入/注入的对象类型
5、你们公司使用SSM框架采用的注解方式还是XML方式开发?
企业主流的开发方式:半注解半xml开发
往往第三方jar中的对象我们使用xml配置(比如druid数据库连接池、Mybatis的SQLSessionFactory),类似于service层和dao层的实现类,这属于我们自己写的代码,往往会使用注解,这就是半xml半注解的模式
6、你对Spring的AOP如何理解?
1、AOP:面向切面编程
它是一种编程思想,一种设计理念,是OOP的一种延续。运用AOP编程思想,可以提高代码的可重用性,使编码更加简洁,更易于维护。
简单的说它就是把我们程序重复的代码抽取出来,在需要执行的时候,使用动态代理的技术,在不修改源码的基础上,对我们的已有方法进行增强。
2、应用场景:事务和日志、统计方法执行效率
7、简述一下Spring支持的事物管理有哪些?
1.声明式事务管理:设置配置文件与先前比照简化了许多。我们把这类设置配置文件格式称为 Spring 经典的声明式事务治理。
2.编程式事务管理:为了不损坏代码原有的条理性,避免出现每一个方法中都包括相同的启动事物、提交、回滚事物样板代码的现象,spring 提供了 transactionTemplate 模板来实现编程式事务管理。这种方式意味着你可以将事务管理和业务代码分离。你只需要通过注解或者XML配置管理事务。
3.区别
(1)编程式事务是自己写事务处理的类,然后调用。
(2)声明式事务是在配置文件中配置,一般搭配在框架里面使用。
8、事物的四大特性有哪些(ACID)?
1.原子性:事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作用;
2.一致性:执行事务前后,数据保持一致,多个事务对同一个数据读取的结果是相同的;
3.隔离性:并发访问数据库时,一个用户的事务不被其他事务所干扰,各并发事务之间数据库是独立的;
4.持久性:一个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有任何影响。
9、Spring的事物管理机制实现原理?
Spring的事务管理机制实现的原理,就是通过这样一个动态代理对所有需要事务管理的Bean进行加载,并根据配置在invoke方法中对当前调用的 方法名进行判定,并在method.invoke方法前后为其加上合适的事务管理代码,这样就实现了Spring式的事务管理。Spring中的AOP实 现更为复杂和灵活,不过基本原理是一致的。
10、请解释Spring Bean的生命周期?
1.Spring Bean的生命周期简单易懂。在一个bean实例被初始化时,需要执行一系列的初始化操作以达到可用的状态。同样,当一个bean不在被调用时需要进行相关的析构操作,并从bean容器中移除。
2.Spring bean factory 负责管理在spring容器中被创建的bean的生命周期。Bean的生命周期由两组回调(call back)方法组成。
初始化之后调用的回调方法。
销毁之前调用的回调方法。
Spring框架提供了以下四种方式来管理bean的生命周期事件:
(1)InitializingBean和DisposableBean回调接口
(2)针对特殊行为的其他Aware接口
(3)Bean配置文件中的Custom init()方法和destroy()方法w
(4)@PostConstruct和@PreDestroy注解方式
实例化 Instantiation
属性赋值 Populate
初始化 Initialization
销毁 Destruction
11、Spring 中@Autowired 和@Resource 的区别
1.@Autowired 默认的是按照类型进行注入, 如果没有类型会按照名称进行注入. 如果想直接按照名称注入需要加入@Qualifier("gatheringDao")
@Autowired
@Qualifier("gatheringDao")
private GatheringDao gatheringDao;
2.@Resource 默认的会按照名称注入,名称找不着会按照类型来找,如果这里写了名称,就直接 按照名称找了不会按类型找@Resource(name = "aaa") @Resource
private GatheringDao gatheringDao;
12、Spring 中用到了那些设计模式?
Spring框架中使用到了大量的设计模式,下面列举了比较有代表性的:
1.代理模式—在AOP和remoting中被用的比较多。
2.单例模式—在spring配置文件中定义的bean默认为单例模式。
3.模板方法—用来解决代码重复的问题。比如. RestTemplate, JmsTemplate, JpaTemplate。
4.工厂模式—BeanFactory用来创建对象的实例。
适配器–spring aop
装饰器–spring data hashmapper
观察者– spring 时间驱动模型
回调–Spring ResourceLoaderAware回调接口
13、Spring 如何保证 Controller 并发的安全
Spring 多线程请求过来调用的Controller对象都是一个,而不是一个请求过来就创建一个Controller对象。
并发的安全? 原因就在于Controller对象是单例的,那么如果不小心在类中定义了类变量,那么这个类变量是被所有请求共享的,这可能会造成多个请求修改该变量的值,出现与预期结果不符合的异常
那有没有办法让Controller不以单例而以每次请求都重新创建的形式存在呢?
答案是当然可以,只需要在类上添加注解@Scope(“prototype”)即可,这样每次请求调用的类都是重新生成的(每次生成会影响效率)
虽然这样可以解决问题,但增加了时间成本,总让人不爽,还有其他方法么?答案是肯定的!
使用ThreadLocal来保存类变量,将类变量保存在线程的变量域中,让不同的请求隔离开来
14、什么是基于Java的Spring注解配置? 给一些注解的例子?
基于Java的配置,允许你在少量的Java注解的帮助下,进行你的大部分Spring配置而非通过XML文件。
以@Configuration 注解为例,它用来标记类可以当做一个bean的定义,被Spring IOC容器使用。另一个例子是@Bean注解,它表示此方法将要返回一个对象,作为一个bean注册进Spring应用上下文。
15、Spring如何解决循环依赖问题
spring提供的两种注入方式,构造注入和setter,那其实构造注入时如果发现循环依赖会直接初始化容器失败,setter注入是采用三级缓存,发现循环依赖会有一个半初始化状态进行流转。
1.架构问题,优先架构重构
2.@lazy懒加载
3.不用构造器注入改用set,Spring已经帮忙解决
16、Spring如何处理线程并发问题?
在一般情况下,只有无状态的Bean才可以在多线程环境下共享,在Spring中,绝大部分Bean都可以声明为singleton作用域,因为Spring对一些Bean中非线程安全状态采用ThreadLocal进行处理,解决线程安全问题。
ThreadLocal和线程同步机制都是为了解决多线程中相同变量的访问冲突问题。同步机制采用了“时间换空间”的方式,仅提供一份变量,不同的线程在访问前需要获取锁,没获得锁的线程则需要排队。而ThreadLocal采用了“空间换时间”的方式。
ThreadLocal会为每一个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。因为每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。ThreadLocal提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的变量封装进ThreadLocal。
三、SpringMvc
1、简单描述一下你对SpringMVC的理解
SpringMVC是一个轻量级的Web表现层框架,用来写Controller接收请求跳转页面的,它是Spring框架的一部分。SpringMVC是对Servlet的封装和增强,简化了servlet的操作。它已经超越了Struts2,成为目前最优秀的表现层框架。
1、本质
web表现层的一个框架,主要用来接收请求、转发请求、跳转页面
2、优势
操作特简单,性能特别高,灵活性特别强
2、描述springmvc的处理流程吧
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8Nh8YjAr-1639100484225)(img/1.png)]
- 第一步:用户发送请求至前端控制器DispatcherServlet
- 第二步:DispatcherServlet收到请求调用HandlerMapping处理器映射器
- 第三步:处理器映射器根据请求Url找到,具体的Handler(后端控制器),生成处理器对象及处理器拦截器(如果有则生成)一并返回DispatcherServlet
- 第四步:DispatcherServlet调用HandlerAdapter处理器适配器去调用Handler
- 第五步:处理器适配器执行Handler
- 第六步:Handler执行完成给处理器适配器返回ModelAndView
- 第七步:处理器适配器向前端控制器返回 ModelAndView,ModelAndView 是SpringMVC 框架的一个底层对象,包括 Model 和 View
- 第八步:前端控制器请求视图解析器去进行视图解析,根据逻辑视图名来解析真正的视图。
- 第九步:视图解析器向前端控制器返回View
- 第十步:前端控制器进行视图渲染,就是将模型数据(在 ModelAndView 对象中)填充到 request 域
- 第十一步:前端控制器向用户响应结果
3、介绍一下SpringMvc中的组件以及作用
1、DispatcherServlet:前端控制器
接收用户请求,响应结果,相当于中央处理器,DispatcherServlet是整个流程控制的中心,由它调用其它组件完成用户请求的处理。DispatcherServlet的存在降低了组件之间的耦合性
2、HandlerMapping:处理器映射器
理解为一个Map<url,Hanlder>,HandlerMapping负责根据用户请求的Url找到Handler即处理器,SpringMVC提供了不同的映射器来实现不同的映射方式,例如:实现接口方式,注解方式等。
3、Handler:处理器
在SpringMVC当中有两层意思:Controller或者Controller当中的方法,Handler相对于前端控制器DispatcherServlet来说是后端控制器,执行具体业务处理的,它在DispatcherServlet的控制下处理用户的具体请求。
4、HandlAdapter:处理器适配器
不同的接口类型转换成usb,体现了万物归一的思想,通过HandlerAdapter对Handler处理器进行执行,这是适配器模式的应用
5、ViewResolver:视图解析器
ViewResolver进行视图解析,首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成View视图对象。
4、SpringMVC 的 controller 里可不可以写成员变量?
可以写啊,注入的 service 不就是成员变量么,你是不想问 struts2 里的获取参数的方式啊? Struts2 早就不用了,他那种用成员变量获取参数的方式,在高并发下会造成线程不安全, springmvc 是使用的形参接收前台数据的,线程比较安全。
5、如何开启注解处理器和适配器?
我们在项目中一般会在 springmvc.xml 中通过开启 <mvc:annotation-driven> 来实现注解处理器和适配器的开启.
6、SpringMVC如何与Ajax相互调用
通过Jackson框架把Java对象转换成js可以识别的json对象
步骤:
1、加入Jackson.jar
2、配置json的映射
3、在接收Ajax方法里直接返回Object、List等,方法前要加@RequestBody注解
7、简述web.xml的作用?
web中可以没有web.xml文件,也就是说,web.xml文件并不是web工程必须的。
web.xml文件是用来初始化配置信息:比如Welcome页面、servlet、servlet-mapping、filter、listener、启动加载级别等。
当你的web工程没用到这些时,你可以不用web.xml文件来配置你的Application。
注解处理器和适配器?
我们在项目中一般会在 springmvc.xml 中通过开启 <mvc:annotation-driven> 来实现注解处理器和适配器的开启.
6、SpringMVC如何与Ajax相互调用
通过Jackson框架把Java对象转换成js可以识别的json对象
步骤:
1、加入Jackson.jar
2、配置json的映射
3、在接收Ajax方法里直接返回Object、List等,方法前要加@RequestBody注解
7、简述web.xml的作用?
web中可以没有web.xml文件,也就是说,web.xml文件并不是web工程必须的。
web.xml文件是用来初始化配置信息:比如Welcome页面、servlet、servlet-mapping、filter、listener、启动加载级别等。
当你的web工程没用到这些时,你可以不用web.xml文件来配置你的Application。