面经-常用框架

1.Spring

1.1什么是Spring框架?

Spring 是⼀种轻量级开发框架,旨在提⾼开发⼈员的开发效率以及系统的可维护性。
Spring 的 6 个特征:核⼼技术,测试,数据访问,Web⽀持,集成,语⾔

1.2列举⼀些重要的Spring模块?

Spring Core 基础 , 可以说 Spring 其他所有的功能都需要依赖于该类库。主要提供 IoC
赖注⼊功能。
Spring Aspects : 该模块为与 AspectJ 的集成提供⽀持。
Spring AOP :提供了⾯向切⾯的编程实现。
Spring JDBC : Java 数据库连接。
Spring JMS Java 消息服务。
Spring ORM : ⽤于⽀持 Hibernate ORM ⼯具。
Spring Web : 为创建 Web 应⽤程序提供⽀持。
Spring Test : 提供了对 JUnit TestNG 测试的⽀持

1.3@RestController vs @Controller

Controller 返回⼀个⻚⾯
单独使⽤ @Controller 不加 @ResponseBody 的话⼀般使⽤在要返回⼀个视图的情况,这种情况
属于⽐᫾传统的 Spring MVC 的应⽤,对应于前后端不分离的情况。
@RestController 返回 JSON XML 形式数据
@RestController 只返回对象,对象数据直接以 JSON XML 形式写⼊ HTTP 响应
(Response) 中,这种情况属于 RESTful Web 服务,这也是⽬前⽇常开发所接触的最常⽤的情况
(前后端分离)。
@Controller +@ResponseBody 返回 JSON XML 形式数据
如果你需要在 Spring4 之前开发 RESTful Web 服务的话,你需要使⽤ @Controller 并结
@ResponseBody 注解,也就是说 @Controller + @ResponseBody = @RestController Spring 4
之后新加的注解)。
@ResponseBody将对象转换成JSON 或者XML形式
@ResponseBody 注解的作⽤是将 Controller 的⽅法返回的对象通过适当的转换器转换为指
定的格式之后,写⼊到 HTTP 响应 (Response) 对象的 body 中,通常⽤来返回 JSON 或者
XML 数据,返回 JSON 数据的情况⽐较多。

1.4Spring IOC & AOP

IOC

        IoC( Inverse of Control: 控制反转)是⼀种 设计思想 ,就是 将原本在程序中⼿动创建对象的控制 权,交由 Spring 框架来管理。   IoC 容器是 Spring ⽤来实现 IoC 的载体, IoC 容器实际上就是个 Map key value ,Map 中存放的是各 种对象。
        将对象之间的相互依赖关系交给 IoC 容器来管理,并由 IoC 容器完成对象的注⼊。 IoC 容器就像是⼀个⼯⼚⼀ 样,当我们需要创建⼀个对象的时候,只需要配置好配置⽂件 / 注解即可,完全不⽤考虑对象是如 何被创建出来的。
AOP
       AOP(Aspect-Oriented Programming:⾯向切⾯编程 ) 能够将那些与业务⽆关, 却为业务模块所共 同调⽤的逻辑或责任(例如事务处理、⽇志管理、权限控制等)封装起来 ,便于 减少系统的重复
代码 降低模块间的耦合度 ,并 有利于未来的可拓展性和可维护性
        Spring AOP就是基于动态代理的 ,如果要代理的对象,实现了某个接⼝,那么 Spring AOP 会使⽤JDK Proxy(动态代理) ,去创建代理对象,⽽对于没有实现接⼝的对象, 这时候 Spring AOP 会使⽤ Cglib ⽣成⼀个被代理对象的⼦类来作为代理

1.5Spring AOP AspectJ AOP 有什么区别?

        Spring AOP 属于运⾏时增强,⽽ AspectJ 是编译时增强。 Spring AOP 基于代理 (Proxying) ,⽽ AspectJ 基于字节码操作 (Bytecode Manipulation)
        Spring AOP 已经集成了 AspectJ AspectJ 应该算的上是 Java ⽣态系统中最完整的 AOP
架了。 AspectJ 相⽐于 Spring AOP 功能更加强⼤,但是 Spring AOP 相对来说更简单,如果我们的切⾯⽐较少,那么两者性能差异不⼤。但是,当切⾯太多的话,最好选择 AspectJ ,它⽐Spring AOP 快很多。

1.6Spring 中的 bean 的作⽤域有哪些?

singleton : 唯⼀ bean 实例, Spring 中的 bean 默认都是单例的。
prototype : 每次请求都会创建⼀个新的 bean 实例。
request : 每⼀次 HTTP 请求都会产⽣⼀个新的 bean ,该 bean 仅在当前 HTTP request 内有
效。
session : 每⼀次 HTTP 请求都会产⽣⼀个新的 bean ,该 bean 仅在当前 HTTP session 内有
效。
global-session : 全局 session 作⽤域,仅仅在基于 portlet web 应⽤中才有意义, Spring5
经没有了。 Portlet 是能够⽣成语义代码 ( 例如: HTML) ⽚段的⼩型 Java Web 插件。它们基于
portlet 容器,可以像 servlet ⼀样处理 HTTP 请求。但是,与 servlet 不同,每个 portlet 都有不
同的会话

