关于java:Java面试问题汇总SSM

37次阅读

共计 11154 个字符,预计需要花费 28 分钟才能阅读完成。

Maven

1.dependency

  • groupId

    定义附属的理论我的项目

  • artifactId

    定义我的项目中的一个模块

  • version

    定义依赖或我的项目的版本

2.maven 依赖 生命周期 scope

  • compile

    默认值,示意以后依赖参加我的项目的编译、测试、运行阶段,属于强依赖,打包时,会打到包里去

  • test

    仅仅参加测试,包含测试用例的编译和执行,比方 Junit

  • runtime

    依赖仅参加运行周期中的应用,个别这种类库都是接口与实现相拆散的类库,比方 JDBC,在编译时依赖相干的接口,在具体运行时,须要 mysql 等驱动程序

  • provided

    该依赖在打包过程中,不须要打进去,这个由运行环境提供,比方 tomcat 或者根底类库等

  • system

    应用上与 provided 雷同,不同之处在于该依赖不从 maven 仓库中提取,而是从本地文件系统中提取,其会参加 systemPath 的属性进行提取依赖

  • import

    只能在 dependencyManagement 中应用,能解决 Maven 单继承问题,import 依赖关系实际上并不参加限度依赖关系的传递性

3. 本地 jar 包装置到 Maven 仓库

mvn install:install-file
-Dfile= 本地 jar 包门路
-DgroupId=jar 包的 groupId
-DartifactId=jar 包 artifactId
-Dversion=jar 包版本
-Dpackaging=jar

Mybatis

1.MyBatis 编程步骤

  1. 创立 SqlSessionFactory 对象。
  2. 通过 SqlSessionFactory 获取 SqlSession 对象。
  3. 通过 SqlSession 取得 Mapper 代理对象。
  4. 通过 Mapper 代理对象,执行数据库操作。
  5. 执行胜利,则应用 SqlSession 提交事务。
  6. 执行失败,则应用 SqlSession 回滚事务。
  7. 最终,敞开会话。

2.MyBatis 如何执行批量插入

  1. 应用 Sql 拼接,有语句大小限度

    INSERT INTO [表名]([列名],[列名]) 
    VALUES
    ([列值],[列值])),
    ([列值],[列值])),
    ([列值],[列值]));
  2. 应用 Mybatis 的批量插入方式
private static SqlSessionFactory sqlSessionFactory;

@Test
public void testBatch() {
    // 创立要插入的用户的名字的数组
    List<String> names = new ArrayList<>();
    names.add("张三");
    names.add("李四");
    names.add("李二");
    names.add("王五");

    // 取得执行器类型为 Batch 的 SqlSession 对象,并且 autoCommit = false,禁止事务主动提交
    try (SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH, false)) {
        // 取得 Mapper 对象
        UserMapper mapper = session.getMapper(UserMapper.class);
        // 循环插入
        for (String name : names) {mapper.insertUser(name);
        }
        // 提交批量操作
        session.commit();}
}
  1. 应用循环一条条插入

3.Mybatis 的 XML Mapper 文件中,不同的 XML 映射文件,id 是否能够反复?

不同的 XML Mapper 文件,如果配置了 "namespace",那么 id 能够反复;如果没有配置 "namespace",那么 id 不能反复。毕竟"namespace" 不是必须的,只是最佳实际而已。

起因就是,namespace + id 是作为 Map<String, MappedStatement> 的 key 应用的。如果没有 "namespace",就剩下 id,那么 id 反复会导致数据相互笼罩。如果有了 "namespace",天然 id 就能够反复,"namespace"不同,namespace + id 天然也就不同。

4. 简述 Mybatis 的 XML 映射文件和 Mybatis 外部数据结构之间的映射关系

Mybatis 将所有 XML 配置信息都封装到 All-In-One 重量级对象 Configuration 外部。

