Java面试题(史上最全)

文章很长,建议收藏起来,慢慢读! 疯狂创客圈为小伙伴奉上如下珍贵的学习资源:html


推荐: 疯狂创客圈 高质量 博文

高并发 必读 的精彩博文
nacos 实战(史上最全) sentinel (史上最全+入门教程)
Zookeeper 分布式锁 (图解+秒懂+史上最全) Webflux(史上最全)
SpringCloud gateway (史上最全) TCP/IP(图解+秒懂+史上最全)
10分钟看懂, Java NIO 底层原理 Feign原理 (图解)
更多精彩博文 ..... 请参见【 疯狂创客圈 高并发 总目录

史上最全 Java 面试题 28 专题 总目录

精心梳理、吐血推荐、史上最强、建议收藏 阿里、京东、美团、头条.... 随意挑、横着走!!!
1.Java算法面试题(史上最强、持续更新、吐血推荐) 2.Java基础面试题(史上最全、持续更新、吐血推荐)
3.JVM面试题(史上最强、持续更新、吐血推荐) 四、架构设计面试题 (史上最全、持续更新、吐血推荐)
五、Spring面试题 专题 六、SpringMVC面试题 专题
7.SpringBoot - 面试题(史上最强、持续更新) 八、Tomcat面试题 专题部分
9.网络协议面试题(史上最全、持续更新、吐血推荐) 十、TCP/IP协议(图解+秒懂+史上最全)
11.JUC并发包与容器 - 面试题(史上最强、持续更新) 十二、设计模式面试题 (史上最全、持续更新、吐血推荐)
13.死锁面试题(史上最强、持续更新) 15.Zookeeper 分布式锁 (图解+秒懂+史上最全)
1四、Redis 面试题 - 收藏版(史上最强、持续更新) 1六、Zookeeper 面试题(史上最强、持续更新)
1七、分布式事务面试题 (史上最全、持续更新、吐血推荐) 1八、一致性协议 (史上最全)
1九、Zab协议 (史上最全) 20、Paxos 图解 (秒懂)
2一、raft 图解 (秒懂) 2六、消息队列、RabbitMQ、Kafka、RocketMQ面试题 (史上最全、持续更新)
22.Linux面试题(史上最全、持续更新、吐血推荐) 2三、Mysql 面试题(史上最强、持续更新)
2四、SpringCloud 面试题 - 收藏版(史上最强、持续更新) 2五、Netty 面试题 (史上最强、持续更新)
2七、内存泄漏 内存溢出(史上最全) 2八、JVM 内存溢出 实战 (史上最全)

Spring面试题 专题部分

什么是spring?

Spring是一个轻量级Java开发框架,最先有Rod Johnson建立,目的是为了解决企业级应用开发的业务逻辑层和其余各层的耦合问题。它是一个分层的JavaSE/JavaEE full-stack(一站式)轻量级开源框架,为开发Java应用程序提供全面的基础架构支持。Spring负责基础架构,所以Java开发者能够专一于应用程序的开发。前端

Spring最根本的使命是解决企业级应用开发的复杂性,即简化Java开发java

Spring能够作不少事情,它为企业级开发提供给了丰富的功能,可是这些功能的底层都依赖于它的两个核心特性,也就是依赖注入(dependency injection,DI)和面向切面编程(aspect-oriented programming,AOP)git

为了下降Java开发的复杂性,Spring采起了如下4种关键策略程序员

  • 基于POJO的轻量级和最小侵入性编程;
  • 经过依赖注入和面向接口实现松耦合;
  • 基于切面和惯例进行声明式编程;
  • 经过切面和模板减小样板式代码。

Spring框架的设计目标,设计理念,和核心是什么

Spring设计目标:Spring为开发者提供一个一站式轻量级应用开发平台;github

Spring设计理念:在JavaEE开发中,支持POJO和JavaBean开发方式,使应用面向接口开发,充分支持OO(面向对象)设计方法;Spring经过IoC容器实现对象耦合关系的管理,并实现依赖反转,将对象之间的依赖关系交给IoC容器,实现解耦;web

Spring框架的核心:IoC容器和AOP模块。经过IoC容器管理POJO对象以及他们之间的耦合关系;经过AOP以动态非侵入的方式加强服务。面试

IoC让相互协做的组件保持松散的耦合,而AOP编程容许你把遍及于应用各层的功能分离出来造成可重用的功能组件。ajax

Spring的优缺点是什么?

优势正则表达式

  • 方便解耦,简化开发

    Spring就是一个大工厂,能够将全部对象的建立和依赖关系的维护,交给Spring管理。

  • AOP编程的支持

    Spring提供面向切面编程,能够方便的实现对程序进行权限拦截、运行监控等功能。

  • 声明式事务的支持

    只须要经过配置就能够完成对事务的管理,而无需手动编程。

  • 方便程序的测试

    Spring对Junit4支持,能够经过注解方便的测试Spring程序。

  • 方便集成各类优秀框架

    Spring不排斥各类优秀的开源框架,其内部提供了对各类优秀框架的直接支持(如:Struts、Hibernate、MyBatis等)。

  • 下降JavaEE API的使用难度

    Spring对JavaEE开发中很是难用的一些API(JDBC、JavaMail、远程调用等),都提供了封装,使这些API应用难度大大下降。

缺点

  • Spring明明一个很轻量级的框架,却给人感受大而全
  • Spring依赖反射,反射影响性能
  • 使用门槛升高,入门Spring须要较长时间

Spring有哪些应用场景

应用场景:JavaEE企业应用开发,包括SSH、SSM等

Spring价值

  • Spring是非侵入式的框架,目标是使应用程序代码对框架依赖最小化;
  • Spring提供一个一致的编程模型,使应用直接使用POJO开发,与运行环境隔离开来;
  • Spring推进应用设计风格向面向对象和面向接口开发转变,提升了代码的重用性和可测试性;

Spring由哪些模块组成?

Spring 总共大约有 20 个模块, 由 1300 多个不一样的文件构成。 而这些组件被分别整合在核心容器(Core Container)AOP(Aspect Oriented Programming)和设备支持(Instrmentation)数据访问与集成(Data Access/Integeration)Web消息(Messaging)Test等 6 个模块中。 如下是 Spring 5 的模块结构图:

在这里插入图片描述

  • spring core:提供了框架的基本组成部分,包括控制反转(Inversion of Control,IOC)和依赖注入(Dependency Injection,DI)功能。
  • spring beans:提供了BeanFactory,是工厂模式的一个经典实现,Spring将管理对象称为Bean。
  • spring context:构建于 core 封装包基础上的 context 封装包,提供了一种框架式的对象访问方法。
  • spring jdbc:提供了一个JDBC的抽象层,消除了烦琐的JDBC编码和数据库厂商特有的错误代码解析, 用于简化JDBC。
  • spring aop:提供了面向切面的编程实现,让你能够自定义拦截器、切点等。
  • spring Web:提供了针对 Web 开发的集成特性,例如文件上传,利用 servlet listeners 进行 ioc 容器初始化和针对 Web 的 ApplicationContext。
  • spring test:主要为测试提供支持的,支持使用JUnit或TestNG对Spring组件进行单元测试和集成测试。

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

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

详细讲解一下核心容器(spring context应用上下文) 模块

这是基本的Spring模块,提供spring 框架的基础功能,BeanFactory 是 任何以spring为基础的应用的核心。Spring 框架创建在此模块之上,它使Spring成为一个容器。

Bean 工厂是工厂模式的一个实现,提供了控制反转功能,用来把应用的配置和依赖从真正的应用代码中分离。最经常使用的就是org.springframework.beans.factory.xml.XmlBeanFactory ,它根据XML文件中的定义加载beans。该容器从XML 文件读取配置元数据并用它去建立一个彻底配置的系统或应用。

Spring框架中有哪些不一样类型的事件

Spring 提供了如下5种标准的事件:

  1. 上下文更新事件(ContextRefreshedEvent):在调用ConfigurableApplicationContext 接口中的refresh()方法时被触发。
  2. 上下文开始事件(ContextStartedEvent):当容器调用ConfigurableApplicationContext的Start()方法开始/从新开始容器时触发该事件。
  3. 上下文中止事件(ContextStoppedEvent):当容器调用ConfigurableApplicationContext的Stop()方法中止容器时触发该事件。
  4. 上下文关闭事件(ContextClosedEvent):当ApplicationContext被关闭时触发该事件。容器被关闭时,其管理的全部单例Bean都被销毁。
  5. 请求处理事件(RequestHandledEvent):在Web应用中,当一个http请求(request)结束触发该事件。若是一个bean实现了ApplicationListener接口,当一个ApplicationEvent 被发布之后,bean会自动被通知。

Spring 应用程序有哪些不一样组件?

Spring 应用通常有如下组件:

  • 接口 - 定义功能。
  • Bean 类 - 它包含属性,setter 和 getter 方法,函数等。
  • Bean 配置文件 - 包含类的信息以及如何配置它们。
  • Spring 面向切面编程(AOP) - 提供面向切面编程的功能。
  • 用户程序 - 它使用接口。

