[关闭]
@yexiaoqi 2021-05-23T13:41:52.000000Z 字数 6832 阅读 997

SSM三大框架

java面试总结


Spring

源码解析

核心类介绍

  1. DefaultListableBeanFactory

    DefaultListableBeanFactory是整个bean加载的核心部分,是Spring注册及加载bean的默认实现,XmlBeanFactory继承DefaultListableBeanFactory并扩展。

  2. XmlBeanDefinitionReader

    读取XML配置文件,解析载入的Bean定义的资源文件,解析过后的BeanDefinition在IoC容器中的注册

说说 IoC 容器的初始化过程?

Resource 定位:我们一般使用外部资源来描述 Bean 对象,所以 IOC 容器第一步就是需要定位 Resource 外部资源 。Resource 的定位其实就是 BeanDefinition 的资源定位,它是由 ResourceLoader 通过统一的 Resource 接口来完成的,这个 Resource 对各种形式的 BeanDefinition 的使用都提供了统一接口 。

载入:第二个过程就是 BeanDefinition 的载入 ,BeanDefinitionReader 读取 , 解析 Resource 定位的资源,也就是将用户定义好的 Bean 表示成 IOC 容器的内部数据结构也就是 BeanDefinition, 在 IOC 容器内部维护着一个 BeanDefinitionMap 的数据结构,通过这样的数据结构, IOC 容器能够对 Bean 进行更好的管理 。 在配置文件中每一个都对应着一个 BeanDefinition 对象 。

注册:第三个过程则是注册,即向 IOC 容器注册这些 BeanDefinition,这个过程是通过 BeanDefinitionRegistery 接口来实现的 。

BeanFactory 和 ApplicationContext 的区别? 什么是延迟实例化,它的优缺点是什么?

BeanFactory 是 Spring 里面最低层的接口,提供了最简单的容器的功能,只提供了实例化对象和获取对象的功能 。

两者装载 bean 的区别

延迟实例化

优点: 应用启动时占用资源很少,对资源要求较高的应用,比较有优势。

缺点:速度会相对来说慢一些 。 而且有可能会出现空指针异常的错误,而且通过 bean 工厂创建的 bean 生命周期会简单一些。 所有的 Bean 在启动的时候都加载,系统运行的速度快,而且可以尽早的发现系统中的配置问题 。

SpringBoot

SpringBoot 用于简化Spring开发的。

Spring Boot的优点?

Spring Boot自动实现原理

Spring Boot创建一个简单的Web项目很简洁,不需要太多配置

  1. @SpringBootApplication
  2. public class ConfigApplication{
  3. public static void main(String[] args){
  4. SpringApplication.run(ConfigApplication.class, args);
  5. }
  6. }

查看run方法(省略不关键的部分代码):

  1. public COnfigurableApplicationContext run(String... args){
  2. ConfigurableApplicationContext context = null;
  3. configureHeadlessProperty();
  4. SpringApplicationRunListeners listeners = getRunListeners(args);
  5. listeners.started();
  6. try {
  7. ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
  8. ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
  9. Banner printedBanner = printBanner(environment);
  10. context = createApplicationContext();
  11. analyzers = new FailureAnalyzers(context);
  12. prepareContext(context, environment, listeners, applicationArguments, printedBanner);
  13. listeners.finished(context, null); return context;
  14. }catch (Throwable ex) {
  15. handleRunFailure(context, listeners, analyzers, ex);
  16. throw new IllegalStateException(ex);
  17. }
  18. }

它首先开启一个SpringApplicationRunListeners监听器,让后创建一个应用上下文ConfigurableApplicationContext,通过这个上下文加载应用所需的类和各种环境配置等。

下面看createApplicationContext方法加载应用定义的和需要的类及各种资源。

自动配置

所有的自动配置都从@SpringBootApplication引入的,它又包含了Configuration@EnableAutoConfiguration@ComponentScan,其中,@EnableAutoConfiguration就是启用自动配置的,并将导入一些自动配置类定义。

  1. @Target({ElementType.TYPE})
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Documented
  4. @Inherited
  5. @SpringBootConfiguration
  6. @EnableAutoConfiguration
  7. @ComponentScan(
  8. excludeFilters = {@Filter(
  9. type = FilterType.CUSTOM,
  10. classes = {TypeExcludeFilter.class}
  11. )} )
  12. public @interface SpringBootApplication {
  13. Class<?>[] exclude() default {};
  14. String[] excludeName() default {};
  15. @AliasFor(
  16. annotation = ComponentScan.class,
  17. attribute = "basePackages"
  18. )
  19. String[] scanBasePackages() default {};
  20. @AliasFor(
  21. annotation = ComponentScan.class,
  22. attribute = "basePackageClasses"
  23. )
  24. Class<?>[] scanBasePackageClasses() default {};
  25. }

@EnableAutoConfiguration中导入了AutoConfigurationImportSelector类,此类中SpringFactoriesLoader.loadFactoryNames 方法的作用就是从META-INF/spring.factories文件中读取指定类对应的类名称列表 ,列表中的自动配置类很多,这些配置类中大多数都将导入,并处于被备用状态,当项目中引入了相关的包时,相关功能将会被启用。