在 XML Mapper 文件中:

  • <parameterMap> 标签,会被解析为 ParameterMap 对象,其每个子元素会被解析为 ParameterMapping 对象。
  • <resultMap> 标签,会被解析为 ResultMap 对象,其每个子元素会被解析为 ResultMapping 对象。
  • 每一个 <select><insert><update><delete> 标签,均会被解析为一个 MappedStatement 对象,标签内的 SQL 会被解析为一个 BoundSql 对象。

5. 通常一个 XML 映射文件,都会写一个 Mapper 接口与之对应。请问,这个 Mapper 接口的工作原理是什么?Mapper 接口里的办法,参数不同时,办法能重载吗?

Mapper 接口,对应的关系如下:

  • 接口的全限名,就是映射文件中的 "namespace" 的值。
  • 接口的办法名,就是映射文件中 MappedStatement 的 "id" 值。
  • 接口办法内的参数,就是传递给 SQL 的参数。

Mapper 接口是没有实现类的,当调用接口办法时,接口全限名 + 办法名拼接字符串作为 key 值,可惟一定位一个对应的 MappedStatement。举例:com.mybatis3.mappers.StudentDao.findStudentById,能够惟一找到 "namespace"com.mybatis3.mappers.StudentDao 上面 "id"findStudentById 的 MappedStatement。

总结来说,在 Mybatis 中,每一个 <select /><insert /><update /><delete /> 标签,都会被解析为一个 MappedStatement 对象。

另外,Mapper 接口的实现类,通过 MyBatis 应用 JDK Proxy 主动生成其代理对象 Proxy,而代理对象 Proxy 会拦挡接口办法,从而“调用”对应的 MappedStatement 办法,最终执行 SQL,返回执行后果。整体流程如下图:

其中,SqlSession 在调用 Executor 之前,会取得对应的 MappedStatement 办法。例如:DefaultSqlSession#select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) 办法,代码如下:

// DefaultSqlSession.java

@Override
public void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
    try {
        // 取得 MappedStatement 对象
        MappedStatement ms = configuration.getMappedStatement(statement);
        // 执行查问
        executor.query(ms, wrapCollection(parameter), rowBounds, handler);
    } catch (Exception e) {throw ExceptionFactory.wrapException("Error querying database.  Cause:" + e, e);
    } finally {ErrorContext.instance().reset();}
}

Mapper 接口里的办法,是不能重载的,因为是 全限名 + 办法名 的保留和寻找策略

Spring

1.BeanFactory 与 ApplicationContext 是干什么的,两者的区别

BeanFactory、ApplicationContext 都代表容器,BeanFactory 是一个 根底接口 ,实现了容器根底的性能,ApplicationContext 是 器的高级状态,减少了许多了个性,顶级父类是 BeanFactory。

跟 FactoryBean 的区别是:

FactoryBean 是一个 Bean, 用于 生产润饰其余的 Bean 实例,典型利用是AOP 代理类,应用 ’&’ 获取 FactoryBean 自身

BeanFactory 是一个工厂,是 容器的顶层接口

2.BeanPostProcessor 的实现

Bean 的 后置处理器 ,是一个 监听器 ,能够 监听容器触发的事件 。将它 向 IOC 容器注册后 ,容器中 治理的 Bean 具备了接管 IOC 容器事件回调的能力 。BeanPostProcessor 是一个 接口类 ,有 两个接口办法 ,postProcessBeforeInitialization 提供 Bean 初始化前的回调入口 ;postProcessAfterInitialization 提供 Bean 初始化的回调入口AbstractAutowireCapableBeanFactory#initializeBean, 这个类能够对我的项目中的 Bean 进行润饰,所有 Bean 都会调用该实现。

3.BeanDefinition 的实现

BeanDefinition 形象了对 Bean 的定义,其是容器 实现依赖反转性能的外围数据结构

4.Spring IOC 容器的实现

Spring 提供了各种各样的容器,有 DefaultListableBeanFactory、FileSystemXmlApplicationContext 等,这些容器都是基于 BeanFactory,BeanFactory 实现了容器的根底性能,包含 containsBean 可能判断容器是否含有指定名称的 Bean,getBean 获取指定名称参数的 Bean 等。