1.7Spring 中的单例 bean 的线程安全问题了解吗?

单例 bean 存在线程问题,主要是因为当多个线程操作同⼀个对象的时候,对这个对象的⾮静态成员变量的写操作会存在线程安全问题。
常⻅的有两种解决办法:
1. Bean 对象中尽量避免定义可变的成员变量(不太现实)。
2. 在类中定义⼀个 ThreadLocal 成员变量,将需要的可变成员变量保存在 ThreadLocal 中(推
荐的⼀种⽅式)。

1.8@Component @Bean 的区别是什么?

1. 作⽤对象不同 : @Component 注解作⽤于,⽽ @Bean 注解作⽤于⽅法。
2. @Component 通常是通过类路径扫描来⾃动侦测以及⾃动装配到 Spring 容器中(我们可以使
@ComponentScan 注解定义要扫描的路径从中找出标识了需要装配的类⾃动装配到
Spring bean 容器中)。 @Bean 注解通常是我们在标有该注解的⽅法中定义产⽣这个
bean, @Bean 告诉了 Spring 这是某个类的示例,当我需要⽤它的时候还给我。
3. @Bean 注解⽐ Component 注解的⾃定义性更强,⽽且很多地⽅我们只能通过 @Bean
解来注册 bean 。⽐如当我们引⽤第三⽅库中的类需要装配到 Spring 容器时,则只能通过
@Bean 来实现。

1.9将⼀个类声明为Spring bean 的注解有哪些?

我们⼀般使⽤ @Autowired 注解⾃动装配 bean ,要想把类标识成可⽤于 @Autowired 注解⾃动
装配的 bean 的类 , 采⽤以下注解可实现:
@Component :通⽤的注解,可标注任意类为 Spring 组件。如果⼀个 Bean 不知道属于哪
个层,可以使⽤ @Component 注解标注。
@Repository : 对应持久层即 Dao 层,主要⽤于数据库相关操作。
@Service : 对应服务层,主要涉及⼀些复杂的逻辑,需要⽤到 Dao 层。
@Controller : 对应 Spring MVC 控制层,主要⽤户接受⽤户请求并调⽤ Service 层返回数
据给前端⻚⾯。

1.10Spring 中的 bean ⽣命周期?

Bean 容器找到配置⽂件中 Spring Bean 的定义。
Bean 容器利⽤ Java Reflection API 创建⼀个 Bean 的实例。如果涉及到⼀些属性值 利⽤ set() ⽅法设置⼀些属性值。
如果 Bean 实现了 BeanNameAware 接⼝,调⽤ setBeanName() ⽅法,传⼊ Bean 的名字。
如果 Bean 实现了 BeanClassLoaderAware 接⼝,调⽤ setBeanClassLoader() ⽅法,传⼊ ClassLoader 对象的实例。
与上⾯的类似,如果实现了其他 *.Aware 接⼝,就调⽤相应的⽅法。
如果有和加载这个 Bean Spring 容器相关的 BeanPostProcessor 对象,执
postProcessBeforeInitialization() ⽅法
如果 Bean 实现了 InitializingBean 接⼝,执⾏ afterPropertiesSet() ⽅法。
如果 Bean 在配置⽂件中的定义包含 init-method 属性,执⾏指定的⽅法。
} 如果有和加载这个 Bean Spring 容器相关的 BeanPostProcessor 对象,执⾏ postProcessAfterInitialization() ⽅法
当要销毁 Bean 的时候,如果 Bean 实现了 DisposableBean 接⼝,执⾏ destroy() ⽅法。
当要销毁 Bean 的时候,如果 Bean 在配置⽂件中的定义包含 destroy-method 属性,执⾏指
定的⽅法。

1.11说说⾃⼰对于 Spring MVC 了解?

MVC(Model View Controller) 是⼀种设计模式,Spring MVC 是⼀款很优秀的 MVC 框架。 Spring MVC 可以帮助我们进⾏更简洁的Web 层的开发,并且它天⽣与 Spring 框架集成。 Spring MVC 下我们⼀般把后端项⽬分为 Service 层(处理业务)、 Dao 层(数据库操作)、 Entity 层(实体类)、 Controller ( 控制层,返回数据给前台⻚⾯)

1.12SpringMVC ⼯作原理了解吗?

1. 客户端(浏览器)发送请求,直接请求到 前端控制器 
2. 前端控制器根据请求信息调⽤ HandlerMapping ,解析请求对应的 Handler
3. 解析到对应的 Handler (也就是我们平常说的 Controller 控制器)后,开始由HandlerAdapter 适配器处理。
4. HandlerAdapter 会根据 Handler 来调⽤真正的处理器(controller)来处理请求,并处理相应的业务逻辑。
5. 处理器处理完业务后,会返回⼀个 ModelAndView 对象 Model 是返回的数据对象, View 是个逻辑上的 View
6. ViewResolver 会根据逻辑 View 查找实际的 View
7. 前端控制器把返回的 Model 传给 View (视图渲染)。
8. View 返回给请求者(浏览器)