例如在项目的maven配置中配置了Redis的引用,Redis的默认配置项将被启用,首先会读取项目中的配置,只有项目中没有相关配置才启用配置的默认值,下面代码是Redis的自动配置,如果配置文件中没设置,会使用下面默认设置。

  1. @ConfigurationProperties(
  2. prefix = "spring.redis"
  3. )
  4. public class RedisProperties {
  5. private int database = 0;
  6. private String host = "localhost";
  7. private String password;
  8. private int port = 6379;
  9. private int timeout;
  10. private RedisProperties.Pool pool;
  11. private RedisProperties.Sentinel sentinel;
  12. private RedisProperties.Cluster cluster;
  13. public RedisProperties(){
  14. }
  15. }

通过自动配置,就不用重复定义配置项名称了,覆盖约定的配置项即可。可通过查看各个Properties类,查看有哪些配置项。

SpringBoot常用注解

Spring Boot面试题

Spring Boot需要独立的容器运行吗?

可以不需要,内置了Tomcat等容器。

你如何理解 Spring Boot 中的 Starters?

Starters可以理解为启动器,它包含了一系列可以集成到应用里面的依赖包,你可以一站式集成 Spring 及其他技术,而不需要到处找示例代码和依赖包。如你想使用 Spring JPA 访问数据库,只要加入 spring-boot-starter-data-jpa 启动器依赖就能使用了。

Starters包含了许多项目中需要用到的依赖,它们能快速持续的运行,都是一系列得到支持的管理传递性依赖。具体请看这篇文章《Spring Boot Starters启动器》。

Spring Boot 自动配置原理是什么?

注解 @EnableAutoConfiguration, @Configuration, @ConditionalOnClass 就是自动配置的核心,首先它得是一个配置文件,其次根据类路径下是否有这个类去自动配置。

具体看这篇文章《Spring Boot自动配置原理、实战》。

Spring Cloud

Spring Cloud面试题

springcloud如何实现服务的注册和发现

服务在发布时 指定对应的服务名(服务名包括了IP地址和端口) 将服务注册到注册中心(eureka或者zookeeper)。这一过程是springcloud自动实现 只需要在main方法添加@EnableDisscoveryClient 同一个服务修改端口就可以启动多个实例

调用方法:传递服务名称通过注册中心获取所有的可用实例 通过负载均衡策略调用(ribbon和feign)对应的服务

Feign Client的原理

Feign Client的原理
1. 基于面向接口的动态代理方式生成实现类
2. 根据接口类的注解声明规则,解析出底层MethodHandler
3. 基于RequestTemplate,动态生成Request
4. Encoder Request请求
5. 拦截器负责对请求和返回进行拦截处理、日志记录
7. 基于重试器发送http请求,可基于不同的框架处理

MyBatis

MyBatis面试题

# 和 $的区别?

#{} 是占位符,${} 是拼接符

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

答:第一种是使用<resultMap>标签,逐一定义列名和对象属性名之间的映射关系。第二种是使用sql列的别名功能,将列别名书写为对象属性名

有了列名与属性名的映射关系后,Mybatis通过反射创建对象,同时使用反射给对象的属性逐一赋值并返回,那些找不到映射关系的属性,是无法完成赋值的。

MyBatis中如何获取参数?

方法1:通过@Param注解获取参数

  1. public User selectUser(@Param("userName") String name, @Param("deptId") int deptId);
  2. <select id="selectUser" resultMap="UserResultMap">
  3. select * from user where user_name = #{userName} and dept_id = #{deptId}
  4. </select>

#{}里面的名称对应的是注解@Param括号里面修饰的名称。

这种方法在参数不多的情况还是比较直观的,推荐使用。

方法2:通过Map获取参数

  1. public User selectUser(Map<String, Object> params);
  2. <select id="selectUser" parameterType="java.util.Map" resultMap="UserResultMap">
  3. select * from user where user_name = #{userName} and dept_id = #{deptId}
  4. </select>

#{}里面的名称对应的是Map里面的key名称。

这种方法适合传递多个参数,且参数易变能灵活传递的情况。

方法3:通过Java Bean获取参数

  1. public User selectUser(Map<String, Object> params);
  2. <select id="selectUser" parameterType="com.test.User" resultMap="UserResultMap">
  3. select * from user where user_name = #{userName} and dept_id = #{deptId}
  4. </select>

#{}里面的名称对应的是User类里面的成员属性。

这种方法很直观,但需要建一个实体类,扩展不容易,需要加属性,看情况使用。

SpringMVC

SpringMVC面试题

SpringMVC的流程?

  1. 用户发送请求至前端控制器DispatcherServlet;
  2. DispatcherServlet收到请求后,调用HandlerMapping处理器映射器,请求获取Handle;
  3. 处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet;
  4. DispatcherServlet通过HandlerAdapter处理器适配器调用处理器;
  5. 执行处理器(Handler,也叫后端控制器);
  6. Handler执行完成返回ModelAndView;
  7. HandlerAdapter将Handler执行结果ModelAndView返回给DispatcherServlet;
  8. DispatcherServlet将ModelAndView传给ViewResolver视图解析器进行解析;
  9. ViewResolver解析后返回具体View;
  10. DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中)
  11. DispatcherServlet响应用户。
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注