Spring 通过 refresh() 办法对容器进行初始化和资源的载入

首先 通过 ResourceLoader 的 Resource 接口定位到存储 Bean 信息的门路

第二个过程是 BeanDefinition 载入,把定义好的Bean 示意成 IOC 容器的外部数据结构 BeanDefinition 通过定义 BeanDefinition 来治理利用的各种对象及依赖关系,其是容器实现依赖反转性能的外围数据结构

第三个过程是 BeanDefinition注册 ,容器解析失去 BeanDefinition 后,须要在容器中注册,这 由 IOC 实现 BeanDefinitionRegistry 接口来实现 ,注册过程是 IOC 容器 外部保护了一个 ConcurrentHasmap 来保留失去的 BeanDefinition。如果某些 Bean 设置了 lazyinit 属性,Bean 的依赖注入会在这个过程事后实现,而不须要等到第一次应用 Bean 的时候才触发。

5.Spring DI(依赖注入)的实现

Spring 的依赖注入产生在以下两种状况:

  1. 用户第一次调用 getBean() 办法
  2. bean 配置了 lazy-init=false,容器会在 解析注册 Bean 定义的时候进行预实例化,触发依赖注入

getBean()办法定义在 BeanFactory 接口中,具体实现在子类 AbstractBeanFactory 中,过程如下:

  1. getBean()办法最终是 委托给 doGetBean 办法来实例化 Bean,doGetBean 办法会 先从缓存中找 是否有创立过,没有再从父工厂中 去查找
  2. 如果父工厂中 没有找到 ,会 依据 Bean 定义的模式来创立 Bean单例模式的 Bean会先从缓存中查找,确保只创立一次 原型模式的 Bean 每次都会创立 ,其余模式依据配置的不同生命周期来抉择适合的办法创立。创立的具体方法通过匿名类中getObject, 并 委托给 createBean 来实现 bean 的实例化
  3. createBean 中,先对 Bean 进行一些筹备工作,而后会 利用配置的前后处理器 ,如果创立 胜利就间接返回 该代理 Bean
  4. 没有创立代理 Bean 的话,会 创立指定的 Bean 实例 委托给 doCreateBean 实现 ,该过程会通过 提前实例化依赖 Bean,并 写入缓存来解决 Bean 的循环依赖
  5. 通过 populateBean 注入 Bean 属性,并 调用 init-method 初始化办法
  6. 注册实例化的 Bean

6.Spring 如何解决循环依赖问题

比方 A 依赖 B, B 依赖 A.

创立 A 的时候,会把 A 对应的 ObjectFactory 放入缓存中,当注入的时候发现须要 B, 就会去调用 B 对象,B 对象会先从 singletonObjects 查找,没有再从 earlySingletonObjects 找,还没有就会调用 singletonFactory 创建对象 B,B 对象也是先从 singletonObjects,earlySingletonObjects,singletonFactories 三个缓存中搜寻,只有找到就返回,相干办法AbstractBeanFactory.doGetBean()

7.Spring Bean 生命周期

  1. Bean 实例的 创立
  2. 为 Bean 实例 设置属性
  3. 调用 Bean 的 初始化办法
  4. 利用能够 通过 IOC 容器应用 Bean
  5. 容器敞开时 调用 Bean 的销毁办法

8.Spring Bean 的作用域,默认是哪个?

Singleton: 单例模式,IOC 容器中 只会存在一个共享的 Bean 实例 ,是 Spring 的 默认模式

prototype: 原型模式,每次从 IOC 容器获取 Bean 的时候,都会创立一个新的 Bean 实例

request: 每次申请都生成一个实例

session: 在一次申请会话中,容器返回该 Bean 的同一实例,不同的 Session 申请不同的实例,实例仅在该 Session 内无效,申请完结,则实例销毁;