1.13Spring 框架中⽤到了哪些设计模式?

⼯⼚设计模式 : Spring 使⽤⼯⼚模式通过 BeanFactory ApplicationContext 创建 bean
象。
代理设计模式 : Spring AOP 功能的实现。
单例设计模式 : Spring 中的 Bean 默认都是单例的。
包装器设计模式 : 我们的项⽬需要连接多个数据库,⽽且不同的客户在每次访问中根据需要会去访问不同的数据库。这种模式让我们可以根据客户的需求能够动态切换不同的数据源。
观察者模式 : Spring 事件驱动模型就是观察者模式很经典的⼀个应⽤。
适配器模式 :Spring AOP 的增强或通知 (Advice) 使⽤到了适配器模式、 spring MVC 中也是⽤
到了适配器模式适配 Controller

1.14Spring 管理事务的⽅式有⼏种?

1. 编程式事务,在代码中硬编码。 ( 不推荐使⽤ )
2. 声明式事务,在配置⽂件中配置(推荐使⽤)
声明式事务⼜分为两种:
1. 基于 XML 的声明式事务
2. 基于注解的声明式事务

1.15Spring 事务中的隔离级别有哪⼏种?

1.16Spring 事务中哪⼏种事务传播⾏为?

事务传播行为,指的就是当一个事务方法被另一个事务方法调用时,这个事务方法应该如何进行。

⽀持当前事务的情况:
REQUIRED(required) 如果当前存在事务,则加⼊该事务;如果当前没有事务,则创建⼀个新的事务。不管有几个事务存在,都合并成一个事务来处理,只要有一个事务抛出异常,所有事务都会回滚;
SUPPORTS(supports) 如果当前存在事务,则加⼊该事务;如果当前没有事务,则以⾮事务的⽅式继续运⾏。如果哥哥有一个苹果,我就吃哥哥的苹果,如果哥哥没有苹果,那我也没得吃;
MANDATORY(mandatory) 如果当前存在事务,则加⼊该事务;如果当前没有事务,则抛出异常。(mandatory :强制性)
不⽀持当前事务的情况:
REQUIRES_NEW(requires-new) 创建⼀个新的事务,如果当前存在事务,则把当前事务挂起。
NOT_SUPPORTED(not-supported) 以⾮事务⽅式运⾏,如果当前存在事务,则把当前事务挂起。
NEVER(never) 以⾮事务⽅式运⾏,如果当前存在事务,则抛出异常。
其他情况:
NESTED(nested) 如果当前存在事务,则创建⼀个事务作为当前事务的嵌套事务来运⾏;如果当前没有事务,则该取值等价于REQUIRED.如果哥哥吃苹果吃出毛病了(代码抛异常了),那我和哥哥都会回到原点(回滚),如果我吃苹果吃出毛病了(代码抛异常了),那就只有我会回到原点(回滚);

1.17@Transactional(rollbackFor = Exception.class)注解了解吗?

@Transactional 注解作⽤于类上时,该类的所有 public ⽅法将都具有该类型的事务属性,同
时,我们也可以在⽅法级别使⽤该标注来覆盖类级别的定义。如果类或者⽅法加了这个注解,那
么这个类⾥⾯的⽅法抛出异常,就会回滚,数据库⾥⾯的数据也会回滚。
@Transactional 注解中如果不配置 rollbackFor 属性 , 那么事物只会在遇到 RuntimeException 的时候才会回滚, 加上 rollbackFor=Exception.class , 可以让事物在遇到⾮运⾏时异常时也回滚。

1.18如何使⽤JPA在数据库中⾮持久化⼀个字段?

字段不被持久化,也就是不被数据库存储.
1.static String transient1; // not persistent because of static
2.final String transient2 = “Satish”; // not persistent because of final
3.transient String transient3; // not persistent because of transient(不被序列化)
4.@Transient
String transient4; // not persistent because of @Transient

2.MyBatis

2.1#{}${}的区别是什么?

        ${} 是 Properties ⽂件中的变量占位符,它可以⽤于标签属性值和 sql 内部,属于静态⽂
本替换,⽐如 ${driver} 会被静态替换为 com.mysql.jdbc.Driver
        #{} 是 sql 的参数占位符, Mybatis 会将 sql 中的 #{} 替换为 ? 号,在 sql 执⾏前会使⽤
PreparedStatement 的参数设置⽅法,按序给 sql ? 号占位符设置参数值,⽐如
ps.setInt(0, parameterValue) #{item.name} 的取值⽅式为使⽤反射从参数对象中获取
item 对象的 name 属性值,相当于 param.getItem().getName()

2.2Xml 映射⽂件中,除了常⻅的 select|insert|updae|delete 签之外,还有哪些标签?

<resultMap> <parameterMap> <sql> <include> <selectKey> ,加上动态 sql 9
个标签, trim|where|set|foreach|if|choose|when|otherwise|bind 等,其中  sql ⽚段标签,通过
<include> 标签引⼊ sql ⽚段, <selectKey> 为不⽀持⾃增的主键⽣成策略标签。

