网上的常规与经典面试题汇总与答案—–框架
面试常考知识点
Spring
BeanFactory 和 ApplicationContext 有什么区别
- ApplicationContext 是 BeanFactory接口的子接口
- BeanFactory 采用的是延迟加载,第一次getBean的时候才会初始化Bean
- ApplicationContext是对BeanFactory的扩展,提供了更多的功能
- 国际化处理
- 事件传递
- Bean自动装配
- 各种不同应用层的Context实现
Spring Bean的生命周期
- 实例化一个Bean,也就是我们通常说的new
- 按照Spring上下文对实例化的Bean进行配置,也就是IOC注入
- 如果这个Bean实现了BeanNameAware接口,会调用它实现的setBeanName(String beanId)方法,此处传递的是Spring配置文件中Bean的ID
- 如果这个Bean实现了BeanFactoryAware接口,会调用它实现的setBeanFactory(),传递的是Spring工厂本身(可以用这个方法获取到其他Bean)
- 如果这个Bean实现了ApplicationContextAware接口,会调用setApplicationContext(ApplicationContext)方法,传入Spring上下文,该方式同样可以实现步骤4,但比4更好,以为ApplicationContext是BeanFactory的子接口,有更多的实现方法
- 如果这个Bean关联了BeanPostProcessor接口,将会调用postProcessBeforeInitialization(Object obj, String s)方法,BeanPostProcessor经常被用作是Bean内容的更改,并且由于这个是在Bean初始化结束时调用After方法,也可用于内存或缓存技术
- 如果这个Bean在Spring配置文件中配置了init-method属性会自动调用其配置的初始化方法
- 如果这个Bean关联了BeanPostProcessor接口,将会调用postAfterInitialization(Object obj, String s)方法 注意:以上工作完成以后就可以用这个Bean了,那这个Bean是一个single的,所以一般情况下我们调用同一个ID的Bean会是在内容地址相同的实例
- 当Bean不再需要时,会经过清理阶段,如果Bean实现了DisposableBean接口,会调用其实现的destroy方法
- 最后,如果这个Bean的Spring配置中配置了destroy-method属性,会自动调用其配置的销毁方法
以BeanFactory为例,说明一个Bean的生命周期活动
- Bean的建立, 由BeanFactory读取Bean定义文件,并生成各个实例
- Setter注入,执行Bean的属性依赖注入
- BeanNameAware的setBeanName(), 如果实现该接口,则执行其setBeanName方法
- BeanFactoryAware的setBeanFactory(),如果实现该接口,则执行其setBeanFactory方法
- BeanPostProcessor的processBeforeInitialization(),如果有关联的processor,则在Bean初始化之前都会执行这个实例的processBeforeInitialization()方法
- InitializingBean的afterPropertiesSet(),如果实现了该接口,则执行其afterPropertiesSet()方法
- Bean定义文件中定义init-method
- BeanPostProcessors的processAfterInitialization(),如果有关联的processor,则在Bean初始化之前都会执行这个实例的processAfterInitialization()方法
- DisposableBean的destroy(),在容器关闭时,如果Bean类实现了该接口,则执行它的destroy()方法
- Bean定义文件中定义destroy-method,在容器关闭时,可以在Bean定义文件中使用“destory-method”定义的方法
如果使用ApplicationContext来维护一个Bean的生命周期,则基本上与上边的流程相同,只不过在执行BeanNameAware的setBeanName()后,若有Bean类实现了org.springframework.context.ApplicationContextAware接口,则执行其setApplicationContext()方法,然后再进行BeanPostProcessors的processBeforeInitialization()实际上,ApplicationContext除了向BeanFactory那样维护容器外,还提供了更加丰富的框架功能,如Bean的消息,事件处理机制等
Spring IOC 如何实现
https://www.cnblogs.com/ITtangtang/p/3978349.html
说说 Spring AOP
AOP技术利用一种称为“横切”的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其名为“Aspect”,即方面。所谓“方面”,简单地说,就是将那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。使用“横切”技术,AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处都基本相似。比如权限认证、日志、事务处理。Aop 的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。
实现原理:代理模式
https://www.jianshu.com/p/874acbfba73a
动态代理
https://www.cnblogs.com/gonjan-blog/p/6685611.html
Spring 事务实现方式
事务的ACID特性
事务的传播特性
Spring定义了7中传播行为
- propagation_requierd:如果当前没有事务,就新建一个事务,如果已存在一个事务中,加入到这个事务中,这是Spring默认的选择。
- propagation_supports:支持当前事务,如果没有当前事务,就以非事务方法执行
- propagation_mandatory:使用当前事务,如果没有当前事务,就抛出异常。
- propagation_required_new:新建事务,如果当前存在事务,把当前事务挂起。
- propagation_not_supported:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起
- propagation_never:以非事务方式执行操作,如果当前事务存在则抛出异常
- propagation_nested:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与propagation_required类似的操作
事务的隔离级别
- read uncommited(读未提交):是最低的事务隔离级别,它允许另外一个事务可以看到这个事务未提交的数据
- read commited(读已提交):保证一个事物提交后才能被另外一个事务读取。另外一个事务不能读取该事物未提交的数据。
- repeatable read(可重复读):这种事务隔离级别可以防止脏读,不可重复读。但是可能会出现幻象读。它除了保证一个事务不能被另外一个事务读取未提交的数据之外还避免了以下情况产生(不可重复读)
- serializable(串行化):这是花费最高代价但最可靠的事务隔离级别。事务被处理为顺序执行。除了防止脏读,不可重复读之外,还避免了幻象读
四种隔离级别最高:Seralizable级别,最低的是Read uncommitted级别; 级别越高,执行效率就越低; 隔离级别的设置只对当前链接有效,对JDBC操作数据库来说,一个Connection对象相当于一个链接,只对该Connection对象设置的隔离级别只对该connection对象有效,与其它链接connection对象无关。
事务几种实现方式
- 编程式事务管理对基于 POJO 的应用来说是唯一选择。我们需要在代码中调用beginTransaction()、commit()、rollback()等事务管理相关的方法,这就是编程式事务管理。
- 基于 TransactionProxyFactoryBean的声明式事务管理
- 基于 @Transactional 的声明式事务管理
- 基于Aspectj AOP配置事务
SpringMvc的运行流程
- 用户发送请求到DispatchServlet
- DispatchServlet根据请求路径查询具体的Handler
- HandlerMapping返回一个HandlerExcutionChain给DispatchServlet HandlerExcutionChain:Handler和Interceptor集合
- DispatchServlet调用HandlerAdapter适配器
- HandlerAdapter调用具体的Handler处理业务
- Handler处理结束返回一个具体的ModelAndView给适配器 ModelAndView:model–>数据模型,view–>视图名称
- 适配器将ModelAndView给DispatchServlet
- DispatchServlet把视图名称给ViewResolver视图解析器
- ViewResolver返回一个具体的视图给DispatchServlet
- 渲染视图
- 展示给用户
Spring MVC 启动流程
https://blog.csdn.net/ahou2468/article/details/69948990
Spring 的单例实现原理
Spring框架对单例的支持是采用单例注册表的方式进行实现
https://www.cnblogs.com/qianzf/p/6793138.html
Spring 框架中用到了哪些设计模式
简单工厂
spring中的BeanFactory就是简单工厂模式的体现,根据传入一个唯一的标识来获得bean对象,但是否是在传入参数后创建还是传入参数前创建这个要根据具体情况来定
工厂方法(Factory Method)
一般情况下,应用程序有自己的工厂对象来创建bean.如果将应用程序自己的工厂对象交给Spring管理,那么Spring管理的就不是普通的bean,而是工厂Bean
单例模式(Singleton)
保证一个类仅有一个实例,并提供一个访问它的全局访问点。
spring中的单例模式完成了后半句话,即提供了全局的访问点BeanFactory。但没有从构造器级别去控制单例,这是因为spring管理的是是任意的java对象。
适配器(Adapter)
包装器(Decorator)
代理(Proxy)
spring的Proxy模式在aop中有体现,比如JdkDynamicAopProxy和Cglib2AopProxy。
观察者(Observer)
spring中Observer模式常用的地方是listener的实现。如ApplicationListener。
策略(Strategy)
spring中在实例化对象的时候用到Strategy模式在SimpleInstantiationStrategy中有如下代码说明了策略模式的使用情况
模板方法(Template Method)
spring中的JdbcTemplate
Netty
为什么选择 Netty
- API使用简单,开发门槛低。
- 功能强大,预置了多种编解码功能,支持多种协议开发。
- 定制能力强,可以通过ChannelHadler进行扩展。
- 性能高,对比其它NIO框架,Netty综合性能最优。
- 经历了大规模的应用验证。在互联网、大数据、网络游戏、企业应用、电信软件得到成功,很多著名的框架通信底层就用了Netty,比如Dubbo
- 稳定,修复了NIO出现的所有Bug。
- 切换IO和NIO,因为IO和NIO的API完全不同,相互切换非常困难。
TCP 粘包/拆包
一个完整的包可能会被TCP拆分成多个包进行发送,也有可能把多个小的包封装成一个大的数据包发送,这就是所谓的TCP粘包和拆包问题。
TCP粘包/拆包发生的原因
- 应用程序write写入的字节大小大于套接口发送缓冲区大小
- 进行MSS大小的TCP分段
- 以太网帧的payload大于MTU进行IP分片
粘包问题的解决策略
由于底层的TCP无法理解上层的业务数据,所以在底层是无法保证数据包不被拆分和重组的,这个问题只能通过上层的应用协议栈设计来解决,根据业界的主流协议的解决方案,可以归纳如下。
- 消息定长,例如每个报文的大小为固定长度200字节,如果不够,空位补空格;
- 在包尾增加回车换行符进行分割,例如FTP协议
- 将消息分为消息头和消息体,消息头中包含表示消息总长度(或者消息体长度)的字段,通常设计思路为消息头的第一个字段使用int32来表示消息的总长度
- 更复杂的应用层协议
Netty 线程模型
https://blog.csdn.net/cj2580/article/details/78124780
Netty 的零拷贝
https://blog.csdn.net/linsongbin1/article/details/77650105
Netty 内部执行流程
https://blog.csdn.net/Truong/article/details/62231036
Netty 实现心跳机制与断线重连
https://segmentfault.com/a/1190000006931568