globalsession: 全局的 session 中,容器返回该 Bean 的同一个实例,仅在 portlet context 无效

9.AOP 两种代理形式

AOP 面向切面编程,能够通过 预编译和运行时动静代理 ,实现在 不批改源代码的状况下给程序动静增加性能

程序入口是:AbstractAutowireCapableBeanFactory -> doCreateBean -> initializeBean -> applyBeanPostProcessorsAfterInitialization

默认策略是 如果指标类是接口,则应用 JDK 动静代理技术,否则应用 Cglib 来生成代理

  1. JDK 动静代理

    次要波及 java.lang.reflect 中的两个类,Proxy 和 InvocationHandler

    InvocationHandler 是一个接口,通过实现该接口来定义横切逻辑 ,并通过 反射机制调用指标类的代码,动静将横切逻辑和业务逻辑编辑在一起。只能为实现接口的类创立代理。

  2. Cglib 代理

    是一个弱小的高性能,高质量的 代码生成类库 ,能够在 运行期扩大 Java 类与实现 Java 接口 ,Cglib 封装了 asm, 能够在运行期动静生成新的 class。能够是一般类,也能够是实现接口的类

10.Spring AOP 实现原理

通过 JDK 代理,和 CGLIB 代理两种形式生成动静代理,结构不同的回调办法来对拦截器链的调用 ,比方 JdkDynamicAopProxy 的 invoke 办法,Cglib2AopProxy 中的 DynamicAdvisedInterceptor 的 intercept 办法,首先获取配置的拦截器链,通过 ReflectiveMethodInvocation 的 proceed 办法实现对拦截器链的调用, 首先须要 依据配置来对拦截器进行匹配,匹配胜利后,拦截器发挥作用,在对拦截器调用实现后,再对指标对象的办法调用,这样一个一般的 Java 对象的性能就失去了加强

11. 哪些办法不能被 AOP 加强

  1. 基于 JDK 代理,除 public 外的其余所有办法,包含 public static 也不能被加强
  2. 基于 CGLIB 代理,因为其通过生成指标类子类的形式来加强,因而不能被子类继承的办法都不能被加强,private、static、final 办法

12.AOP 切点函数

类别 函数 入参 阐明
办法切入点函数 execution() 办法匹配模式串 满足某一匹配模式的所有指标类办法连接点。<br/> 如 execution(* greetTo(..)) 示意所有指标类中的 greetTo()办法
@annotation() 办法注解类名 标注了特定注解的指标类办法连接点。<br/> 如 @annotation(com.smart.anno.NeedTest)示意任何标注了 @NeedTest 注解的指标类办法
办法入参切入点函数 args() 类名 通过判断指标类办法运行时入参对象的类型定义指定连接点。<br/> 如 args(com.smart.Waiter)示意所有有且仅有一个按类型匹配于 Waiter 入参的办法
@args() 类型注解类名 通过判断指标类办法运行时入参对象的类是否标注特定注解来指定连接点。<br/> 如 @args(com.smart.Monitorable)示意任何这样的一个指标办法:它有一个入参且 入参对象的类 标注 @Monitorable 注解
指标类切点函数 within() 类名匹配串 示意特定域下的所有连接点。
如 within(com.smart.service.*) 示意 com.smart.service 包中的所有连接点,即包中所有类的所有办法;
而 within(com.smart.service.*Service)示意在 com.smart.service 包中所有以 Service 结尾的类的所有连接点
target() 类名 如果指标类按类型匹配于指定类,则指标类的所有连接点匹配这个切点
如通过 target(com.smart.Waiter),Waiter 及 Waiter 实现类 NaiveWaiter 中的所有连接点都匹配该切点
@within() 类型注解类名 如果指标类型按类型匹配于某个类 A, 且类 A 标注了特定注解,则指标类的所有连接点匹配该切点
如 @within(com.smart.Monitorable) 如果 Waiter 类标注了 @Monitorable 注解,则 Waiter 的所有连接点都匹配该切点,说是这个注解也会匹配 Waiter 的子类,但试了后并没有用,Spring 5.1
@target 类型注解类名 如果指标类标注了特定注解,则指标类的所有连接点都匹配该切点。
如 @target(com.smart.Monitorable), 如果 NaiveWaiter 标注了 @Monitorable, 则 NaiveWaiter 的所有连接点都匹配这个切点
代理类切点函数 this() 类名 代理类按类型匹配于指定类,则被代理的指标类的所有连接点都匹配该切点。
如 this(com.smart.Seller) 匹配任何运行期对象为 Seller 类型的类