2.3最佳实践中,通常⼀个 Xml 映射⽂件,都会写⼀个 Dao 接⼝与之对应,请问,这个 Dao 接⼝的⼯作原理是什么?Dao 接⼝⾥的⽅法,参数不同时,⽅法能重载吗?

Dao 接⼝,就是⼈们常说的 Mapper 接⼝,接⼝的全限名,就是映射⽂件中的 namespace的值,接⼝的⽅法名,就是映射⽂件中 MappedStatement id 值,接⼝⽅法内的参数,就是传递给 sql 的参数。 Mapper 接⼝是没有实现类的,当调⽤接⼝⽅法时,接⼝全限名 + ⽅法名拼接字符
串作为 key 值,可唯⼀定位⼀个 MappedStatement. Mybatis 中,每⼀个 <select> <insert> <update> <delete> 标签,都会被解析为⼀ MappedStatement 对象
Dao 接⼝⾥的⽅法,是不能重载的,因为是全限名 + ⽅法名的保存和寻找策略。
Dao 接⼝的⼯作原理是 JDK 动态代理 Mybatis 运⾏时会使⽤ JDK 动态代理为 Dao 接⼝⽣成代
proxy 对象,代理对象 proxy 会拦截接⼝⽅法,转⽽执⾏ MappedStatement 所代表的 sql ,然后将 sql 执⾏结果返回。

2.4Mybatis 是如何进⾏分⻚的?分⻚插件的原理是什么?

Mybatis 使⽤ RowBounds 对象进⾏分⻚,它是针对 ResultSet 结果集执⾏的内存分⻚,⽽
⾮物理分⻚,可以在 sql 内直接书写带有物理分⻚的参数来完成物理分⻚功能,也可以使⽤分⻚
插件来完成物理分⻚。
分⻚插件的基本原理是使⽤ Mybatis 提供的插件接⼝,实现⾃定义插件,在插件的拦截⽅法内拦
截待执⾏的 sql ,然后重写 sql ,根据 dialect ⽅⾔,添加对应的物理分⻚语句和物理分⻚参数

2.5简述 Mybatis 的插件运⾏原理,以及如何编写⼀个插件

        Mybatis 仅可以编写针对ParameterHandler 、 ResultSetHandler StatementHandler Executor 4 种接⼝的插件,Mybatis 使⽤ JDK 的动态代理,为需要拦截的接⼝⽣成代理对象以实现接⼝⽅法拦截功能,每当执⾏这 4 种接⼝对象的⽅法时,就会进⼊拦截⽅法,具体就是 InvocationHandler invoke() ,当然,只会拦截那些你指定需要拦截的⽅法。
        实现 Mybatis Interceptor 接⼝并复写 intercept() ⽅法,然后在给插件编写注解,指定要拦截哪⼀个接⼝的哪些⽅法即可,记住,别忘了在配置⽂件中配置你编写的插件。

2.6Mybatis 执⾏批量插⼊,能返回数据库主键列表吗?

在mysql数据库中支持批量插入,所以只要配置useGeneratedKeys(true)和keyProperty(主键字段)就可以批量插入并返回主键了。

2.7Mybatis 动态 sql 是做什么的?都有哪些动态 sql?能简述⼀下动态 sql 的执⾏原理不?

Mybatis 动态 sql 可以让我们在 Xml 映射⽂件内,以标签的形式编写动态 sql ,完成逻辑判断
和动态拼接 sql 的功能, Mybatis 提供了 9 种动态 sql 标签trim|where|set|foreach|if|choose|when|otherwise|bind 。
其执⾏原理为,使 OGNL sql 参数对象中计算表达式的值,根据表达式的值动态拼接 sql
以此来完成动态 sql 的功能。

2.8Mybatis 是如何将 sql 执⾏结果封装为⽬标对象并返回的?都有哪些映射形式?

        第⼀种是使⽤ <resultMap> 标签,逐⼀定义列名和对象属性名之间的映射关系
        第⼆种是使⽤ sql 列的别名功能将列别名书写为对象属性名,⽐如 T_NAME AS NAME ,对象属性名⼀般是 name ,⼩写,但是列名不区分⼤⼩写, Mybatis 会忽略列名⼤⼩写,智能找到与之对应对象属性名,你甚⾄可以写成 T_NAME AS NaMe Mybatis ⼀样可以正常⼯作。
        有了列名与属性名的映射关系后,Mybatis 通过反射创建对象,同时使⽤反射给对象的属性逐⼀赋值并返回,那些找不到映射关系的属性,是⽆法完成赋值的。

2.9Mybatis 能执⾏⼀对⼀、⼀对多的关联查询吗?都有哪些实现⽅式,以及它们之间的区别。

        能,Mybatis 不仅可以执⾏⼀对⼀、⼀对多的关联查询,还可以执⾏多对⼀,多对多的关联查询,多对⼀查询,其实就是⼀对⼀查询,只需要把 selectOne() 修改为 selectList() 即可;多对多查询,其实就是⼀对多查询,只需要把 selectOne() 修改为 selectList() 即可。
        关联对象查询,有两种实现⽅式,⼀种是单独发送⼀个 sql 去查询关联对象,赋给主对象,然后返回主对象。另⼀种是使⽤嵌套查询,嵌套查询的含义为使⽤ join 查询,⼀部分列是 A 对象的属性值,另外⼀部分列是关联对象 B 的属性值,好处是只发⼀个 sql 查询,就可以把主对象和其关