使用 Spring 有哪些方式?

使用 Spring 有如下方式:

  • 做为一个成熟的 Spring Web 应用程序。
  • 做为第三方 Web 框架,使用 Spring Frameworks 中间层。
  • 做为企业级 Java Bean,它能够包装现有的 POJO(Plain Old Java Objects)。
  • 用于远程使用。

Spring控制反转(IOC)(13)

什么是Spring IOC 容器?

控制反转即IoC (Inversion of Control),它把传统上由程序代码直接操控的对象的调用权交给容器,经过容器来实现对象组件的装配和管理。所谓的“控制反转”概念就是对组件对象控制权的转移,从程序代码自己转移到了外部容器。

Spring IOC 负责建立对象,管理对象(经过依赖注入(DI),装配对象,配置对象,而且管理这些对象的整个生命周期。

控制反转(IoC)有什么做用

  • 管理对象的建立和依赖关系的维护。对象的建立并非一件简单的事,在对象关系比较复杂时,若是依赖关系须要程序猿来维护的话,那是至关头疼的
  • 解耦,由容器去维护具体的对象
  • 托管了类的产生过程,好比咱们须要在类的产生过程当中作一些处理,最直接的例子就是代理,若是有容器程序能够把这部分处理交给容器,应用程序则无需去关心类是如何完成代理的

IOC的优势是什么?

  • IOC 或 依赖注入把应用的代码量降到最低。
  • 它使应用容易测试,单元测试再也不须要单例和JNDI查找机制。
  • 最小的代价和最小的侵入性使松散耦合得以实现。
  • IOC容器支持加载服务时的饿汉式初始化和懒加载。

Spring IoC 的实现机制

Spring 中的 IoC 的实现原理就是工厂模式加反射机制。

示例:

interface Fruit {
   public abstract void eat();
 }

class Apple implements Fruit {
    public void eat(){
        System.out.println("Apple");
    }
}

class Orange implements Fruit {
    public void eat(){
        System.out.println("Orange");
    }
}

class Factory {
    public static Fruit getInstance(String ClassName) {
        Fruit f=null;
        try {
            f=(Fruit)Class.forName(ClassName).newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return f;
    }
}

class Client {
    public static void main(String[] a) {
        Fruit f=Factory.getInstance("io.github.dunwu.spring.Apple");
        if(f!=null){
            f.eat();
        }
    }
}

Spring 的 IoC支持哪些功能

Spring 的 IoC 设计支持如下功能:

  • 依赖注入
  • 依赖检查
  • 自动装配
  • 支持集合
  • 指定初始化方法和销毁方法
  • 支持回调某些方法(可是须要实现 Spring 接口,略有侵入)

其中,最重要的就是依赖注入,从 XML 的配置上说,即 ref 标签。对应 Spring RuntimeBeanReference 对象。

对于 IoC 来讲,最重要的就是容器。容器管理着 Bean 的生命周期,控制着 Bean 的依赖注入。

BeanFactory 和 ApplicationContext有什么区别?

BeanFactory和ApplicationContext是Spring的两大核心接口,均可以当作Spring的容器。其中ApplicationContext是BeanFactory的子接口。

依赖关系

BeanFactory:是Spring里面最底层的接口,包含了各类Bean的定义,读取bean配置文档,管理bean的加载、实例化,控制bean的生命周期,维护bean之间的依赖关系。

ApplicationContext接口做为BeanFactory的派生,除了提供BeanFactory所具备的功能外,还提供了更完整的框架功能:

  • 继承MessageSource,所以支持国际化。
  • 统一的资源文件访问方式。
  • 提供在监听器中注册bean的事件。
  • 同时加载多个配置文件。
  • 载入多个(有继承关系)上下文 ,使得每个上下文都专一于一个特定的层次,好比应用的web层。

加载方式

BeanFactroy采用的是延迟加载形式来注入Bean的,即只有在使用到某个Bean时(调用getBean()),才对该Bean进行加载实例化。这样,咱们就不能发现一些存在的Spring的配置问题。若是Bean的某一个属性没有注入,BeanFacotry加载后,直至第一次使用调用getBean方法才会抛出异常。

ApplicationContext,它是在容器启动时,一次性建立了全部的Bean。这样,在容器启动时,咱们就能够发现Spring中存在的配置错误,这样有利于检查所依赖属性是否注入。 ApplicationContext启动后预载入全部的单实例Bean,经过预载入单实例bean ,确保当你须要的时候,你就不用等待,由于它们已经建立好了。

相对于基本的BeanFactory,ApplicationContext 惟一的不足是占用内存空间。当应用程序配置Bean较多时,程序启动较慢。

建立方式

BeanFactory一般以编程的方式被建立,ApplicationContext还能以声明的方式建立,如使用ContextLoader。

注册方式

BeanFactory和ApplicationContext都支持BeanPostProcessor、BeanFactoryPostProcessor的使用,但二者之间的区别是:BeanFactory须要手动注册,而ApplicationContext则是自动注册。

Spring 如何设计容器的,BeanFactory和ApplicationContext的关系详解

Spring 做者 Rod Johnson 设计了两个接口用以表示容器。

  • BeanFactory
  • ApplicationContext

BeanFactory 简单粗暴,能够理解为就是个 HashMap,Key 是 BeanName,Value 是 Bean 实例。一般只提供注册(put),获取(get)这两个功能。咱们能够称之为 “低级容器”

ApplicationContext 能够称之为 “高级容器”。由于他比 BeanFactory 多了更多的功能。他继承了多个接口。所以具有了更多的功能。例如资源的获取,支持多种消息(例如 JSP tag 的支持),对 BeanFactory 多了工具级别的支持等待。因此你看他的名字,已经不是 BeanFactory 之类的工厂了,而是 “应用上下文”, 表明着整个大容器的全部功能。该接口定义了一个 refresh 方法,此方法是全部阅读 Spring 源码的人的最熟悉的方法,用于刷新整个容器,即从新加载/刷新全部的 bean。

固然,除了这两个大接口,还有其余的辅助接口,这里就不介绍他们了。

BeanFactory和ApplicationContext的关系

为了更直观的展现 “低级容器” 和 “高级容器” 的关系,这里经过经常使用的 ClassPathXmlApplicationContext 类来展现整个容器的层级 UML 关系。

img

有点复杂? 先不要慌,我来解释一下。

最上面的是 BeanFactory,下面的 3 个绿色的,都是功能扩展接口,这里就不展开讲。

看下面的隶属 ApplicationContext 粉红色的 “高级容器”,依赖着 “低级容器”,这里说的是依赖,不是继承哦。他依赖着 “低级容器” 的 getBean 功能。而高级容器有更多的功能:支持不一样的信息源头,能够访问文件资源,支持应用事件(Observer 模式)。

一般用户看到的就是 “高级容器”。 但 BeanFactory 也很是够用啦!

左边灰色区域的是 “低级容器”, 只负载加载 Bean,获取 Bean。容器其余的高级功能是没有的。例如上图画的 refresh 刷新 Bean 工厂全部配置,生命周期事件回调等。

小结

说了这么多,不知道你有没有理解Spring IoC? 这里小结一下:IoC 在 Spring 里,只须要低级容器就能够实现,2 个步骤:

  1. 加载配置文件,解析成 BeanDefinition 放在 Map 里。
  2. 调用 getBean 的时候,从 BeanDefinition 所属的 Map 里,拿出 Class 对象进行实例化,同时,若是有依赖关系,将递归调用 getBean 方法 —— 完成依赖注入。

上面就是 Spring 低级容器(BeanFactory)的 IoC。

至于高级容器 ApplicationContext,他包含了低级容器的功能,当他执行 refresh 模板方法的时候,将刷新整个容器的 Bean。同时其做为高级容器,包含了太多的功能。一句话,他不只仅是 IoC。他支持不一样信息源头,支持 BeanFactory 工具类,支持层级容器,支持访问文件资源,支持事件发布通知,支持接口回调等等。

ApplicationContext一般的实现是什么?

FileSystemXmlApplicationContext :此容器从一个XML文件中加载beans的定义,XML Bean 配置文件的全路径名必须提供给它的构造函数。

ClassPathXmlApplicationContext:此容器也从一个XML文件中加载beans的定义,这里,你须要正确设置classpath由于这个容器将在classpath里找bean配置。

WebXmlApplicationContext:此容器加载一个XML文件,此文件定义了一个WEB应用的全部bean。

什么是Spring的依赖注入?

控制反转IoC是一个很大的概念,能够用不一样的方式来实现。其主要实现方式有两种:依赖注入和依赖查找

依赖注入:相对于IoC而言,依赖注入(DI)更加准确地描述了IoC的设计理念。所谓依赖注入(Dependency Injection),即组件之间的依赖关系由容器在应用系统运行期来决定,也就是由容器动态地将某种依赖关系的目标对象实例注入到应用系统中的各个关联的组件之中。组件不作定位查询,只提供普通的Java方法让容器去决定依赖关系。

依赖注入的基本原则

依赖注入的基本原则是:应用组件不该该负责查找资源或者其余依赖的协做对象。配置对象的工做应该由IoC容器负责,“查找资源”的逻辑应该从应用组件的代码中抽取出来,交给IoC容器负责。容器全权负责组件的装配,它会把符合依赖关系的对象经过属性(JavaBean中的setter)或者是构造器传递给须要的对象。

依赖注入有什么优点

依赖注入之因此更流行是由于它是一种更可取的方式:让容器全权负责依赖查询,受管组件只须要暴露JavaBean的setter方法或者带参数的构造器或者接口,使容器能够在初始化时组装对象的依赖关系。其与依赖查找方式相比,主要优点为:

  • 查找定位操做与应用代码彻底无关。
  • 不依赖于容器的API,能够很容易地在任何容器之外使用应用对象。
  • 不须要特殊的接口,绝大多数对象能够作到彻底没必要依赖容器。

有哪些不一样类型的依赖注入实现方式?

依赖注入是时下最流行的IoC实现方式,依赖注入分为接口注入(Interface Injection),Setter方法注入(Setter Injection)和构造器注入(Constructor Injection)三种方式。其中接口注入因为在灵活性和易用性比较差,如今从Spring4开始已被废弃。

构造器依赖注入:构造器依赖注入经过容器触发一个类的构造器来实现的,该类有一系列参数,每一个参数表明一个对其余类的依赖。

Setter方法注入:Setter方法注入是容器经过调用无参构造器或无参static工厂 方法实例化bean以后,调用该bean的setter方法,即实现了基于setter的依赖注入。

构造器依赖注入和 Setter方法注入的区别

构造函数注入 setter 注入
没有部分注入 有部分注入
不会覆盖 setter 属性 会覆盖 setter 属性
任意修改都会建立一个新实例 任意修改不会建立一个新实例
适用于设置不少属性 适用于设置少许属性

两种依赖方式均可以使用,构造器注入和Setter方法注入。最好的解决方案是用构造器参数实现强制依赖,setter方法实现可选依赖。

Spring Beans(19)

什么是Spring beans?

Spring beans 是那些造成Spring应用的主干的java对象。它们被Spring IOC容器初始化,装配,和管理。这些beans经过容器中配置的元数据建立。好比,以XML文件中 的形式定义。

一个 Spring Bean 定义 包含什么?

一个Spring Bean 的定义包含容器必知的全部配置元数据,包括如何建立一个bean,它的生命周期详情及它的依赖。

如何给Spring 容器提供配置元数据?Spring有几种配置方式

这里有三种重要的方法给Spring 容器提供配置元数据。

  • XML配置文件。
  • 基于注解的配置。
  • 基于java的配置。

Spring配置文件包含了哪些信息

Spring配置文件是个XML 文件,这个文件包含了类信息,描述了如何配置它们,以及如何相互调用。

Spring基于xml注入bean的几种方式

  1. Set方法注入;
  2. 构造器注入:①经过index设置参数的位置;②经过type设置参数类型;
  3. 静态工厂注入;
  4. 实例工厂;

你怎样定义类的做用域?

当定义一个 在Spring里,咱们还能给这个bean声明一个做用域。它能够经过bean 定义中的scope属性来定义。如,当Spring要在须要的时候每次生产一个新的bean实例,bean的scope属性被指定为prototype。另外一方面,一个bean每次使用的时候必须返回同一个实例,这个bean的scope 属性 必须设为 singleton。

解释Spring支持的几种bean的做用域

Spring框架支持如下五种bean的做用域:

  • singleton : bean在每一个Spring ioc 容器中只有一个实例。
  • prototype:一个bean的定义能够有多个实例。
  • request:每次http请求都会建立一个bean,该做用域仅在基于web的Spring ApplicationContext情形下有效。
  • session:在一个HTTP Session中,一个bean定义对应一个实例。该做用域仅在基于web的Spring ApplicationContext情形下有效。
  • global-session:在一个全局的HTTP Session中,一个bean定义对应一个实例。该做用域仅在基于web的Spring ApplicationContext情形下有效。

注意: 缺省的Spring bean 的做用域是Singleton。使用 prototype 做用域须要慎重的思考,由于频繁建立和销毁 bean 会带来很大的性能开销。

Spring框架中的单例bean是线程安全的吗?

不是,Spring框架中的单例bean不是线程安全的。

spring 中的 bean 默认是单例模式,spring 框架并无对单例 bean 进行多线程的封装处理。

实际上大部分时候 spring bean 无状态的(好比 dao 类),全部某种程度上来讲 bean 也是安全的,但若是 bean 有状态的话(好比 view model 对象),那就要开发者本身去保证线程安全了,最简单的就是改变 bean 的做用域,把“singleton”变动为“prototype”,这样请求 bean 至关于 new Bean()了,因此就能够保证线程安全了。

  • 有状态就是有数据存储功能。
  • 无状态就是不会保存数据。

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

在通常状况下,只有无状态的Bean才能够在多线程环境下共享,在Spring中,绝大部分Bean均可以声明为singleton做用域,由于Spring对一些Bean中非线程安全状态采用ThreadLocal进行处理,解决线程安全问题。

ThreadLocal和线程同步机制都是为了解决多线程中相同变量的访问冲突问题。同步机制采用了“时间换空间”的方式,仅提供一份变量,不一样的线程在访问前须要获取锁,没得到锁的线程则须要排队。而ThreadLocal采用了“空间换时间”的方式。

ThreadLocal会为每个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。由于每个线程都拥有本身的变量副本,从而也就没有必要对该变量进行同步了。ThreadLocal提供了线程安全的共享对象,在编写多线程代码时,能够把不安全的变量封装进ThreadLocal。

解释Spring框架中bean的生命周期

在传统的Java应用中,bean的生命周期很简单。使用Java关键字new进行bean实例化,而后该bean就可使用了。一旦该bean再也不被使用,则由Java自动进行垃圾回收。相比之下,Spring容器中的bean的生命周期就显得相对复杂多了。正确理解Spring bean的生命周期很是重要,由于你或许要利用Spring提供的扩展点来自定义bean的建立过程。下图展现了bean装载到Spring应用上下文中的一个典型的生命周期过程。

img

bean在Spring容器中从建立到销毁经历了若干阶段,每一阶段均可以针对Spring如何管理bean进行个性化定制。

正如你所见,在bean准备就绪以前,bean工厂执行了若干启动步骤。

咱们对上图进行详细描述:

Spring对bean进行实例化;

Spring将值和bean的引用注入到bean对应的属性中;

若是bean实现了BeanNameAware接口,Spring将bean的ID传递给setBean-Name()方法;

若是bean实现了BeanFactoryAware接口,Spring将调用setBeanFactory()方法,将BeanFactory容器实例传入;

若是bean实现了ApplicationContextAware接口,Spring将调用setApplicationContext()方法,将bean所在的应用上下文的引用传入进来;

若是bean实现了BeanPostProcessor接口,Spring将调用它们的post-ProcessBeforeInitialization()方法;

若是bean实现了InitializingBean接口,Spring将调用它们的after-PropertiesSet()方法。相似地,若是bean使用initmethod声明了初始化方法,该方法也会被调用;

若是bean实现了BeanPostProcessor接口,Spring将调用它们的post-ProcessAfterInitialization()方法;

此时,bean已经准备就绪,能够被应用程序使用了,它们将一直驻留在应用上下文中,直到该应用上下文被销毁;

若是bean实现了DisposableBean接口,Spring将调用它的destroy()接口方法。一样,若是bean使用destroy-method声明了销毁方法,该方法也会被调用。

如今你已经了解了如何建立和加载一个Spring容器。可是一个空的容器并无太大的价值,在你把东西放进去以前,它里面什么都没有。为了从Spring的DI(依赖注入)中受益,咱们必须将应用对象装配进Spring容器中。

哪些是重要的bean生命周期方法? 你能重载它们吗?

有两个重要的bean 生命周期方法,第一个是setup , 它是在容器加载bean的时候被调用。第二个方法是 teardown 它是在容器卸载类的时候被调用。

bean 标签有两个重要的属性(init-method和destroy-method)。用它们你能够本身定制初始化和注销方法。它们也有相应的注解(@PostConstruct和@PreDestroy)。

什么是Spring的内部bean?什么是Spring inner beans?

在Spring框架中,当一个bean仅被用做另外一个bean的属性时,它能被声明为一个内部bean。内部bean能够用setter注入“属性”和构造方法注入“构造参数”的方式来实现,内部bean一般是匿名的,它们的Scope通常是prototype。

在 Spring中如何注入一个java集合?

Spring提供如下几种集合的配置元素:

类型用于注入一列值,容许有相同的值。

类型用于注入一组值,不容许有相同的值。

类型用于注入一组键值对,键和值均可觉得任意类型。

类型用于注入一组键值对,键和值都只能为String类型。

什么是bean装配?

装配,或bean 装配是指在Spring 容器中把bean组装到一块儿,前提是容器须要知道bean的依赖关系,如何经过依赖注入来把它们装配到一块儿。

什么是bean的自动装配?

在Spring框架中,在配置文件中设定bean的依赖关系是一个很好的机制,Spring 容器可以自动装配相互合做的bean,这意味着容器不须要和配置,能经过Bean工厂自动处理bean之间的协做。这意味着 Spring能够经过向Bean Factory中注入的方式自动搞定bean之间的依赖关系。自动装配能够设置在每一个bean上,也能够设定在特定的bean上。

解释不一样方式的自动装配,spring 自动装配 bean 有哪些方式?

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

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

  • no:默认的方式是不进行自动装配的,经过手工设置ref属性来进行装配bean。
  • byName:经过bean的名称进行自动装配,若是一个bean的 property 与另外一bean 的name 相同,就进行自动装配。
  • byType:经过参数的数据类型进行自动装配。
  • constructor:利用构造函数进行装配,而且构造函数的参数经过byType进行装配。
  • autodetect:自动探测,若是有构造方法,经过 construct的方式自动装配,不然使用 byType的方式自动装配。

使用@Autowired注解自动装配的过程是怎样的?

使用@Autowired注解来自动装配指定的bean。在使用@Autowired注解以前须要在Spring配置文件进行配置,<context:annotation-config />。

在启动spring IoC时,容器自动装载了一个AutowiredAnnotationBeanPostProcessor后置处理器,当容器扫描到@Autowied、@Resource或@Inject时,就会在IoC容器自动查找须要的bean,并装配给该对象的属性。在使用@Autowired时,首先在容器中查询对应类型的bean:

  • 若是查询结果恰好为一个,就将该bean装配给@Autowired指定的数据;
  • 若是查询的结果不止一个,那么@Autowired会根据名称来查找;
  • 若是上述查找的结果为空,那么会抛出异常。解决方法时,使用required=false。

自动装配有哪些局限性?

自动装配的局限性是:

重写:你仍需用 和 配置来定义依赖,意味着总要重写自动装配。

基本数据类型:你不能自动装配简单的属性,如基本数据类型,String字符串,和类。

模糊特性:自动装配不如显式装配精确,若是有可能,建议使用显式装配。

你能够在Spring中注入一个null 和一个空字符串吗?

能够。

Spring注解(8)

什么是基于Java的Spring注解配置? 给一些注解的例子

基于Java的配置,容许你在少许的Java注解的帮助下,进行你的大部分Spring配置而非经过XML文件。

以@Configuration 注解为例,它用来标记类能够当作一个bean的定义,被Spring IOC容器使用。

另外一个例子是@Bean注解,它表示此方法将要返回一个对象,做为一个bean注册进Spring应用上下文。

@Configuration
public class StudentConfig {
    @Bean
    public StudentBean myStudent() {
        return new StudentBean();
    }
}

怎样开启注解装配?

注解装配在默认状况下是不开启的,为了使用注解装配,咱们必须在Spring配置文件中配置 <context:annotation-config/>元素。

@Component, @Controller, @Repository, @Service 有何区别?

@Component:这将 java 类标记为 bean。它是任何 Spring 管理组件的通用构造型。spring 的组件扫描机制如今能够将其拾取并将其拉入应用程序环境中。

@Controller:这将一个类标记为 Spring Web MVC 控制器。标有它的 Bean 会自动导入到 IoC 容器中。

@Service:此注解是组件注解的特化。它不会对 @Component 注解提供任何其余行为。您能够在服务层类中使用 @Service 而不是 @Component,由于它以更好的方式指定了意图。

@Repository:这个注解是具备相似用途和功能的 @Component 注解的特化。它为 DAO 提供了额外的好处。它将 DAO 导入 IoC 容器,并使未经检查的异常有资格转换为 Spring DataAccessException。

@Required 注解有什么做用

这个注解代表bean的属性必须在配置的时候设置,经过一个bean定义的显式的属性值或经过自动装配,若@Required注解的bean属性未被设置,容器将抛出BeanInitializationException。示例:

public class Employee {
    private String name;
    @Required
    public void setName(String name){
        this.name=name;
    }
    public string getName(){
        return name;
    }
}

@Autowired 注解有什么做用

@Autowired默认是按照类型装配注入的,默认状况下它要求依赖对象必须存在(能够设置它required属性为false)。@Autowired 注解提供了更细粒度的控制,包括在何处以及如何完成自动装配。它的用法和@Required同样,修饰setter方法、构造器、属性或者具备任意名称和/或多个参数的PN方法。

public class Employee {
    private String name;
    @Autowired
    public void setName(String name) {
        this.name=name;
    }
    public string getName(){
        return name;
    }
}

@Autowired和@Resource之间的区别

@Autowired可用于:构造函数、成员变量、Setter方法

@Autowired和@Resource之间的区别

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

@Qualifier 注解有什么做用

当您建立多个相同类型的 bean 并但愿仅使用属性装配其中一个 bean 时,您可使用@Qualifier 注解和 @Autowired 经过指定应该装配哪一个确切的 bean 来消除歧义。

@RequestMapping 注解有什么用?

@RequestMapping 注解用于将特定 HTTP 请求方法映射到将处理相应请求的控制器中的特定类/方法。此注释可应用于两个级别:

  • 类级别:映射请求的 URL
  • 方法级别:映射 URL 以及 HTTP 请求方法

Spring数据访问(14)

解释对象/关系映射集成模块

Spring 经过提供ORM模块,支持咱们在直接JDBC之上使用一个对象/关系映射映射(ORM)工具,Spring 支持集成主流的ORM框架,如Hiberate,JDO和 iBATIS,JPA,TopLink,JDO,OJB 。Spring的事务管理一样支持以上全部ORM框架及JDBC。

在Spring框架中如何更有效地使用JDBC?

使用Spring JDBC 框架,资源管理和错误处理的代价都会被减轻。因此开发者只需写statements 和 queries从数据存取数据,JDBC也能够在Spring框架提供的模板类的帮助下更有效地被使用,这个模板叫JdbcTemplate

解释JDBC抽象和DAO模块

经过使用JDBC抽象和DAO模块,保证数据库代码的简洁,并能避免数据库资源错误关闭致使的问题,它在各类不一样的数据库的错误信息之上,提供了一个统一的异常访问层。它还利用Spring的AOP 模块给Spring应用中的对象提供事务管理服务。

spring DAO 有什么用?

Spring DAO(数据访问对象) 使得 JDBC,Hibernate 或 JDO 这样的数据访问技术更容易以一种统一的方式工做。这使得用户容易在持久性技术之间切换。它还容许您在编写代码时,无需考虑捕获每种技术不一样的异常。

spring JDBC API 中存在哪些类?

JdbcTemplate

SimpleJdbcTemplate

NamedParameterJdbcTemplate

SimpleJdbcInsert

SimpleJdbcCall

JdbcTemplate是什么

JdbcTemplate 类提供了不少便利的方法解决诸如把数据库数据转变成基本数据类型或对象,执行写好的或可调用的数据库操做语句,提供自定义的数据错误处理。

使用Spring经过什么方式访问Hibernate?使用 Spring 访问 Hibernate 的方法有哪些?

在Spring中有两种方式访问Hibernate:

  • 使用 Hibernate 模板和回调进行控制反转
  • 扩展 HibernateDAOSupport 并应用 AOP 拦截器节点

如何经过HibernateDaoSupport将Spring和Hibernate结合起来?

用Spring的 SessionFactory 调用 LocalSessionFactory。集成过程分三步:

  • 配置the Hibernate SessionFactory
  • 继承HibernateDaoSupport实现一个DAO
  • 在AOP支持的事务中装配

Spring支持的事务管理类型, spring 事务实现方式有哪些?

Spring支持两种类型的事务管理:

编程式事务管理:这意味你经过编程的方式管理事务,给你带来极大的灵活性,可是难维护。

声明式事务管理:这意味着你能够将业务代码和事务管理分离,你只需用注解和XML配置来管理事务。

Spring事务的实现方式和实现原理

Spring事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring是没法提供事务功能的。真正的数据库层的事务提交和回滚是经过binlog或者redo log实现的。

说一下Spring的事务传播行为

spring事务的传播行为说的是,当多个事务同时存在的时候,spring如何处理这些事务的行为。

① PROPAGATION_REQUIRED:若是当前没有事务,就建立一个新事务,若是当前存在事务,就加入该事务,该设置是最经常使用的设置。

② PROPAGATION_SUPPORTS:支持当前事务,若是当前存在事务,就加入该事务,若是当前不存在事务,就以非事务执行。

③ PROPAGATION_MANDATORY:支持当前事务,若是当前存在事务,就加入该事务,若是当前不存在事务,就抛出异常。

④ PROPAGATION_REQUIRES_NEW:建立新事务,不管当前存不存在事务,都建立新事务。

⑤ PROPAGATION_NOT_SUPPORTED:以非事务方式执行操做,若是当前存在事务,就把当前事务挂起。

⑥ PROPAGATION_NEVER:以非事务方式执行,若是当前存在事务,则抛出异常。

⑦ PROPAGATION_NESTED:若是当前存在事务,则在嵌套事务内执行。若是当前没有事务,则按REQUIRED属性执行。

说一下 spring 的事务隔离?

spring 有五大隔离级别,默认值为 ISOLATION_DEFAULT(使用数据库的设置),其余四个隔离级别和数据库的隔离级别一致:

  1. ISOLATION_DEFAULT:用底层数据库的设置隔离级别,数据库设置的是什么我就用什么;
  2. ISOLATION_READ_UNCOMMITTED:未提交读,最低隔离级别、事务未提交前,就可被其余事务读取(会出现幻读、脏读、不可重复读);
  3. ISOLATION_READ_COMMITTED:提交读,一个事务提交后才能被其余事务读取到(会形成幻读、不可重复读),SQL server 的默认级别;
  4. ISOLATION_REPEATABLE_READ:可重复读,保证屡次读取同一个数据时,其值都和事务开始时候的内容是一致,禁止读取到别的事务未提交的数据(会形成幻读),MySQL 的默认级别;
  5. ISOLATION_SERIALIZABLE:序列化,代价最高最可靠的隔离级别,该隔离级别能防止脏读、不可重复读、幻读。

脏读 :表示一个事务可以读取另外一个事务中还未提交的数据。好比,某个事务尝试插入记录 A,此时该事务还未提交,而后另外一个事务尝试读取到了记录 A。

不可重复读 :是指在一个事务内,屡次读同一数据。

幻读 :指同一个事务内屡次查询返回的结果集不同。好比同一个事务 A 第一次查询时候有 n 条记录,可是第二次同等条件下查询却有 n+1 条记录,这就好像产生了幻觉。发生幻读的缘由也是另一个事务新增或者删除或者修改了第一个事务结果集里面的数据,同一个记录的数据内容被修改了,全部数据行的记录就变多或者变少了。

Spring框架的事务管理有哪些优势?

  • 为不一样的事务API 如 JTA,JDBC,Hibernate,JPA 和JDO,提供一个不变的编程模式。
  • 为编程式事务管理提供了一套简单的API而不是一些复杂的事务API
  • 支持声明式事务管理。
  • 和Spring各类数据访问抽象层很好得集成。

你更倾向用那种事务管理类型?

大多数Spring框架的用户选择声明式事务管理,由于它对应用代码的影响最小,所以更符合一个无侵入的轻量级容器的思想。声明式事务管理要优于编程式事务管理,虽然比编程式事务管理(这种方式容许你经过代码控制事务)少了一点灵活性。惟一不足地方是,最细粒度只能做用到方法级别,没法作到像编程式事务那样能够做用到代码块级别。

Spring面向切面编程(AOP)(13)

什么是AOP

OOP(Object-Oriented Programming)面向对象编程,容许开发者定义纵向的关系,但并适用于定义横向的关系,致使了大量代码的重复,而不利于各个模块的重用。

AOP(Aspect-Oriented Programming),通常称为面向切面编程,做为面向对象的一种补充,用于将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块,这个模块被命名为“切面”(Aspect),减小系统中的重复代码,下降了模块间的耦合度,同时提升了系统的可维护性。可用于权限认证、日志、事务处理等。

Spring AOP and AspectJ AOP 有什么区别?AOP 有哪些实现方式?

AOP实现的关键在于 代理模式,AOP代理主要分为静态代理和动态代理。静态代理的表明为AspectJ;动态代理则以Spring AOP为表明。

(1)AspectJ是静态代理的加强,所谓静态代理,就是AOP框架会在编译阶段生成AOP代理类,所以也称为编译时加强,他会在编译阶段将AspectJ(切面)织入到Java字节码中,运行的时候就是加强以后的AOP对象。

(2)Spring AOP使用的动态代理,所谓的动态代理就是说AOP框架不会去修改字节码,而是每次运行时在内存中临时为方法生成一个AOP对象,这个AOP对象包含了目标对象的所有方法,而且在特定的切点作了加强处理,并回调原对象的方法。

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

Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理:

  • JDK动态代理只提供接口的代理,不支持类的代理。核心InvocationHandler接口和Proxy类,InvocationHandler 经过invoke()方法反射来调用目标类中的代码,动态地将横切逻辑和业务编织在一块儿;接着,Proxy利用 InvocationHandler动态建立一个符合某一接口的的实例, 生成目标类的代理对象。
  • 若是代理类没有实现 InvocationHandler 接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。CGLIB(Code Generation Library),是一个代码生成的类库,能够在运行时动态的生成指定类的一个子类对象,并覆盖其中特定方法并添加加强代码,从而实现AOP。CGLIB是经过继承的方式作的动态代理,所以若是某个类被标记为final,那么它是没法使用CGLIB作动态代理的。

静态代理与动态代理区别在于生成AOP代理对象的时机不一样,相对来讲AspectJ的静态代理方式具备更好的性能,可是AspectJ须要特定的编译器进行处理,而Spring AOP则无需特定的编译器处理。

InvocationHandler 的 invoke(Object proxy,Method method,Object[] args):proxy是最终生成的代理实例; method 是被代理目标实例的某个具体方法; args 是被代理目标实例某个方法的具体入参, 在方法反射调用时使用。

如何理解 Spring 中的代理?

将 Advice 应用于目标对象后建立的对象称为代理。在客户端对象的状况下,目标对象和代理对象是相同的。

Advice + Target Object = Proxy

解释一下Spring AOP里面的几个名词

(1)切面(Aspect):切面是通知和切点的结合。通知和切点共同定义了切面的所有内容。 在Spring AOP中,切面可使用通用类(基于模式的风格) 或者在普通类中以 @AspectJ 注解来实现。

(2)链接点(Join point):指方法,在Spring AOP中,一个链接点 老是 表明一个方法的执行。 应用可能有数以千计的时机应用通知。这些时机被称为链接点。链接点是在应用执行过程当中可以插入切面的一个点。这个点能够是调用方法时、抛出异常时、甚至修改一个字段时。切面代码能够利用这些点插入到应用的正常流程之中,并添加新的行为。

(3)通知(Advice):在AOP术语中,切面的工做被称为通知。

(4)切入点(Pointcut):切点的定义会匹配通知所要织入的一个或多个链接点。咱们一般使用明确的类和方法名称,或是利用正则表达式定义所匹配的类和方法名称来指定这些切点。

(5)引入(Introduction):引入容许咱们向现有类添加新方法或属性。

(6)目标对象(Target Object): 被一个或者多个切面(aspect)所通知(advise)的对象。它一般是一个代理对象。也有人把它叫作 被通知(adviced) 对象。 既然Spring AOP是经过运行时代理实现的,这个对象永远是一个 被代理(proxied) 对象。

(7)织入(Weaving):织入是把切面应用到目标对象并建立新的代理对象的过程。在目标对象的生命周期里有多少个点能够进行织入:

  • 编译期:切面在目标类编译时被织入。AspectJ的织入编译器是以这种方式织入切面的。
  • 类加载期:切面在目标类加载到JVM时被织入。须要特殊的类加载器,它能够在目标类被引入应用以前加强该目标类的字节码。AspectJ5的加载时织入就支持以这种方式织入切面。
  • 运行期:切面在应用运行的某个时刻被织入。通常状况下,在织入切面时,AOP容器会为目标对象动态地建立一个代理对象。SpringAOP就是以这种方式织入切面。

Spring在运行时通知对象

经过在代理类中包裹切面,Spring在运行期把切面织入到Spring管理的bean中。代理封装了目标类,并拦截被通知方法的调用,再把调用转发给真正的目标bean。当代理拦截到方法调用时,在调用目标bean方法以前,会执行切面逻辑。

直到应用须要被代理的bean时,Spring才建立代理对象。若是使用的是ApplicationContext的话,在ApplicationContext从BeanFactory中加载全部bean的时候,Spring才会建立被代理的对象。由于Spring运行时才建立代理对象,因此咱们不须要特殊的编译器来织入SpringAOP的切面。

Spring只支持方法级别的链接点

由于Spring基于动态代理,因此Spring只支持方法链接点。Spring缺乏对字段链接点的支持,并且它不支持构造器链接点。方法以外的链接点拦截功能,咱们能够利用Aspect来补充。

在Spring AOP 中,关注点和横切关注的区别是什么?在 spring aop 中 concern 和 cross-cutting concern 的不一样之处

关注点(concern)是应用中一个模块的行为,一个关注点可能会被定义成一个咱们想实现的一个功能。

横切关注点(cross-cutting concern)是一个关注点,此关注点是整个应用都会使用的功能,并影响整个应用,好比日志,安全和数据传输,几乎应用的每一个模块都须要的功能。所以这些都属于横切关注点。

Spring通知有哪些类型?

在AOP术语中,切面的工做被称为通知,其实是程序执行时要经过SpringAOP框架触发的代码段。

Spring切面能够应用5种类型的通知:

  1. 前置通知(Before):在目标方法被调用以前调用通知功能;
  2. 后置通知(After):在目标方法完成以后调用通知,此时不会关心方法的输出是什么;
  3. 返回通知(After-returning ):在目标方法成功执行以后调用通知;
  4. 异常通知(After-throwing):在目标方法抛出异常后调用通知;
  5. 环绕通知(Around):通知包裹了被通知的方法,在被通知的方法调用以前和调用以后执行自定义的行为。

img

同一个aspect,不一样advice的执行顺序:

①没有异常状况下的执行顺序:

around before advice
before advice
target method 执行
around after advice
after advice
afterReturning

②有异常状况下的执行顺序:

around before advice
before advice
target method 执行
around after advice
after advice
afterThrowing:异常发生
java.lang.RuntimeException: 异常发生

什么是切面 Aspect?

aspect 由 pointcount 和 advice 组成,切面是通知和切点的结合。 它既包含了横切逻辑的定义, 也包括了链接点的定义. Spring AOP 就是负责实施切面的框架, 它将切面所定义的横切逻辑编织到切面所指定的链接点中.
AOP 的工做重心在于如何将加强编织目标对象的链接点上, 这里包含两个工做:

  • 如何经过 pointcut 和 advice 定位到特定的 joinpoint 上
  • 如何在 advice 中编写切面代码.

能够简单地认为, 使用 @Aspect 注解的类就是切面.

在这里插入图片描述

解释基于XML Schema方式的切面实现

在这种状况下,切面由常规类以及基于XML的配置实现。

解释基于注解的切面实现

在这种状况下(基于@AspectJ的实现),涉及到的切面声明的风格与带有java5标注的普通java类一致。

有几种不一样类型的自动代理?

BeanNameAutoProxyCreator

DefaultAdvisorAutoProxyCreator

Metadata autoproxying

Spring MVC面试题 专题部分

什么是Spring MVC?简单介绍下你对Spring MVC的理解?

Spring MVC是一个基于Java的实现了MVC设计模式的请求驱动类型的轻量级Web框架,经过把模型-视图-控制器分离,将web层进行职责解耦,把复杂的web应用分红逻辑清晰的几部分,简化开发,减小出错,方便组内开发人员之间的配合。

Spring MVC的优势

(1)能够支持各类视图技术,而不只仅局限于JSP;

(2)与Spring框架集成(如IoC容器、AOP等);

(3)清晰的角色分配:前端控制器(dispatcherServlet) , 请求处处理器映射(handlerMapping), 处理器适配器(HandlerAdapter), 视图解析器(ViewResolver)。

(4) 支持各类请求资源的映射策略。

核心组件

Spring MVC的主要组件?

(1)前端控制器 DispatcherServlet(不须要程序员开发)

做用:接收请求、响应结果,至关于转发器,有了DispatcherServlet 就减小了其它组件之间的耦合度。

(2)处理器映射器HandlerMapping(不须要程序员开发)

做用:根据请求的URL来查找Handler

(3)处理器适配器HandlerAdapter

注意:在编写Handler的时候要按照HandlerAdapter要求的规则去编写,这样适配器HandlerAdapter才能够正确的去执行Handler。

(4)处理器Handler(须要程序员开发)

(5)视图解析器 ViewResolver(不须要程序员开发)

做用:进行视图的解析,根据视图逻辑名解析成真正的视图(view)

(6)视图View(须要程序员开发jsp)

View是一个接口, 它的实现类支持不一样的视图类型(jsp,freemarker,pdf等等)

什么是DispatcherServlet

Spring的MVC框架是围绕DispatcherServlet来设计的,它用来处理全部的HTTP请求和响应。

什么是Spring MVC框架的控制器?

控制器提供一个访问应用程序的行为,此行为一般经过服务接口实现。控制器解析用户输入并将其转换为一个由视图呈现给用户的模型。Spring用一个很是抽象的方式实现了一个控制层,容许用户建立多种用途的控制器。

Spring MVC的控制器是否是单例模式,若是是,有什么问题,怎么解决?

答:是单例模式,因此在多线程访问的时候有线程安全问题,不要用同步,会影响性能的,解决方案是在控制器里面不能写字段。

工做原理

请描述Spring MVC的工做流程?描述一下 DispatcherServlet 的工做流程?

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

img

MVC框架

MVC是什么?MVC设计模式的好处有哪些

mvc是一种设计模式(设计模式就是平常开发中编写代码的一种好的方法和经验的总结)。模型(model)-视图(view)-控制器(controller),三层架构的设计模式。用于实现前端页面的展示与后端业务数据处理的分离。

mvc设计模式的好处

1.分层设计,实现了业务系统各个组件之间的解耦,有利于业务系统的可扩展性,可维护性。

2.有利于系统的并行开发,提高开发效率。

经常使用注解

注解原理是什么

注解本质是一个继承了Annotation的特殊接口,其具体实现类是Java运行时生成的动态代理类。咱们经过反射获取注解时,返回的是Java运行时生成的动态代理对象。经过代理对象调用自定义注解的方法,会最终调用AnnotationInvocationHandler的invoke方法。该方法会从memberValues这个Map中索引出对应的值。而memberValues的来源是Java常量池。

Spring MVC经常使用的注解有哪些?

@RequestMapping:用于处理请求 url 映射的注解,可用于类或方法上。用于类上,则表示类中的全部响应请求的方法都是以该地址做为父路径。

@RequestBody:注解实现接收http请求的json数据,将json转换为java对象。

@ResponseBody:注解实现将conreoller方法返回对象转化为json对象响应给客户。

SpingMvc中的控制器的注解通常用哪一个,有没有别的注解能够替代?

答:通常用@Controller注解,也可使用@RestController,@RestController注解至关于@ResponseBody + @Controller,表示是表现层,除此以外,通常不用别的注解代替。

@Controller注解的做用

在Spring MVC 中,控制器Controller 负责处理由DispatcherServlet 分发的请求,它把用户请求的数据通过业务处理层处理以后封装成一个Model ,而后再把该Model 返回给对应的View 进行展现。在Spring MVC 中提供了一个很是简便的定义Controller 的方法,你无需继承特定的类或实现特定的接口,只需使用@Controller 标记一个类是Controller ,而后使用@RequestMapping 和@RequestParam 等一些注解用以定义URL 请求和Controller 方法之间的映射,这样的Controller 就能被外界访问到。此外Controller 不会直接依赖于HttpServletRequest 和HttpServletResponse 等HttpServlet 对象,它们能够经过Controller 的方法参数灵活的获取到。

@Controller 用于标记在一个类上,使用它标记的类就是一个Spring MVC Controller 对象。分发处理器将会扫描使用了该注解的类的方法,并检测该方法是否使用了@RequestMapping 注解。@Controller 只是定义了一个控制器类,而使用@RequestMapping 注解的方法才是真正处理请求的处理器。单单使用@Controller 标记在一个类上还不能真正意义上的说它就是Spring MVC 的一个控制器类,由于这个时候Spring 还不认识它。那么要如何作Spring 才能认识它呢?这个时候就须要咱们把这个控制器类交给Spring 来管理。有两种方式:

  • 在Spring MVC 的配置文件中定义MyController 的bean 对象。
  • 在Spring MVC 的配置文件中告诉Spring 该到哪里去找标记为@Controller 的Controller 控制器。

@RequestMapping注解的做用

RequestMapping是一个用来处理请求地址映射的注解,可用于类或方法上。用于类上,表示类中的全部响应请求的方法都是以该地址做为父路径。

RequestMapping注解有六个属性,下面咱们把她分红三类进行说明(下面有相应示例)。

value, method

value: 指定请求的实际地址,指定的地址能够是URI Template 模式(后面将会说明);

method: 指定请求的method类型, GET、POST、PUT、DELETE等;

consumes,produces

consumes: 指定处理请求的提交内容类型(Content-Type),例如application/json, text/html;

produces: 指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回;

params,headers

params: 指定request中必须包含某些参数值是,才让该方法处理。

headers: 指定request中必须包含某些指定的header值,才能让该方法处理请求。

@ResponseBody注解的做用

做用: 该注解用于将Controller的方法返回的对象,经过适当的HttpMessageConverter转换为指定格式后,写入到Response对象的body数据区。

使用时机:返回的数据不是html标签的页面,而是其余某种格式的数据时(如json、xml等)使用;

@PathVariable和@RequestParam的区别

请求路径上有个id的变量值,能够经过@PathVariable来获取 @RequestMapping(value = “/page/{id}”, method = RequestMethod.GET)

@RequestParam用来得到静态的URL请求入参 spring注解时action里用到。

其余

Spring MVC与Struts2区别

相同点

都是基于mvc的表现层框架,都用于web项目的开发。

不一样点

1.前端控制器不同。Spring MVC的前端控制器是servlet:DispatcherServlet。struts2的前端控制器是filter:StrutsPreparedAndExcutorFilter。

2.请求参数的接收方式不同。Spring MVC是使用方法的形参接收请求的参数,基于方法的开发,线程安全,能够设计为单例或者多例的开发,推荐使用单例模式的开发(执行效率更高),默认就是单例开发模式。struts2是经过类的成员变量接收请求的参数,是基于类的开发,线程不安全,只能设计为多例的开发。

3.Struts采用值栈存储请求和响应的数据,经过OGNL存取数据,Spring MVC经过参数解析器是将request请求内容解析,并给方法形参赋值,将数据和视图封装成ModelAndView对象,最后又将ModelAndView中的模型数据经过reques域传输到页面。Jsp视图解析器默认使用jstl。

4.与spring整合不同。Spring MVC是spring框架的一部分,不须要整合。在企业项目中,Spring MVC使用更多一些。

Spring MVC怎么样设定重定向和转发的?

(1)转发:在返回值前面加"forward:",譬如"forward:user.do?name=method4"

(2)重定向:在返回值前面加"redirect:",譬如"redirect:http://www.baidu.com"

Spring MVC怎么和AJAX相互调用的?

经过Jackson框架就能够把Java里面的对象直接转化成Js能够识别的Json对象。具体步骤以下 :

(1)加入Jackson.jar

(2)在配置文件中配置json的映射

(3)在接受Ajax方法里面能够直接返回Object,List等,但方法前面要加上@ResponseBody注解。

如何解决POST请求中文乱码问题,GET的又如何处理呢?

(1)解决post请求乱码问题:

在web.xml中配置一个CharacterEncodingFilter过滤器,设置成utf-8;

<filter>
    <filter-name>CharacterEncodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>

    <init-param>
        <param-name>encoding</param-name>
        <param-value>utf-8</param-value>
    </init-param>
</filter>

<filter-mapping>
    <filter-name>CharacterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

(2)get请求中文参数出现乱码解决方法有两个:

①修改tomcat配置文件添加编码与工程编码一致,以下:

<ConnectorURIEncoding="utf-8" connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>

②另一种方法对参数进行从新编码:

String userName = new String(request.getParamter(“userName”).getBytes(“ISO8859-1”),“utf-8”)

ISO8859-1是tomcat默认编码,须要将tomcat编码后的内容按utf-8编码。

Spring MVC的异常处理?

答:能够将异常抛给Spring框架,由Spring框架来处理;咱们只须要配置简单的异常处理器,在异常处理器中添视图页面便可。

若是在拦截请求中,我想拦截get方式提交的方法,怎么配置

答:能够在@RequestMapping注解里面加上method=RequestMethod.GET。

怎样在方法里面获得Request,或者Session?

答:直接在方法的形参中声明request,Spring MVC就自动把request对象传入。

若是想在拦截的方法里面获得从前台传入的参数,怎么获得?

答:直接在形参里面声明这个参数就能够,但必须名字和传过来的参数同样。

若是前台有不少个参数传入,而且这些参数都是一个对象的,那么怎么样快速获得这个对象?

答:直接在方法中声明这个对象,Spring MVC就自动会把属性赋值到这个对象里面。

Spring MVC中函数的返回值是什么?

答:返回值能够有不少类型,有String, ModelAndView。ModelAndView类把视图和数据都合并的一块儿的,但通常用String比较好。

Spring MVC用什么对象从后台向前台传递数据的?

答:经过ModelMap对象,能够在这个对象里面调用put方法,把对象加到里面,前台就能够经过el表达式拿到。

怎么样把ModelMap里面的数据放入Session里面?

答:能够在类上面加上@SessionAttributes注解,里面包含的字符串就是要放入session里面的key。

Spring MVC里面拦截器是怎么写的

有两种写法,一种是实现HandlerInterceptor接口,另一种是继承适配器类,接着在接口方法当中,实现处理逻辑;而后在Spring MVC的配置文件中配置拦截器便可:

<!-- 配置Spring MVC的拦截器 -->
<mvc:interceptors>
    <!-- 配置一个拦截器的Bean就能够了 默认是对全部请求都拦截 -->
    <bean id="myInterceptor" class="com.zwp.action.MyHandlerInterceptor"></bean>
    <!-- 只针对部分请求拦截 -->
    <mvc:interceptor>
       <mvc:mapping path="/modelMap.do" />
       <bean class="com.zwp.action.MyHandlerInterceptorAdapter" />
    </mvc:interceptor>
</mvc:interceptors>

介绍一下 WebApplicationContext

WebApplicationContext 继承了ApplicationContext 并增长了一些WEB应用必备的特有功能,它不一样于通常的ApplicationContext ,由于它能处理主题,并找到被关联的servlet。

Tomcat 专题 部分

Tomcat是什么?

Tomcat 服务器Apache软件基金会项目中的一个核心项目,是一个免费的开放源代码的Web 应用服务器,属于轻量级应用服务器,在中小型系统和并发访问用户不是不少的场合下被广泛使用,是开发和调试JSP 程序的首选。

Tomcat的缺省端口是多少,怎么修改

  1. 找到Tomcat目录下的conf文件夹
  2. 进入conf文件夹里面找到server.xml文件
  3. 打开server.xml文件
  4. 在server.xml文件里面找到下列信息
  5. 把Connector标签的8080端口改为你想要的端口
<Service name="Catalina">
<Connector port="8080" protocol="HTTP/1.1" 
               connectionTimeout="20000" 
               redirectPort="8443" />

tomcat 有哪几种Connector 运行模式(优化)?

下面,咱们先大体了解Tomcat Connector的三种运行模式。

  • BIO:同步并阻塞 一个线程处理一个请求。缺点:并发量高时,线程数较多,浪费资源。Tomcat7或如下,在Linux系统中默认使用这种方式。

配制项:protocol=”HTTP/1.1”

  • NIO:同步非阻塞IO

    利用Java的异步IO处理,能够经过少许的线程处理大量的请求,能够复用同一个线程处理多个connection(多路复用)。

    Tomcat8在Linux系统中默认使用这种方式。

    Tomcat7必须修改Connector配置来启动。

    配制项:protocol=”org.apache.coyote.http11.Http11NioProtocol”

    备注:咱们经常使用的Jetty,Mina,ZooKeeper等都是基于java nio实现.

  • APR:即Apache Portable Runtime,从操做系统层面解决io阻塞问题。AIO方式,****异步非阻塞IO(Java NIO2又叫AIO) 主要与NIO的区别主要是操做系统的底层区别.能够作个比喻:比做快递,NIO就是网购后要本身到官网查下快递是否已经到了(多是屡次),而后本身去取快递;AIO就是快递员送货上门了(不用关注快递进度)。

    配制项:protocol=”org.apache.coyote.http11.Http11AprProtocol”

    备注:需在本地服务器安装APR库。Tomcat7或Tomcat8在Win7或以上的系统中启动默认使用这种方式。Linux若是安装了apr和native,Tomcat直接启动就支持apr。

Tomcat有几种部署方式?

在Tomcat中部署Web应用的方式主要有以下几种:

  1. 利用Tomcat的自动部署。

    把web应用拷贝到webapps目录。Tomcat在启动时会加载目录下的应用,并将编译后的结果放入work目录下。

  2. 使用Manager App控制台部署。

    在tomcat主页点击“Manager App” 进入应用管理控制台,能够指定一个web应用的路径或war文件。

  3. 修改conf/server.xml文件部署。

    修改conf/server.xml文件,增长Context节点能够部署应用。

  4. 增长自定义的Web部署文件。

    在conf/Catalina/localhost/ 路径下增长 xyz.xml文件,内容是Context节点,能够部署应用。

tomcat容器是如何建立servlet类实例?用到了什么原理?

  1. 当容器启动时,会读取在webapps目录下全部的web应用中的web.xml文件,而后对 xml文件进行解析,并读取servlet注册信息。而后,将每一个应用中注册的servlet类都进行加载,并经过 反射的方式实例化。(有时候也是在第一次请求时实例化)
  2. 在servlet注册时加上1若是为正数,则在一开始就实例化,若是不写或为负数,则第一次请求实例化。

Tomcat工做模式

Tomcat做为servlet容器,有三种工做模式:

  • 一、独立的servlet容器,servlet容器是web服务器的一部分;
  • 二、进程内的servlet容器,servlet容器是做为web服务器的插件和java容器的实现,web服务器插件在内部地址空间打开一个jvm使得java容器在内部得以运行。反应速度快但伸缩性不足;
  • 三、进程外的servlet容器,servlet容器运行于web服务器以外的地址空间,并做为web服务器的插件和java容器实现的结合。反应时间不如进程内但伸缩性和稳定性比进程内优;

进入Tomcat的请求能够根据Tomcat的工做模式分为以下两类:

  • Tomcat做为应用程序服务器:请求来自于前端的web服务器,这多是Apache, IIS, Nginx等;
  • Tomcat做为独立服务器:请求来自于web浏览器;

面试时问到Tomcat相关问题的概率并不高,正式由于如此,不少人忽略了对Tomcat相关技能的掌握,下面这一篇文章整理了Tomcat相关的系统架构,介绍了Server、Service、Connector、Container之间的关系,各个模块的功能,能够说把这几个掌握住了,Tomcat相关的面试题你就不会有任何问题了!另外,在面试的时候你还要有意识无心识的往Tomcat这个地方引,就好比说常见的Spring MVC的执行流程,一个URL的完整调用链路,这些相关的题目你是能够往Tomcat处理请求的这个过程去说的!掌握了Tomcat这些技能,面试官必定会佩服你的!

学了本章以后你应该明白的是:

  • Server、Service、Connector、Container四大组件之间的关系和联系,以及他们的主要功能点;
  • Tomcat执行的总体架构,请求是如何被一步步处理的;
  • Engine、Host、Context、Wrapper相关的概念关系;
  • Container是如何处理请求的;
  • Tomcat用到的相关设计模式;

Tomcat顶层架构

俗话说,站在巨人的肩膀上看世界,通常学习的时候也是先总览一下总体,而后逐个部分个个击破,最后造成思路,了解具体细节,Tomcat的结构很复杂,可是 Tomcat 很是的模块化,找到了 Tomcat 最核心的模块,问题才能够游刃而解,了解了 Tomcat 的总体架构对之后深刻了解 Tomcat 来讲相当重要!

先上一张Tomcat的顶层结构图(图A),以下:

在这里插入图片描述

Tomcat中最顶层的容器是Server,表明着整个服务器,从上图中能够看出,一个Server能够包含至少一个Service,便可以包含多个Service,用于具体提供服务。

Service主要包含两个部分:Connector和Container。从上图中能够看出 Tomcat 的心脏就是这两个组件,他们的做用以下:

  • Connector用于处理链接相关的事情,并提供Socket与Request请求和Response响应相关的转化;
  • Container用于封装和管理Servlet,以及具体处理Request请求;

一个Tomcat中只有一个Server,一个Server能够包含多个Service,一个Service只有一个Container,可是能够有多个Connectors,这是由于一个服务能够有多个链接,如同时提供Http和Https连接,也能够提供向相同协议不一样端口的链接,示意图以下(Engine、Host、Context下面会说到):

在这里插入图片描述

多个 Connector 和一个 Container 就造成了一个 Service,有了 Service 就能够对外提供服务了,可是 Service 还要一个生存的环境,必需要有人可以给她生命、掌握其生死大权,那就非 Server 莫属了!因此整个 Tomcat 的生命周期由 Server 控制。

另外,上述的包含关系或者说是父子关系,均可以在tomcat的conf目录下的server.xml配置文件中看出,下图是删除了注释内容以后的一个完整的server.xml配置文件(Tomcat版本为8.0)

在这里插入图片描述

详细的配置文件内容能够到Tomcat官网查看:Tomcat配置文件

上边的配置文件,还能够经过下边的一张结构图更清楚的理解:

在这里插入图片描述

Server标签设置的端口号为8005,shutdown=”SHUTDOWN” ,表示在8005端口监听“SHUTDOWN”命令,若是接收到了就会关闭Tomcat。一个Server有一个Service,固然还能够进行配置,一个Service有多个Connector,Service左边的内容都属于Container的,Service下边是Connector。

Tomcat顶层架构小结

  1. Tomcat中只有一个Server,一个Server能够有多个Service,一个Service能够有多个Connector和一个Container;
  2. Server掌管着整个Tomcat的生死大权;
  3. Service 是对外提供服务的;
  4. Connector用于接受请求并将请求封装成Request和Response来具体处理;
  5. Container用于封装和管理Servlet,以及具体处理request请求;

知道了整个Tomcat顶层的分层架构和各个组件之间的关系以及做用,对于绝大多数的开发人员来讲Server和Service对咱们来讲确实很远,而咱们开发中绝大部分进行配置的内容是属于Connector和Container的,因此接下来介绍一下Connector和Container。

Connector和Container的微妙关系

由上述内容咱们大体能够知道一个请求发送到Tomcat以后,首先通过Service而后会交给咱们的Connector,Connector用于接收请求并将接收的请求封装为Request和Response来具体处理,Request和Response封装完以后再交由Container进行处理,Container处理完请求以后再返回给Connector,最后在由Connector经过Socket将处理的结果返回给客户端,这样整个请求的就处理完了!

Connector最底层使用的是Socket来进行链接的,Request和Response是按照HTTP协议来封装的,因此Connector同时须要实现TCP/IP协议和HTTP协议!

Tomcat既然须要处理请求,那么确定须要先接收到这个请求,接收请求这个东西咱们首先就须要看一下Connector!

Connector架构分析

Connector用于接受请求并将请求封装成Request和Response,而后交给Container进行处理,Container处理完以后在交给Connector返回给客户端。

所以,咱们能够把Connector分为四个方面进行理解:

  1. Connector如何接受请求的?
  2. 如何将请求封装成Request和Response的?
  3. 封装完以后的Request和Response如何交给Container进行处理的?
  4. Container处理完以后如何交给Connector并返回给客户端的?

首先看一下Connector的结构图(图B),以下所示:

在这里插入图片描述

Connector就是使用ProtocolHandler来处理请求的,不一样的ProtocolHandler表明不一样的链接类型,好比:Http11Protocol使用的是普通Socket来链接的,Http11NioProtocol使用的是NioSocket来链接的。

其中ProtocolHandler由包含了三个部件:Endpoint、Processor、Adapter。

  1. Endpoint用来处理底层Socket的网络链接,Processor用于将Endpoint接收到的Socket封装成Request,Adapter用于将Request交给Container进行具体的处理。
  2. Endpoint因为是处理底层的Socket网络链接,所以Endpoint是用来实现TCP/IP协议的,而Processor用来实现HTTP协议的,Adapter将请求适配到Servlet容器进行具体的处理。
  3. Endpoint的抽象实现AbstractEndpoint里面定义的Acceptor和AsyncTimeout两个内部类和一个Handler接口。Acceptor用于监听请求,AsyncTimeout用于检查异步Request的超时,Handler用于处理接收到的Socket,在内部调用Processor进行处理。

至此,咱们应该很轻松的回答1,2,3的问题了,可是4仍是不知道,那么咱们就来看一下Container是如何进行处理的以及处理完以后是如何将处理完的结果返回给Connector的?

Container架构分析

Container用于封装和管理Servlet,以及具体处理Request请求,在Container内部包含了4个子容器,结构图以下(图C):

在这里插入图片描述

4个子容器的做用分别是:

  1. Engine:引擎,用来管理多个站点,一个Service最多只能有一个Engine;
  2. Host:表明一个站点,也能够叫虚拟主机,经过配置Host就能够添加站点;
  3. Context:表明一个应用程序,对应着平时开发的一套程序,或者一个WEB-INF目录以及下面的web.xml文件;
  4. Wrapper:每一Wrapper封装着一个Servlet;

下面找一个Tomcat的文件目录对照一下,以下图所示:

在这里插入图片描述

Context和Host的区别是Context表示一个应用,咱们的Tomcat中默认的配置下webapps下的每个文件夹目录都是一个Context,其中ROOT目录中存放着主应用,其余目录存放着子应用,而整个webapps就是一个Host站点。

咱们访问应用Context的时候,若是是ROOT下的则直接使用域名就能够访问,例如:www.baidu.com,若是是Host(webapps)下的其余应用,则可使用www.baidu.com/docs进行访问,固然默认指定的根应用(ROOT)是能够进行设定的,只不过Host站点下默认的主应用是ROOT目录下的。

看到这里咱们知道Container是什么,可是仍是不知道Container是如何进行请求处理的以及处理完以后是如何将处理完的结果返回给Connector的?别急!下边就开始探讨一下Container是如何进行处理的!

Container如何处理请求的

Container处理请求是使用Pipeline-Valve管道来处理的!(Valve是阀门之意)

Pipeline-Valve是责任链模式,责任链模式是指在一个请求处理的过程当中有不少处理者依次对请求进行处理,每一个处理者负责作本身相应的处理,处理完以后将处理后的结果返回,再让下一个处理者继续处理。

在这里插入图片描述

可是!Pipeline-Valve使用的责任链模式和普通的责任链模式有些不一样!区别主要有如下两点:

  • 每一个Pipeline都有特定的Valve,并且是在管道的最后一个执行,这个Valve叫作BaseValve,BaseValve是不可删除的;
  • 在上层容器的管道的BaseValve中会调用下层容器的管道。

咱们知道Container包含四个子容器,而这四个子容器对应的BaseValve分别在:StandardEngineValve、StandardHostValve、StandardContextValve、StandardWrapperValve。

Pipeline的处理流程图以下(图D):

在这里插入图片描述

  • Connector在接收到请求后会首先调用最顶层容器的Pipeline来处理,这里的最顶层容器的Pipeline就是EnginePipeline(Engine的管道);
  • 在Engine的管道中依次会执行EngineValve一、EngineValve2等等,最后会执行StandardEngineValve,在StandardEngineValve中会调用Host管道,而后再依次执行Host的HostValve一、HostValve2等,最后在执行StandardHostValve,而后再依次调用Context的管道和Wrapper的管道,最后执行到StandardWrapperValve。
  • 当执行到StandardWrapperValve的时候,会在StandardWrapperValve中建立FilterChain,并调用其doFilter方法来处理请求,这个FilterChain包含着咱们配置的与请求相匹配的Filter和Servlet,其doFilter方法会依次调用全部的Filter的doFilter方法和Servlet的service方法,这样请求就获得了处理!
  • 当全部的Pipeline-Valve都执行完以后,而且处理完了具体的请求,这个时候就能够将返回的结果交给Connector了,Connector在经过Socket的方式将结果返回给客户端。