13. 六种加强类型

  1. @Before 前置加强,相当于 BeforeAdvice
  2. @AfterReturning 后置加强,相当于 AfterReturningAdvice
  3. @Around 盘绕加强,相当于 MethodInterceptor
  4. @AfterThrowing 抛出加强,相当于 ThrowsAdvice
  5. @AfterFinal 加强,不论抛出异样还是失常退出,都会执行,没有对应的加强接口,个别用于开释资源
  6. @DeclareParents 引介加强,相当于 IntroductionInterceptor

14.Spring MVC 运行流程

  1. 客户端申请到 DispatcherServlet
  2. DispatcherServlet 依据申请地址查问映射处理器 HandleMapping,获取 Handler
  3. 申请 HandlerAdatper 执行 Handler
  4. 执行相应的 Controller 办法,执行结束返回 ModelAndView
  5. 通过 ViewResolver 解析视图,返回 View
  6. 渲染视图,将 Model 数据转换为 Response 响应
  7. 将后果返回给客户端

2,3 两步都在 DispatcherServlet -> doDispatch 中进行解决

15.Spring MVC 启动流程

  1. 在 Tomcat 启动的时候,ServletContext 会依据 web.xml 加载 ContextLoaderListener,继而通过 ContextLoaderListener 载入 IOC 容器,具体过程有 ContextLoader 实现,这个 IOC 容器是在 Web 环境下应用的 WebApplicationContext, 这个容器在前面的 DispatcherServlet 中作为双亲根上下文来应用
  2. IOC 容器加载实现后,开始加载 DIspatcherServlet,这是 Spring MVC 的外围,由 HttpServletBean -> initServeltBean 启动(HttpServletBean 是 DispatcherServlet 的父类,HttpServletBean 继承了 HttpServlet),最终调用DispatcherServlet -> initStrategies 办法对 HandlerMapping、ViewResolver 等进行初始化,至此,DispatcherServelt 就初始化实现了,它持有一个第一步实现的上下文作为根上下文,以本人的 Servlet 名称命名的 IOC 容器,这个容器是一个 WebApplicationContext 对象。

16.Spring 事务实现形式、事务的流传机制、默认的事务类别·

  1. 事务实现形式

    • 申明式,在 xml 文件中通过 tx:advice 来配置事务
    • 注解式,在 xml 文件中定一个事务管理对象(DataSourceTransactionManager),而后退出 \<tx:annotation-driven/>, 这样就能够应用 @Transactional 注解配置事务
  2. 事务的流传机制

    一共 7 种事务流传行为,相干 code: AbstractPlatformTransactionManager -> getTransaction

    • PROPAGATION_REQUIRED

      如果以后没有事务,则新建一个事务;如果曾经存在一个事务,则退出到这个事务中,这也是默认事务类别

    • PROPAGATION_SUPPORTS

      反对以后事务。如果以后没有事务,则以非事务形式执行

    • PROPAGATION_MANDATORY

      应用以后事务。如果以后没有事务,则抛出异样

    • PROPAGATION_REQUIRES_NEW

      新建事务。如果以后存在事务,则把以后事务挂起

    • PROPAGATION_NOT_SUPPORTED

      以非事务形式执行操作。如果以后存在事务,则把以后事务挂起

    • PROPAGATION_NEVER

      以非事务形式执行。如果以后存在事务,则抛出异样

    • PROPAGATION_NESTED

      如果以后存在事务,则在嵌套事务内执行;如果以后没有事务,则执行与 PROPAGATION_REQUIRED 相似的操作