联对象查出来。
        那么问题来了,join 查询出来 100 条记录,如何确定主对象是 5 个,⽽不是 100 个?其去重复的原理是 <resultMap> 标签内的 <id> ⼦标签,指定了唯⼀确定⼀条记录的 id 列, Mybatis 根据列值来完成 100 条记录的去重复功能, <id> 可以有多个,代表了联合主键的语意。同样主对象的关联对象,也是根据这个原理去重复的,尽管⼀般情况下,只有主对象会有重复记
录,关联对象⼀般不会重复

2.10Mybatis 是否⽀持延迟加载?如果⽀持,它的实现原理是什么?

        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() ⽅法的调⽤。这就是延迟加载的基本原理。

2.11Mybatis Xml 映射⽂件中,不同的 Xml 映射⽂件,id 否可以重复?

不同的 Xml 映射⽂件,如果配置了 namespace ,那么 id 可以重复;如果没有配置namespace,那么 id 不能重复;毕竟 namespace 不是必须的,只是最佳实践⽽已。原因就是 namespace+id 是作为 Map<String, MappedStatement> key 使⽤的,如果没有namespace,就剩下 id ,那么, id 重复会导致数据互相覆盖。有了 namespace ,⾃然 id 就可以重复,namespace 不同, namespace+id ⾃然也就不同。

2.12Mybatis 中如何执⾏批处理?

使⽤ BatchExecutor 完成批处理

2.13Mybatis 都有哪些 Executor 执⾏器?它们之间的区别是什么?

Mybatis 有三种基本的 Executor 执⾏器, SimpleExecutor ReuseExecutor BatchExecutor
SimpleExecutor 每执⾏⼀次 update select ,就开启⼀个 Statement 对象,⽤完⽴刻关闭
Statement 对象。
ReuseExecutor 执⾏ update select ,以 sql 作为 key 查找 Statement 对象,存在就使⽤, 不存在就创建,⽤完后,不关闭 Statement 对象,⽽是放置于 Map<String, Statement> 内,供下
⼀次使⽤。简⾔之,就是重复使⽤ Statement 对象
BatchExecutor 执⾏ update (没有 select JDBC 批处理不⽀持 select ),将所有 sql 都添加
到批处理中( addBatch() ),等待统⼀执⾏( executeBatch() ),它缓存了多个 Statement 对象,每个 Statement 对象都是 addBatch() 完毕后,等待逐⼀执⾏ executeBatch() 批处理。与JDBC 批处理相同。
作⽤范围: Executor 的这些特点,都严格限制在 SqlSession ⽣命周期范围内。

2.14Mybatis 中如何指定使⽤哪⼀种 Executor 执⾏器?

Mybatis 配置⽂件中,可以指定默认的 ExecutorType 执⾏器类型,也可以⼿动给
DefaultSqlSessionFactory 的创建 SqlSession 的⽅法传递 ExecutorType 类型参数。

2.15Mybatis 是否可以映射 Enum 枚举类?

Mybatis 可以映射枚举类,不单可以映射枚举类, Mybatis 可以映射任何对象到表的⼀列上。映射⽅式为⾃定义⼀个 TypeHandler ,实现 TypeHandler setParameter() getResult() 接⼝⽅法。 TypeHandler 有两个作⽤,⼀是完成从 javaType jdbcType 的转换,⼆是完成jdbcType ⾄ javaType 的转换,体现为 setParameter() getResult() 两个⽅法,分别代表设置sql 问号占位符参数和获取列查询结果

2.16Mybatis 映射⽂件中,如果 A 标签通过 include 引⽤了 B 签的内容,请问,B 标签能否定义在 A 标签的后⾯,还是说必须定义在 A 标签的前⾯?

虽然 Mybatis 解析 Xml 映射⽂件是按照顺序解析的,但是,被引⽤的 B 标签依然可以定义
任何地⽅ Mybatis 都可以正确识别。
原理是, Mybatis 解析 A 标签,发现 A 标签引⽤了 B 标签,但是 B 标签尚未解析到,尚不存在,此时,Mybatis 会将 A 标签标记为未解析状态,然后继续解析余下的标签,包含 B 标签,待所有标签解析完毕,Mybatis 会重新解析那些被标记为未解析的标签,此时再解析 A 标签时, B标签已经存在,A 标签也就可以正常解析完成了。

2.17简述 Mybatis Xml 映射⽂件和 Mybatis 内部数据结构之间的映射关系?

Mybatis 将所有 Xml 配置信息都封装到 All-In-One 重量级对象 Configuration 内部。在 Xml映射⽂件中, <parameterMap> 标签会被解析为 ParameterMap 对象,其每个⼦元素会被解析为
ParameterMapping 对象 <resultMap> 标签会被解析为 ResultMap 对象,其每个⼦元素会被解析为 ResultMapping 对象。每⼀个 <select> <insert><update> <delete> 标签均会被解析为MappedStatement 对象,标签内的 sql 会被解析为 BoundSql 对象

