面试题-javaEE篇

面试题-javaEE篇

JAVAlijiangchao2022-05-20 20:17:16170A+A-

JavaEE框架篇

一、SpringMVC

1.1 SpringMVC执行原理1、 用户发送请求至前端控制器 DispatcherServlet。2、 DispatcherServlet 收到请求调用 HandlerMapping 处理器映射器。3、 处理器映射器找到具体的处理器(可以根据 xml 配置、注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给 DispatcherServlet。4、 DispatcherServlet 调用 HandlerAdapter 处理器适配器。5、 HandlerAdapter 经过适配调用具体的处理器(Controller,也叫后端控制器)。6、 Controller 执行完成返回 ModelAndView。7、 HandlerAdapter 将 controller 执行结果 ModelAndView 返回给DispatcherServlet。8、 DispatcherServlet 将 ModelAndView 传给 ViewReslover 视图解析器。9、 ViewReslover 解析后返回具体 View。10、DispatcherServlet 根据 View 进行渲染视图(即将模型数据填充至视图中)。11、 DispatcherServlet 响应用户。

1.2 springMVC 的常用注解

@requestMapping: 请求路径映射处理方法@responseBody:响应数据为 json 数据@requestBody:接收 json 数据,反序列化为 java 对象@pathVariable:接收 restful 风格的参数,参数在 url 路径中,需要通过该注解获取参数@ModelAttribute:将数据保存到 request 域中@RequestParam:接收参数

1.3 springMVC 是线程安全的么

1、SpringMVC 是线程安全的,因为 springMVC 是基于方法拦截处理请求,参数的变量全部是局部变量,并且 spring容器中的 bean 也是单例模式,所以一般情况下不会产生线程安全问题。2、如果非得要在 springMVC 中定义成员变量,设置为只读状态或者无状态也不会有线程安全问题。3、如若非得在 controller 中定义带状态的对象,并且多线程可以操作,则两种方式解决线程安全问题: 1、在 Controller 中使用 ThreadLocal 变量,对于 springMVC 中的数据共享,是通过 ThreadLocal 实现,ThreadLocal 相当于一个 map 集合,只不过 key 实现线程对象,value 是共享数据,针对共享数据进行线程隔离,同一个变量,不同的线程访问,会得到不同的结果,互相不干扰。 2、在 spring 配置文件 Controller 中声明 scope="prototype",每次都创建新的 controller。

1.4 过滤器和拦截器的区别

执行顺序:过滤前 - 拦截前 - Action 处理 - 拦截后 - 过滤后。1、拦截器是基于 java 的反射机制的,而过滤器是基于函数回调。2、拦截器不依赖与 servlet 容器,过滤器依赖与 servlet 容器。3、拦截器只能对处理器(Controller、Action)请求起作用,而过滤器则可以对几乎所有的请求起作用。4、拦截器可以访问上下文对象,而过滤器不能访问。5、在 Servlet 的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次

二、Spring

2.1 Spring 框架的理解

Spring 是一个轻量级的 IoC 和 AOP 容器框架。是为 Java 应用程序提供基础性服务的一套框架,目的是用于简化企业应用程序的开发,它使得开发者只需要关心业务需求。常见的配置方式有三种:基于 XML 的配置、基于注解的配置、基于 Java 的配置。主要由以下几个模块组成:Spring Core:核心类库,提供 IOC 服务;Spring Context:提供框架式的 Bean 访问方式,以及企业级功能(JNDI、定时任务等);Spring AOP:AOP 服务;Spring DAO:对 JDBC 的抽象,简化了数据访问异常的处理;Spring ORM:对现有的 ORM 框架的支持;Spring Web:提供了基本的面向 Web 的综合特性,例如多方文件上传;Spring MVC:提供面向 Web 应用的 Model-View-Controller 实现。

2.2 spring 的优点

(1)spring 属于低侵入式设计,代码的污染极低;(2)spring 的 DI 机制将对象之间的依赖关系交由框架处理,减低组件的耦合性;(3)Spring 提供了 AOP 技术,支持将一些通用任务,如安全、事务、日志、权限等进行集中式管理,从而提供更好的复用。(4)spring 对于主流的应用框架提供了集成支持。

2.3 Spring 框架中都用到了哪些设计模式

(1)工厂模式:BeanFactory 就是简单工厂模式的体现,用来创建对象的实例;(2)单例模式:Bean 默认为单例模式。(3)代理模式:Spring 的 AOP 功能用到了 JDK 的动态代理和 CGLIB 字节码生成技术;(4)模板方法:用来解决代码重复的问题。比如. RestTemplate, JmsTemplate,JpaTemplate。(5)观察者模式:定义对象键一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知被制动更新,如 Spring 中 listener 的实现.

2.4 spring 中 bean 的作用域

scope 配置项有 5 个属性,用于描述不同的作用域。① singleton(单例)使用该属性定义 Bean 时,IOC 容器仅创建一个 Bean 实例,IOC 容器每次返回的是同一个 Bean 实例。② prototype(多例)使用该属性定义 Bean 时,IOC 容器可以创建多个 Bean 实例,每次返回的都是一个新的实例。③ request该属性仅对 HTTP 请求产生作用,使用该属性定义 Bean 时,每次 HTTP 请求都会创建一个新的 Bean,适用于WebApplicationContext 环境。④ session该属性仅用于 HTTP Session,同一个 Session 共享一个 Bean 实例。不同Session 使用不同的实例。⑤ global-session该属性仅用于 HTTP Session,同 session 作用域不同的是,所有的 Session

2.5. spring 的 IOC 原理

IOC 就是控制反转,原来我们需要创建对象的,必须自己 new,但是现在有了spring 容器,我们不需要再自己 new了,有两个好处,解耦,因为对象自己 new 完之后,无法更改,如果依赖对象发生异常,则会对我们自己的类造成影响。springIOC,用户只需要进行配置,容器会在容器中自动实例化依赖对象,并且是单例模式,直接通过@autowired直接注入即可。IOC 主要是通过反射实现,底层原理大概是这样的:1、项目启动,加载 web.xml;2、在 web.xml 根据 context-param 通过 contextListener 加载 spring 上下文,加载 spring 配置文件;3、我猜,spring 可能通过 dom4j 解析 xml 配置文件;4、获取 bean 标签,一旦发现 bean 标签,则读取 class 属性;5、通过反射,Class.forName,获取该类的 class 字节码对象;6、调用通过 Constructor 的 newInstance()实例化对象;7、说 IOC 就离不开 DI,所谓 DI 是依赖注入,spring 的依赖注入有两种方式:构造注入和 setter 注入;8、所谓构造注入,就是读取标签的,通过 class 字节码文件对象,获取构造参数;9、通过 Constructor,直接构造对象,并对依赖对象进行初始化;10、setter 注入,就是通过反射的;11、通过 Field,设置依赖对象的属性值,dom4j 读取 property 标签的 name和 value 属性值,根据 name 获取 Field 成员,一般来说会通过 setAccessible 暴力破解,然后通过 set 方法,指定 field 的对象和属性值,完成 setter 注入。总结:以上就是对于 spring 的 IOC 和 DI 的理解,大概就是通过反射和 dom4j完成控制反转和依赖注入。Spring 的 IOC 有三种注入方式 :构造器注入、setter 方法注入、根据注解注

2.6 构造注入和 Setter 注入的区别

如果发现配置了对象的构造注入,那么 Spring 会在调用构造函数前把构造函数需要的依赖对象都实例化好,然后再把这些实例化后的对象作为参数去调用构造函数。在使用构造函数和 set 方法依赖注入时,Spring 处理对象和对象依赖的对象的顺序时不一样的。一般把一个 Bean设计为构造函数接收依赖对象时,其实是表达了这样一种关系:他们(依赖对象)不存在时我也不存在,即“没有他们就没有我”。通过构造函数的注入方式其实表达了 2 个对象间的一种强的聚合关系:组合关系。就比如一辆车如果没有轮子、引擎等部件那么车也就不存在了。而且车是由若干重 要部件组成的,在这些部件没有的情况下车也不可能存在。这里车和他的重要部件就时组合的关系。如果你的应用中有这样类似的场景那么你应该使用“构造函数注 入”的方式管理他们的关系。“构造函数注入”可以保证合作者先创建,在后在创建自己。通过 set 方法注入的方式表达了 2 个对象间较弱的依赖关系:聚合关系。就像一辆车,如果没有车内音像车也时可以工作的。当你不要求合作者于自己被创建 时,“set 方法注入”注入比较合适。虽然在理论上“构造函数注入”和“set 方法注入”代表 2 种不同的依赖强度,但是在 spring 中,spring 并不会把无效的合作者传递给一个 bean。总结:在 spring 中,“构造函数注入”和 “set 方法注入”唯一的区别在于 2 种方式创建合作者的顺序不同。使用构造函数依赖注入时,Spring 保证所有一个对象所有依赖的对象先实例化后,才实例化这个对象。(没有他们就没有我原则)使用 set 方法依赖注入时,Spring 首先实例化对象,然后才实例化所有依赖的对象。

2.7 spring 的 AOP 原理

AOP,一般称为面向切面,作为面向对象的一种补充,用于将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块,这个模块被命名为“切面”(Aspect),减少系统中的重复代码,降低了模块间的耦合度,同时提高了系统的可维护性。可用于权限认证、日志、事务处理。AOP 实现的关键在于 代理模式,AOP 代理主要是通过反射动态代理实现。(2)Spring AOP 使用的动态代理,所谓的动态代理就是说 AOP 框架不会去修改字节码,而是每次运行时在内存中临时为方法生成一个 AOP 对象,这个 AOP 对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法。Spring AOP 中的动态代理主要有两种方式,JDK 动态代理和 CGLIB 动态代理:①JDK 动态代理只提供接口的代理,不支持类的代理。核心 InvocationHandler接口和 Proxy 类,InvocationHandler 通过 invoke()方法反射来调用目标类中的代码,动态地将横切逻辑和业务编织在一起;接着,Proxy 利用 InvocationHandler 动态创建一个符合某一接口的的实例, 生成目标类的代理对象。InvocationHandler 的 invoke(Object proxy,Method method,Object[]args):proxy 是最终生成的代理实例; method是被代理目标实例的某个具体方法; args 是被代理目标实例某个方法的具体入参,在方法反射调用时使用。②如果代理类没有实现 InvocationHandler 接口,那么 Spring AOP 会选择使用CGLIB 来动态代理目标类。CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成指定类的一个子类对象,并覆盖其中特定方法并添加增强代码,从而实现 AOP。CGLIB 是通过继承的方式做的动态代理,因此如果某个类被标记为 final,那么它是无法使用 CGLIB 做动态代理的

2.8 spring 中 AOP 的使用场景

AOP 用来封装横切关注点,具体可以在下面的场景中使用:Authentication 权限Caching 缓存Context passing 内容传递Error handling 错误处理Lazy loading 懒加载Debugging调试logging, tracing, profiling and monitoring 记录跟踪 优化 校准Performance optimization 性能优化Persistence持久化Resource pooling 资源池Synchronization 同步Transactions 事务

2.9 Spring 中动态代理实现方式

JDK 动态代理只能为接口创建动态代理实例,而不能对类创建动态代理。需要获得被目标类的接口信息(应用 Java的反射技术),生成一个实现了代理接口的动态代理类(字节码),再通过反射机制获得动态代理类的构造函数,利用构造函数生成动态代理类的实例对象,在调用具体方法前调用invocationHandler 中的 excute()方法来处理,在如果想要对被代理类进行增强可以在执行 method.invoke()方法前和后做代码处理,之前处理叫前切,之后处理叫后切,同时还可通过 method 获取信息,如访问修饰符、全类名、方法名、返回值类型和参数列表,作为是否对方法进行处理的判断条件,也就是我们说的切点;实现 JDK 动态代理,只需要:1、定义动态代理处理类,实现 InvocationHandler 接口,通过构造参数接收被代理类对象实例;2、重写 excute()方法,在方法中,通过反射执行被代理被对象的方法method.invoke();3、method.invoke()方法需要两个参数,一个是被代理类对象引用,一个是方法参数;4、在方法执行前可以判断切点条件,在方法执行后,可以做资源处理;5、在生成代理对象前,需要获取被代理类的 classloader 类加载器和接口集,及动态代理类对象实例;6、代码:Proxy.newProxyInstance( --生成动态代理对象obj.getClass().getClassLoader(),--获取被代理类对象的类加载器obj.getClass.getInterfaces(), --获取被代理类对象的接口handler--实现了 InvocationHandler 的动态代理处理器,用于生成动态代理对象 );实现原理:在被代理类执行方法前,进行拦截,有和代理对象实现了相同接口的,被代理对象执行方法,并进行扩展处理

2.10 JDK 动态代理和 CGLIB 动态代理的区别

一、概括来说 JDK 动态代理只能对实现了接口的类生成代理,而不能针对类 CGLIB 是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法(继 承) 二、Spring 在选择用 JDK 还是 CGLiB 的依据: (1)当 Bean 实现接口时,Spring 就会用 JDK 的动态代理 (2)当 Bean 没有实现接口时,Spring 使用 CGlib 是实现 (3)可以强制使用 CGlib(在 spring 配置中加入) 三、CGlib 比 JDK 快 (1)使用 CGLib 实现动态代理,CGLib 底层采用 ASM 字节码生成框架,使用字节 码技术生成代理类,比使用 Java 反射效率要高。唯一需要注意的是,CGLib 不能对声明为 final 的方法进行代 理,因为 CGLib 原理是动态生成被代 理类的子类。 (2)在对 JDK 动态代理与 CGlib 动态代理的代码实验中看,1W 次执行下,JDK7 及 8 的动态代理性能比 CGlib 要 好 20%左右

2.11 FactoryBean 和 BeanFactory 的区别

BeanFactory 和 FactoryBean 的区别BeanFactory 是接口,提供了 IOC 容器最基本的形式,给具体的 IOC 容器的实现提供了规范,FactoryBean 也是接口,为 IOC 容器中 Bean 的实现提供了更加灵活的方式,FactoryBean 在 IOC 容器的基础上给Bean 的实现加上了一个简单工厂模式和装饰模式(如果想了解装饰模式参考:修饰者模式(装饰者模式,Decoration) 我们可以在 getObject()方法中灵活配置。其实在 Spring 源码中有很多 FactoryBean 的实现类.BeanFactory 是个 Factory,也就是 IOC 容器或对象工厂,FactoryBean 是个Bean。在 Spring 中,所有的 Bean 都是由 BeanFactory(也就是 IOC 容器)来进行管理的。但对 FactoryBean 而言,这个 Bean 不是简单的 Bean,而是一个能生产或者修饰对象生成的工厂 Bean,它的实现与设计模式中的工厂模式和修饰器模式类似 。一般情况下,Spring 通过反射机制利用的 class 属性指定实现类实例化 Bean,在某些情况下,实例化 Bean过程比较复杂,如果按照传统的方式,则需要在中提供大量的配置信息。配置方式的灵活性是受限的,这时采用编码的方式可能会得到一个简单的方案。Spring 为此提供了一个org.springframework.bean.factory.FactoryBean 的工厂类接口,用户可以通过实现该接口定制实例化 Bean 的逻辑。FactoryBean 接口对于 Spring 框架来说占用重要的地位,Spring 自身就提供了 70 多个 FactoryBean 的实现。它们隐藏了实例化一些复杂 Bean 的细节,给上层应用带来了便利。从 Spring3.0开始,FactoryBean 开始支持泛型,即接口声明改为 FactoryBean的形式。

2.12 Spring 框架中的单例 Beans 是线程安全的么

Spring 框架并没有对单例 bean 进行任何多线程的封装处理。关于单例 bean 的线程安全和并发问题需要开发 者自行去搞定。但实际上,大部分的 Spring bean并没有可变的状态(比如 Serview 类和 DAO 类),所以在某种程 度上说 Spring的单例 bean 是线程安全的。如果你的 bean 有多种状态的话(比如 View Model对象),就需要自行保证线程安全。最浅显的解决办法就是将多态 bean 的作用域由“singleton”变更为“prototype”。

2.13 Spring 如何处理线程并发问题

在一般情况下,只有无状态的 Bean 才可以在多线程环境下共享,在 Spring 中,绝大部分 Bean 都可以声明为singleton 作用域,因为 Spring 对一些 Bean 中非线程安全状态采用ThreadLocal 进行处理,解决线程安全问题。ThreadLocal 和线程同步机制都是为了解决多线程中相同变量的访问冲突问题。同步机制采用了“时间换空间”的方式,仅提供一份变量,不同的线程在访问前需要获取锁,没获得锁的线程则需要排队。而 ThreadLocal 采用了“空间换时间”的方式。ThreadLocal 会为每一个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。因为每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。ThreadLocal提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的变量封装进 ThreadLocal

2.14 Spring 中 bean 的自动装配

在 spring 中,对象无需自己查找或创建与其关联的其他对象,由容器负责把需要 相互协作的对象引用赋予各个对 象,使用 autowire 来配置自动装载模式。

在 Spring 框架 xml 配置中共有 5 种自动装配:

(1)no:默认的方式是不进行自动装配的,通过手工设置 ref 属性来进行装配 bean。

(2)byName:通过 bean 的名称进行自动装配,如果一个 bean 的 property 与另一 bean 的 name 相同,就进行 自动装配。

(3)byType:通过参数的数据类型进行自动装配。

(4)constructor:利用构造函数进行装配,并且构造函数的参数通过 byType 进行装配。

(5)autodetect:自动探测,如果有构造方法,通过 construct 的方式自动装 配,否则使用 byType 的方式自动装 配。 基于注解的方式: 使用@Autowired 注解来自动装配指定的 bean。在使用@Autowired 注解之前需要 在 Spring 配置文件进行配置, 。

在启动 spring IoC 时,容器自动装载了一 个 AutowiredAnnotationBeanPostProcessor 后置处理器,当容器扫描到@Autowied、@Resource 或@Inject 时,就会在 IoC 容器自动查找需要的 bean,并装配 给该对象的属性。在使用@Autowired 时,首先在容器中查询对应类型的 bean: 如果查询结果刚好为一个,就将该 bean 装配给@Autowired 指定的数据; 如果查询的结果不止一个,那么@Autowired 会根据名称来查找; 如果上述查找的结果为空,那么会抛出异常。解决方法时,使用 required=false。 @Autowired 可用于:构造函数、成员变量、Setter 方法

2.15 @Autowired 和@Resource之间的区别

(1) @Autowired 默认是按照类型装配注入的,默认情况下它要求依赖对象必须存在(可以设置它 required 属性 为 false)。(2) @Resource 默认是按照名称来装配注入的,只有当找不到与名称匹配的 bean才会按照类型来装配注入。

2.16 如何实现 spring 事务管理器

(1)编程式事务管理,在代码中调用 beginTransaction()、commit()、 rollback()等事务管理相关的方法,这就 是编程式事务管理。

(2)基于 TransactionProxyFactoryBean 的声明式事务管理

( 3 ) 基 于 @Transactional 的 声 明 式 事 务 管 理 ,spring 配 置 文 件 中 配 置 TransactionManager , 配 置 ,开启注解式事务管理

(4)基于 Aspectj AOP 配置事务

2.17 Spring 事务传播特性

事务传播行为就是多个事务方法调用时,如何定义方法间事务的传播。Spring 定义了 7 中传播行为:(1)propagation_requierd:如果当前没有事务,就新建一个事务,如果已存在一个事务中,加入到这个事务中,这是 Spring 默认的选择。(2)propagation_supports:支持当前事务,如果没有当前事务,就以非事务方法执行。(3)propagation_mandatory:使用当前事务,如果没有当前事务,就抛出异常。(4)propagation_required_new:新建事务,如果当前存在事务,把当前事务挂起。(5)propagation_not_supported:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。(6)propagation_never:以非事务方式执行操作,如果当前事务存在则抛出异常。(7)propagation_nested:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与propagation_required 类似的操作。

三、Mybatis

3.1 什么是Mybatis

(1) Mybatis 是一个半 ORM(对象关系映射)框架,它内部封装了 JDBC,开发时只需要关注 SQL 语句本身,不需要花费精力去处理加载驱动、创建连接、创建 statement 等繁杂的过程。程序员直接编写原生态 sql,可以严格控制 sql 执行性能,灵活度高。(2)MyBatis 可以使用XML 或注解来配置和映射原生信息,将POJO 映射成数据库中的记录,避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。(3)通过 xml 文件或注解的方式将要执行的各种 statement 配置起来,并通过java 对象和 statement 中 sql的动态参数进行映射生成最终执行的 sql 语句,最后由 mybatis 框架执行 sql并将结果映射为 java 对象并返回。(从执行 sql 到返回 result 的过程)。

3.2 mybatis 的特点

Mybaits 的优点:(1)基于 SQL 语句编程,相当灵活,不会对应用程序或者数据库的现有设计造成任何影响,SQL 写在 XML 里,解除 sql 与程序代码的耦合,便于统一管理;提供 XML 标签,支持编写动态 SQL语句,并可重用。(2)与 JDBC 相比,减少了 50%以上的代码量,消除了 JDBC 大量冗余的代码,不需要手动开关连接;(3)很好的与各种数据库兼容(因为 MyBatis 使用 JDBC 来连接数据库,所以只要 JDBC 支持的数据库 MyBatis都支持)。(4)能够与 Spring 很好的集成;(5)提供映射标签,支持对象与数据库的 ORM 字段关系映射;提供对象关系映射标签,支持对象关系组件维护。

3.3、MyBatis 框架的缺点:

(1)SQL 语句的编写工作量较大,尤其当字段多、关联表多时,对开发人员编写SQL 语句的功底有一定要求。(2)SQL 语句依赖于数据库,导致数据库移植性差,不能随意更换数据库。

3.4、MyBatis 框架适用场合:

(1)MyBatis 专注于 SQL 本身,是一个足够灵活的 DAO 层解决方案。(2)对性能的要求很高,或者需求变化较多的项目,如互联网项目,MyBatis 将是不错的选择。

3.5 mybatis 框架原理

1、加载 sqlMapConfig 文件,创建 Configation 对象;2、根据 Configation 创建 SessionFactory 对象;3、通过 SessionFactory 生成 session,session 是恒程序员操作数据库的接口;4、session 会话通过底层真正操作数据库的是 Excutor 接口操作数据库;5、底层实际上是通过 MappedStatement 进行数据的操作,封装了 SQL 语句、输入参数、输出参数;

3.6 mybatis 有哪些动态标签

if 标签:判断是否符合条件。foreach 标签:对一个集合进行遍历. collection:遍历集合 item:遍历集合元素 index:元素索引值 open:遍历开始 close:遍历结束 separator:遍历元素的分隔符。where 标签:补充相应的 where 的 sql 语句,解决了 if 标签在上面所容易造成错误的问题。更好地简化了 where的条件判断。sql 标签:这个元素可以被用来定义可重用的 SQL 代码段,可以包含在其他语句中。它可以被静态地 (在加载参数) 参数化. 不同的属性值通过包含的实例变化。choose, when, otherwise 标签

3.7 mybatis 的一对一、一对多映射

一对一和一对多映射可以嵌套使用,查询结果用 ResultType 和 ResultMap 接 收; resultType:要求 pojo 和数据库字段、类型一模一样。 resultMap:可以根据映射与实体 bean 数据绑定,SQL 查询列名别名符合即可。

一对一映射:
<association>
<id property="" column=""/>
<result property="" column="" />
</association>
一对多映射:
<collection property="students" column="id" fetchType="lazy"
javaType="ArrayList" ofType="com.dj.domain.Student"
select="com.dj.mapper.StudentMapper.selectStudentByClazzId">
<id property="id" column="id"/>
<resultproperty="name" column="name"/>
<resultproperty="sex" column="sex"/>
<resultproperty="age" column="age"/>
</collection>
复杂的案例:
<!-- 超复杂的 Result Map -->
<resultMap id="detailedBlogResultMap" type="Blog">
<constructor>
<idArg column="blog_id" javaType="int"/>
</constructor>
<result property="title" column="blog_title"/>
<association property="author" javaType="Author">
<id property="id" column="author_id"/>
<result property="username" column="author_username"/>
<result property="password" column="author_password"/>
</association>
<collection property="posts" ofType="Post">
<id property="id" column="post_id"/>
<result property="subject" column="post_subject"/>
<association property="author" javaType="Author"/>
<collection property="comments" ofType="Comment">
<id property="id" column="comment_id"/>
</collection>
</resultMap>

3.8 mybatis 的 mapper.xml 中的#{}和${}的区别

#{}:表示占位符,防止sql注入,使用 #{} 格式的语法会导致 MyBatis 创建PreparedStatement 参数并安全地设置参数(就像使用 一样);${}:连接符,不对参数做任何解析,直接拼接 sql 语句,相当于 statment,有sql 注入风险,一般需要使用 group by ,order by 必须使用列名时才使用;

<select paramType="int" resultType="com.jiyun.User"> select *
from table where id = #{id} </select>

${}:连接符,不对参数做任何解析,直接拼接 sql 语句,相当于 statment,有 sql 注入风险,一般需要使用 group by ,order by 必须使用列名时才使用;

ORDER BY ${columnName}

3.9 mybatis 分页如何处理

一对一映射:   一对多映射:    复杂的案例:  3.8 mybatis 的 mapper.xml 中的#{}和${}的区别 #{}:表示占位符,防止sql注入,使用 #{} 格式的语法会导致 MyBatis 创建 PreparedStatement 参数并安全地设置参数(就像使用 一样); ${}:连接符,不对参数做任何解析,直接拼接 sql 语句,相当于 statment,有 sql 注入风险,一般需要使用 group by ,order by 必须使用列名时才使用; 3.9 mybatis 分页如何处理 mybatis 分页查询有两种方案: 1、可以通过 limit 关键字拼接 sql 语句,需要两个参数,第一个参数开始条 数,第二个参数查询个数; 2、可以通过 pageHelper 插件实现: 1、在 sqlMapConfig 文件中配置 mybatis 的插件(plugins);

2、在查询数据前通过 PageHelper.start()方法,调用 PageHelper 插 件,参数为当前 页和每页显示条数 3、查询结果会封装到一个 page 对象中, 包含分页查询记录、总记录数、总 页数等; 4、从 page 对象中获取需要的数据; 3、pageHelper也可以交给spring容器来管理

3.10 简单的说一下 MyBatis 的一级缓存和二级缓存

Mybatis 首先去缓存中查询结果集,如果没有则查询数据库,如果有则从缓存取出返回结果集就不走数据库。Mybatis 内部存储缓存使用一个 HashMap,key 为 hashCode+sqlId+Sql 语句。value 为从查询出来映射生成的 java对象.Mybatis 的二级缓存即查询缓存,它的作用域是一个 mapper 的 namespace,即在同一个 namespace 中查询 sql 可以从缓存中获取数据。二级缓存是可以跨 SqlSession 的。

四、springboot相关面试话术

4.1、什么是springboot

SpringBoot是Spring项目中的一个子工程,其实人们把Spring Boot 称为搭建程序的脚手架。其最主要作用就是帮我们快速的构建庞大的spring项目,并且尽可能的减少一切xml配置,做到开箱即用,迅速上手,让我们关注与业务而非配置。

4.2、为什么要用springboot

Spring Boot 优点非常多,如:一、独立运行Spring Boot而且内嵌了各种servlet容器,Tomcat、Jetty等,现在不再需要打成war包部署到容器中,SpringBoot只要打成一个可执行的jar包就能独立运行,所有的依赖包都在一个jar包内。二、简化配置spring-boot-starter-web启动器自动依赖其他组件,简少了maven的配置。三、自动配置Spring Boot能根据当前类路径下的类、jar包来自动配置bean,如添加一个spring-boot-starter-web启动器就能拥有web的功能,无需其他配置。四、无代码生成和XML配置Spring Boot配置过程中无代码生成,也无需XML配置文件就能完成所有配置工作,这一切都是借助于条件注解完成的,这也是Spring4.x的核心功能之一。五、应用监控Spring Boot提供一系列端点可以监控服务及应用,做健康检测

4.3、springboot有哪些优点

减少开发,测试时间和努力。使用 JavaCong 有助于避免使用 XML。避免大量的Maven 导入和各种版本冲突。通过提供默认值快速开始开发。没有单独的 Web 服务器需要。这意味着你不再需要启动 Tomcat,Glasssh或其他任何东西。需要更少的配置 因为没有 web.xml 文件。只需添加用@ Conguration 注释的类,然后添加用@Bean 注释的方法,Spring 将自动加载对象并像以前一样对其进行管理。您甚至可以将@Autowired 添加到 bean 方法中,以使 Spring 自动装入需要的依赖关系中。基于环境的配置 使用这些属性,您可以将您正在使用的环境传递到应用程序:-Dspring.proles.active = {enviornment}。在加载主应用程序属性文件后,Spring 将在(application{environment} .properties)中加载后续的应用程序属性文件。application.ymlspring.active.profile=devapplication-dev.ymlapplication-test.ymlapplication-prod.yml

4.4、Spring Boot 的核心注解是哪个?它主要由哪几个注

解组成的启动类上面的注解是@SpringBootApplication,它也是 Spring Boot 的核心注解,主要组合包含了以下3 个注解:@SpringBootConguration:组合了@Conguration 注解,实现配置文件的功能。@EnableAutoConguration:打开自动配置的功能,也可以关闭某个自动配置的选项,如关闭数据源自动配置功能:@SpringBootApplication(exclude = { DataSourceAutoConguration.class})。@ComponentScan:Spring组件扫描,从当前类所在的包以及子包扫描,之外的包扫描不到,所以我们在开发的时候,所有的类都在主类的子包下

4.5、springboot项目有哪几种运行方式

打包用命令或者放到容器中运行用 Maven/Gradle 插件运行直接执行 main 方法运行

4.6、如何理解springboot中的starters?

Starters可以理解为启动器,它包含了一系列可以集成到应用里面的依赖包,你可以一站式集成Spring及其他技术,而不需要到处找示例代码和依赖包。如你想使用Spring JPA访问数据库,只要加入springboot-starter-data-jpa启动器依赖就能使用了。Starters包含了许多项目中需要用到的依赖,它们能快速持续的运行,都是一系列得到支持的管理传递性依赖。

4.7、springboot自动配置原理

这个就得从springboot项目的核心注解@SpringbootApplication说起了,这个注解包含了三个注解,其中一个是@EnableAutoConfiguration注解,这个注解主要是开启自动配置的,这个注解会"猜"你将如何配置 spring,前提是你已经添加 了jar 依赖项,比如项目中引入了 spring-boot-starter-web ,这个包里已经添加 Tomcat 和 SpringMVC,这个注解节就会自动假设您在开发一个 web 应用程序并添加相应的 spring 配置,springboot默认有一个spring-bootautoconfigure包,大多数常用的第三方的配置都自动集成了,像redis、es等,这里边有一个META-INF/spring.factories文件,这里边定义了所有需要加载的bean的全路径,spring会根据反射的原理,创建这些对象,放到IOC容器中,加载时需要的参数,通过JavaConfig的方式加载配置文件中的参数然后创建了对应的对象,这就是自动配置的原理

五、springcloud相关面试话术

5.1、什么是Springcloud

Spring Cloud 是一系列框架的集合,它利用 Spring Boot 的开发便利性简化 了分布式系统的开发,比如服务发现、服务网关、服务路由、链路追踪等。他的设计 目的是为 了简化 Spring 应用的搭建和开发过程。该框架遵循“约定大于配置”原 则,采用特定的方 式进行配置,从而使开发者不用定义大量的 XML 配置。Spring Cloud 并不重复造轮子,而是将市 面上开发得比较好的模块集成进去,进行封装,

从而减少了各模块的开发成本。换句话说:Spring Cloud 提供了构建分布式系统 所需的“全家桶”。核心组件:Eureka、Ribbon、Feign、 Hystrix、Zuul. 为什么要使用这个呢?因为之前的嗯项目架构都是集中式的。这就会导致一个问题在 项目当中出现任何一个小问题都会让整个项目不能使用。修改完之后需要让整个项目 全量更新,所以基于传统架构的这种方式,我们在这个项目当中把,架构调整了一 下,采用了微服务的架构。那使用了微服务架构之后,在整体的分配任务上呀,还有 扩展性上来讲,比以前的开发以及这个效率上都有很显著的提高。 我介绍一下spring cloud里边儿的一些组件吧,我们项目当中使用的。首先就是它 的 注册中心Eureka。所有的微服务。都需要连接Eureka去进行管理 。 它里边儿会有心跳协议,会知道每个微服务具体的一个在线状态。以及给其他调用 微服务的这些去提供一些这这个微服务的基本信息 接着就是这个远程调用feign,它提供了微服务之间的远程调用的一个组件,它是 基于HTTP的* 。 然后,远程调用这个组件集成了负载均衡ribbon *。它可以 有效的分辨出当前注册中心当中这个为服务有多少实例,会根据内部的算法去均衡 的域访问这些实例,它的算法有轮询还有随机,这个算法我们也可以自定义,它默 认的算法呢是轮循去访问 接着就是 。熔断器hystrix。那他这个组件儿在我们项目当中用的时候,就是在远程调用 时。如果任何一个微服务响应超时或者发生异常,熔断器就会介入,把当前请求切 断。然后去执行我们的回调方法,返回回调方法当中的数据。这样的话会保证我们 微服务当中的请求链路不会卡死,而且,这样的话不会让用户在前台一直在等着。 会有一个非常好的用户体验。 接着就是我们的网关。 Zuul。网关在我们项目当中充当的地位就是一个所有请求的入口。所有请求进来之 后,首先通过网关有网关,根据路径儿去解析,然后转发到对应的微服务上,当然 这个网关还充当了一个功能,就是一个鉴权功能,我们项目当中,登陆了之后,会 给用户颁发一个token。用户在访问的时候,这个token会携带在请求头当中,经过 我们网关时,网关会拦截取出token。验证token的真实性。验证通过之后才会访问 到我们的微服务。这就是我们项目当中微服务具体使用的一些场景以及它的组件。

5.2、服务注册和服务发现是 什么意思,springcloud是如

何实现的

在微服务项目中,我们通常会用到服务之间的相互调用,我们通常在属性文件中进行 所有的需要请求的微服务的地址端口等信息。随着越来越多的 服务开发和部署,添 加和修改这些属性变得更加复杂。有些服务可能会下架,而某些位置可 能会发生变 化。手动更改属性可能会产生问题。Eureka 提供了服务注册和服务发现的功能, 服务注册是让所有微服务将自己的信息注册到注册中心,服务发现是让微服务可以 拉取注册中心里的服务列表,方便结合feign进行远程调用,由于所有服务都在 Eureka 服务器上注册并通过调用 Eureka 服务器完成查找, 因此无需处理服务 地点的任何更改和处理。

5.3、负载均衡的意义是什么

我觉得负载均衡的主要意义就是,避免单一应用由于并发等原因,导致应用宕机从而导致系统整体无法使用,多负载同时工作,可以很好的解决高并发的问题,实现服务的高可用。在我们项目中,服务的接入层由nginx管理,用户请求经过nginx之后,根据相应的域名,转发到对应的服务器去,由于nginx只负责请求转发,没有业务逻辑处理,所以效率上非常高。nginx支持的负载均衡策略有很多,我们在nginx.conf中配置upstream模块即可。首先是轮训,默认的就是这种方式第二种权重的方式,就是根据服务器的性能,配置较大的权重,nginx就会分配更多的请求第三种是iphash的方式,nginx会根据请求的ip地址,今夕那个hash运算,然后分配相应的服务器,后续来自同一ip的请求都会分配到这个服务器上第四种是最少连接数,把请求转发给连接数较少的后端服务器还有就是可以根据响应时间和url hash来做处理,我们项目中配置的是权重的方式。在我们项目的微服务架构中,feign和zuul都集成了ribbon的的功能,它是负责在微服务之间相互调用的时候,帮我们实现负载均衡的功能,我们在将微服务注册到注册中心时,如果服务名称一致,就默认为一个集群,在进行远程调用或者路由转发的时候,都可以均衡的访问响应的服务器,ribbon的负载均衡机制有轮训和随机,默认是轮训,当然也可以自定义负载均衡的策略。

5.4、hystrix介绍

hystrix在微服务架构中充当熔断器的功能,它提供了资源隔离、限流、熔断、降级、运维监控等功能,在微服务架构中通常会有多个微服务之间相互调用,基础服务的故障可能会导致级联故障,进而造成整个系统不可用的情况,这种现象被称为服务雪崩效应。服务雪崩效应是一种因“服务提供者”的不可用导致“服务消费者”的不可用,并将不可用逐渐放大的过程。熔断器的原理很简单,如同电力过载保护器。它可以实现快速失败,如果它在一段时间内侦测到许多类似的错误,会强迫其以后的多个调用快速失败,不再访问远程服务器,直接执行回调方法,返回回调方法中的友好数据或者缓存数据,从而防止应用程序不断地尝试执行可能会失败的操作,使得应用程序继续执行而不用等待修正错误,或者浪费 CPU时间去等到长时间的超时产生。熔断器也可以使应用程序能够诊断错误是否已经修正,如果已经、修正,应用程序会再次尝试调用操作。当 Hystrix Command 请求后端服务失败数量超过一定比例(默认 50%),断路器会切换到开路状态(Open)。这时所有请求会直接失败而不会发送到后端服务. 断路器保持在开路状态一段时间后(默认 5 秒), 自动切换到半开路状态(HALF-OPEN).这时会判断下一次请求的返回情况,如果请求成功, 断路器切回闭路状态(CLOSED), 否则重新切换到开路状态(OPEN). Hystrix 的断路器就像我们家庭电路中的保险丝, 一旦后端服务不可用, 断路器会直接切断请求链, 避免发送大量无效请求影响系统吞吐量, 并且断路器有自我检测并恢复的能力。

5.5、Eureka和ZooKeeper都可以提供服务注册与发现的功

能,请说说两个的区别

1、ZooKeeper保证的是CP,就是一致性和容错,Eureka保证的是AP,就是可用性和 容错。 ZooKeeper在选举期间注册服务瘫痪,虽然服务最终会恢复,但是选举期间不可用 的,只有等到选举结束之后,所有数据同步之后才能使用。 Eureka各个节点是平等关系,只要有一台Eureka就可以保证服务可用,而查询到的 数据并不是最新的,自我保护机制会导致Eureka不再从注册列表移除因长时间没收 到心跳而应该过期的服务。Eureka仍然能够接受新服务的注册和查询请求,但是不 会被同步到其他节点(高可用),当网络稳定时,当前实例新的注册信息会被同步到其 他节点中(最终一致性) Eureka可以很好的应对因网络故障导致部分节点失去联系的情况,而不会像 ZooKeeper一样使得整个注册系统瘫痪

2、ZooKeeper有Leader和Follower角色,Eureka各个节点平等

3、ZooKeeper采用过半数存活原则,Eureka采用自我保护机制解决分区问题 4、Eureka本质上是一个微服务的一个模块,而ZooKeeper是一个进程,需要单独安 装


点击这里复制本文地址 以上内容由兔豪学习分享网整理呈现,请务必在转载分享时注明本文地址!如对内容有疑问,请联系我们,谢谢!

支持Ctrl+Enter提交
qrcode

兔豪学习分享网 © All Rights Reserved.  
豫ICP备18039133号 My title page contents
Powered by zblog Themes by www.tuzi0.com
| 免责声明| 留言建议| 广告合作|

当前在线 6 人