17.Spring 事务模版

TransactionTemplate 事务模版是 对原始事务管理形式的封装,原始事务管理是基于TransactionDefinitionPlatformTransactionManagerTransactionStatus 的编程式事务

事务模版次要 通过 execute(TransactionCallback<T> action)来执行事务,TransactionCallback 有两种形式一种是有返回值 TransactionCallback,一种是没有返回值 TransactionCallbackWithoutResult。

18.Spring 事务底层原理

  1. 事务的筹备

    在申明式事务处理中,须要 Ioc 容器配置 TransactionProxyFactoryBean, 其父类 AbstractSingletonProxyFactoryBean 实现了 InitializingBeean 接口, 因而在初始化过程中会调用 afterPropertiesSet 办法,这个办法实例化了 ProxyFactory, 并为其设置了告诉,指标对象后,最终返回 Proxy 代理对象,对象建设起来后,在调用其代理办法的时候,会调用相应的 TransactionInterceptor 拦截器,在这个调用中,会依据 TransactionAttribute 配置的事务属性进行配置,为事务处理做好筹备

  2. 事务拦截器实现

    通过 TransactionProxyFactoryBean 的 AOP 包装后,此时如果对指标对象进行办法调用,实际上起作用的是一个 Proxy 代理对象,拦截器会拦挡其中的事务处理,在调用 Proxy 对象的代理办法时会触发 invoke 回调, 其中会依据事务属性配置决定具体用哪一个 PlatformTransactionManager 来实现事务操作

19. 什么是 Spring Boot?

Spring Boot 是 Spring 的子项目,正如其名字,提供 Spring 的疏导 (Boot ) 的性能。

通过 Spring Boot,咱们开发者能够 疾速配置 Spring 我的项目,引入各种 Spring MVC、Spring Transaction、Spring AOP、MyBatis 等等框架 ,而 无需一直反复编写沉重的 Spring 配置,升高了 Spring 的应用老本。

20.Spring Boot 启动流程

  1. 启动类外面调用 SpringApplication.run 办法
  2. 在 run 办法中,首先结构 SpringApplication 对象,而后再调用 run 办法
  3. 在结构 SpringApplication 对象中,做了如下工作

    • 将 sources 放入 primarySources 变量中
    • 判断 webApplication 是什么类型的
    • 设置 ApplicationContextInitializer,ApplicationListener,通过加载 META-INF/spring.factories 中配置的类
    • 找到 main 办法找到启动主类
  4. run 办法中,做的工作

    • StopWatch 次要是监控启动过程,统计启动工夫,检测利用是否曾经启动或者进行。
    • 加载 SpringApplicationRunListener(也是通过 META-INF/spring.factories), 默认加载的是 EventPublishingRunListener
    • 调用 RunListener.starting()办法。
    • 依据 args 创立利用参数解析器 ApplicationArguments;
    • 筹备环境变量:获取环境变量 environment,将利用参数放入到环境变量持有对象中,监听器监听环境变量对象的变动(listener.environmentPrepared)
    • 打印 Banner 信息(SpringBootBanner)
    • 创立 SpringBoot 的利用上下文(AnnotationConfigEmbeddedWebApplicationContext)
    • prepareContext 上下文之前的筹备
    • refreshContext 刷新上下文
    • afterRefresh(ApplicationRunner,CommandLineRunner 接口实现类的启动)
    • 返回上下文对象

21. 什么是 Spring Boot 主动配置?

  1. Spring Boot 在启动时扫描我的项目所依赖的 jar 包,寻找蕴含spring.factories 文件的 jar 包。
  2. 依据 spring.factories 配置加载 AutoConfigure 类。
  3. 依据 @Conditional 等条件注解的条件,进行主动配置并将 Bean 注入 Spring IoC 中。

正文完
 0