2.18为什么说 Mybatis 是半⾃动 ORM 映射⼯具?它与全⾃动的区别在哪⾥?

Hibernate 属于全⾃动 ORM 映射⼯具,使⽤ Hibernate 查询关联对象或者关联集合对象时,可以根据对象关系模型直接获取,所以它是全⾃动的。⽽ Mybatis 在查询关联对象或关联集合对象时,需要⼿动编写 sql 来完成,所以,称之为半⾃动 ORM 映射⼯具。

ORM框架是一种编程技术,它的目标是通过使用面向对象的语法来处理数据库操作,而不是使用传统的SQL查询

3.Kafka

3.1Kafka 是什么?主要应⽤场景有哪些?

Kafka 是⼀个分布式流式处理平台。
流平台具有三个关键功能:
1. 消息队列 :发布和订阅消息流,这个功能类似于消息队列,这也是 Kafka 也被归类为消息队
列的原因。
2. 容错的持久⽅式存储记录消息流 Kafka 会把消息持久化到磁盘,有效避免了消息丢失的⻛
·
3. 流式处理平台: 在消息发布的时候进⾏处理, Kafka 提供了⼀个完整的流式处理类库。
Kafka 主要有两⼤应⽤场景:
1. 消息队列 :建⽴实时流数据管道,以可靠地在系统或应⽤程序之间获取数据。
2. 数据处理: 构建实时的流数据处理程序来转换或处理数据流。

3.2和其他消息队列相⽐,Kafka的优势在哪⾥?

1. 极致的性能 :基于 Scala Java 语⾔开发,设计中⼤量使⽤了批量处理和异步的思想,最
⾼可以每秒处理千万级别的消息。
2. ⽣态系统兼容性⽆可匹敌 Kafka 与周边⽣态系统的兼容性是最好的没有之⼀,尤其在⼤数
据和流计算领域。

3.3队列模型了解吗?Kafka 的消息模型知道吗?

队列模型:早期的消息模型

使⽤队列( Queue )作为消息通信载体,满⾜⽣产者与消费者模式,⼀条消息只能被⼀个消费者
使⽤,未被消费的消息在队列中保留直到被消费或超时。
不好解决的问题: 假如我们存在这样⼀种情况:我们需要将⽣产者产⽣的消息分发给多个消费者,并且每个消费者 都能接收到完成的消息内容。
发布 - 订阅模型 :Kafka 消息模型
在发布 - 订阅模型中,如果只有⼀个订阅者,那它和队列模型就基本是⼀样的了。所以说,发布
- 订阅模型在功能层⾯上是可以兼容队列模型的。
Kafka 采⽤的就是发布 - 订阅模型。
RocketMQ 的消息模型和 Kafka 基本是完全⼀样的。唯⼀的区别是 Kafka 中没有队列这个 概念,与之对应的是 Partition (分区)。

3.4什么是ProducerConsumerBrokerTopicPartition

Kafka 将⽣产者发布的消息发送到 Topic (主题) 中,需要这些消息的消费者可以订阅这些
Topic (主题)。
1. Producer (⽣产者) : 产⽣消息的⼀⽅。
2. Consumer (消费者) : 消费消息的⼀⽅。
3. Broker (代理) : 可以看作是⼀个独⽴的 Kafka 实例。多个 Kafka Broker 组成⼀个 KafkaCluster。
4.Topic (主题) : Producer 将消息发送到特定的主题, Consumer 通过订阅特定的 Topic(
) 来消费消息。
5.Partition (分区) : Partition 属于 Topic 的⼀部分,真正保存消息的地⽅。⼀个 Topic 可以有多个 Partition ,并且同⼀ Topic 下的 Partition 可以分布在不同的 Broker 上,这也就表明⼀个 Topic 可以横跨多个 Broker 。Kafka 中的 Partition (分区) 实际上可以对应成为消息队列中的队列

3.5Kafka 的多副本机制了解吗?带来了什么好处?

分区(Partition )中的多个副本之间会有⼀个叫做 leader 的家伙,其他副本称为 follower 。我们发送的消息会被发送到 leader 副本,然后 follower 副本才能从 leader 副本中拉取消息进⾏同步。
⽣产者和消费者只与 leader 副本交互。你可以理解为其他副本只是 leader 副本的拷⻉,它
们的存在只是为了保证消息存储的安全性。当 leader 副本发⽣故障时会从 follower 中选举
出⼀个 leader,但是 follower 中如果有和 leader 同步程度达不到要求的参加不了 leader 的竞
Kafka 的多分区( Partition )以及多副本( Replica )机制有什么好处呢?
1. Kafka 通过给特定 Topic 指定多个 Partition, ⽽各个 Partition 可以分布在不同的 Broker ,
这样便能提供⽐较好的并发能⼒(负载均衡)。
2. Partition 可以指定对应的 Replica , 这也极⼤地提⾼了消息存储的安全性 , 提⾼了容灾能
⼒,不过也相应的增加了所需要的存储空间

3.6Zookeeper Kafka 中的作⽤知道吗?

ZooKeeper 主要为 Kafka 提供元数据的管理的功能
1. Broker 注册 :在 Zookeeper 上会有⼀个专⻔ ⽤来进⾏ Broker 服务器列表记录 的节点。每
Broker 在启动时,都会到 Zookeeper 上进⾏注册,即到 /brokers/ids 下创建属于⾃⼰的节点。每个 Broker 就会将⾃⼰的 IP 地址和端⼝等信息记录到该节点中去
2. Topic 注册 : 在 Kafka 中,同⼀个 Topic 的消息会被分成多个分区 并将其分布在多个Broker 上, 这些分区信息及与 Broker 的对应关系 也都是由 Zookeeper 在维护。
3. 负载均衡 :上⾯也说过了 Kafka 通过给特定 Topic 指定多个 Partition, ⽽各个 Partition 可以
分布在不同的 Broker , 这样便能提供⽐较好的并发能⼒。 对于同⼀个 Topic 的不同Partition, Kafka 会尽⼒将这些 Partition 分布到不同的 Broker 服务器上。当⽣产者产⽣消息后也会尽量投递到不同 Broker Partition ⾥⾯。当 Consumer 消费的时候, Zookeeper 可以根据当前的 Partition 数量以及 Consumer 数量来实现动态负载均衡

3.7Kafka 如何保证消息的消费顺序?

        每次添加消息到 Partition( 分区 ) 的时候都会采⽤尾加法 Kafka 只能为我们保证Partition(分区 ) 中的消息有序,⽽不能保证 Topic( 主题 ) 中的 Partition( 分区 ) 的有序。 消息在被追加到 Partition( 分区 ) 的时候都会分配⼀个特定的偏移量( offset Kafka 通过偏 移量( offset )来保证消息在分区内的顺序性。
        Kafka 中发送 1 条消息的时候,可以指定 topic, partition, key,data (数据) 4 个参数。如果你发送消息的时候指定了 Partition 的话,所有消息都会被发送到指定的 Partition 。并且,同⼀个 key
的消息可以保证只发送到同⼀个 partition ,这个我们可以采⽤表 / 对象的 id 来作为 key
对于如何保证 Kafka 中消息消费的顺序,有了下⾯两种⽅法:
1. 1 Topic 只对应⼀个 Partition
2. (推荐)发送消息的时候指定 key/Partition

3.8Kafka 如何保证消息不丢失

⽣产者丢失消息的情况
⽣产者 (Producer) 调⽤ send ⽅法发送消息之后,消息可能因为⽹络问题并没有发送过去。
1.Kafka ⽣产者 (Producer) 使⽤ send ⽅法发送消息实际上是异步的操作,我们可以通过 get() ⽅法获取调⽤结果,但是这样也让它变为了同步操作

2.为其添加回调函数的形式。如果消息发送失败的话,我们检查失败的原因之后重新发送即可!

另外这⾥推荐为 Producer retries (重试次数)设置⼀个⽐较合理的值,⼀般是 3 ,但是为
了保证消息不丢失的话⼀般会设置⽐较⼤⼀点。设置完成之后,当出现⽹络问题之后能够⾃动重
试消息发送,避免消息丢失。另外,建议还要设置重试间隔,因为间隔太⼩的话重试的效果就不
明显了,⽹络波动⼀次你 3 次⼀下⼦就重试完了
消费者丢失消息的情况
我们知道消息在被追加到 Partition( 分区 ) 的时候都会分配⼀个特定的偏移量 offset )。偏移量 (offset) 表示 Consumer 当前消费到的 Partition( 分区 ) 的所在的位置。 Kafka 通过偏移量 (offset )可以保证消息在分区内的顺序性。
当消费者拉取到了分区的某个消息之后,消费者会⾃动提交  offset 。⾃动提交的话会有⼀个问题,当消费者刚拿到这个消息准备进⾏真正消费的时候,突然挂掉了,消息实际上并没有被消费,但是 offset 却被⾃动提交了。 解决办法也⽐较粗暴,我们⼿动关闭闭⾃动提交 offset ,每次在真正消费完消息之后之后再⾃⼰ ⼿动提交 offset 但是,这样会带来消息被重新消费的问题。⽐如你刚刚消费完消息之后,还没提交 offset ,结果⾃⼰挂掉了,那么这个消息理论上就会被消费两次

Kafka 弄丢了消息
假如 leader 副本所在的 broker 突然挂掉,那么就要从 follower 副本重新选出
⼀个 leader ,但是 leader 的数据还有⼀些没有被 follower 副本的同步的话,就会造成消息丢
失。四步骤:
1.设置 acks = all
解决办法就是我们设置 acks = all acks Kafka ⽣产者 (Producer) 很重要的⼀个参数。acks 的默认值即为 1 ,代表我们的消息被 leader 副本接收之后就算被成功发送。当我们配置 acks = all 代表则所有副本都要接收到该消息之后该消息才算真正成功被发送。
2.设置 replication.factor >= 3
为了保证 leader 副本能有 follower 副本能同步消息,我们⼀般会为 topic 设置 replication.factor
>= 3 。这样就可以保证每个分区 (partition) ⾄少有 3 个副本。虽然造成了数据冗余,但是带来了
数据的安全性。
3.设置 min.insync.replicas > 1
⼀般情况下我们还需要设置 min.insync.replicas> 1 ,这样配置代表消息⾄少要被写⼊到 2 个副
本才算是被成功发送 min.insync.replicas 的默认值为 1 ,在实际⽣产中应尽量避免默认值1。
但是,为了保证整个 Kafka 服务的⾼可⽤性,你需要确保 replication.factor > min.insync.replicas
为什么呢?设想⼀下加⼊两者相等的话,只要是有⼀个副本挂掉,整个分区就⽆法正常⼯作了。这明显违反⾼可⽤性!⼀般推荐设置成 replication.factor = min.insync.replicas + 1
4.设置 unclean.leader.election.enable = false
多个 follower 副本之间的消息同步情况不⼀样,当我们配置了 unclean.leader.election.enable = false 的话,当 leader 副本发⽣故障时就不会从 follower 副本中和 leader 同步程度达不到要求的副本中选择出 leader ,这样降低了消息丢失的可能性。

3.9Kafka 如何保证消息不重复消费

生产端:
生产端发送消息后,假如遇到网络问题,无法获得响应,生产端就无法判断该消息是否成功提交到了 Kafka,而我们一般会配置重试次数,但这样会引发生产端重新发送同一条消息,从而造成消息重复的发送。

从 0.11.0 的版本开始,Kafka 给每个 producer 一个唯一 ID,并且在每条消息中生成一个 sequence num,sequence num是递增且唯一的这样就能对消息去重,达到 一个生产端不重复发送一条消息。但是这个方法是有局限性的,只在一个 生产端 内生产的消息有效,如果一个消息分别在两个 producer 发送就不行了,还是会造成消息的重复发送。但是这种可能性比较小,因为消息的重试一般会在一个生产端内进行。当然,对应一个消息分别在两个 producer 发送的请求我们也有方案,只是多做一些补偿的工作,我们可以为每一个消息分配一个全局id,并把全局id存放在远程缓存或关系型数据库里。这样在发送前判断一下是否已经发送过。

服务端:
服务端不会重复的存储消息,如果有重复消息也应该是生产端重复发送造成的,所以无需特别的配置。

消费端
第一步,enable.auto.commit=false:

同样要避免自动提交偏移量,大家可以想象一种情况,消费端拉取消息和处理消息都完成了,但是自动提交偏移量还没提交这时消费端挂了,这时候kakfa消费组开始重平衡并把分区分给了另一个消费者,由于偏移量没提交新的消费者会重复拉取消息,最终造成重复消费消息。

第二步,单纯配成手动提交同样不能避免重复消费,需要消费端用正确姿势消费。

消费者拉取消息后,先提交 offset 后再处理消息。在提交 offset 之后,业务逻辑处理消息之前出现宕机,待消费者重新上线时,就无法读到刚刚已经提交而未处理的这部分消息,这就对应了不重复消费消息但是会有丢失消息的情况。

4.Netty

  • 32
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Bootstrap 是一个流行的前端开发框架,几乎所有的前端面试都会涉及到它。而Bootstrap 面试的主要内容,主要涉及到以下几个方面。 首先,面试官会询问你关于 BootStrap 的基本概念、使用场景和原理。Bootstrap 是一个基于 HTML、CSS、JavaScript 的快速开发框架,主要用于前端开发。它使用了响应式设计,支持各种屏幕大小和类型的设备。你需要根据使用场景去使用不同的版本,同时要熟悉其布局原理和基本的使用方法,从而能够熟练地在自己的项目中应用Bootstrap。 其次,面试官可能会提问关于响应式设计、网格系统和组件的使用。Bootstrap 是一个响应式设计框架,其使用了一个灵活的网格系统,以此来布局页面,而组件则是为了快速开发页面而设计的。因此,你需要熟悉 Bootstrap 的网格系统原理、媒体查询的使用方法等等,同时对常用的组件如导航、表格、表单、按钮、图标等有一定的掌握,并根据实际需要进行合理使用。 第三,面试官可能会问你一些关于 Bootstrap 的扩展库和插件的使用情况。Bootstrap 有很多的扩展库和插件,如:插件、主题、工具、表单验证等等。你需要掌握它们的基本用法和使用思路,能够灵活运用它们完成各种自己的项目需求。 最后,面试官可能会问你一些关于 Bootstrap 的性能和优化相关的内容。Bootstrap 已经很流行了,但是,无论多好的框架都会有自己的优缺点,你需要对 Bootstrap 框架其优化和性能等方面问题进行了解,为了更好地使用 Bootstrap, 并且为了更好地优化它。 总之,只有熟悉了 Bootstrap 的基本使用和扩展,理解其性能和优化并为此做出努力,才能成为一名优秀的前端开发者。当然,对于面试官而言,看重的不仅仅是你的知识面有多广,更是你能不能将所学到的知识运用到实际的项目中,提高自己的开发效率和质量。因此,面试时一定要自信,不断学习和应用 Bootstrap 相关的技术,才能在竞争激烈的市场中脱颖而出。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值