Java 面试题之 Spring 部分

Spring

1.1.描述一下 Spring 框架的作用和优点?

1)Spring 是一个开源的轻量级的应用开发框架,其目的是用于简化企业级应用程序开发,减少侵入;

2)Spring 提供的 IOC 和 AOP 应用,可以将组件的耦合度降至最低,即解耦,便于系统日后的维护和升级;

3)Spring 为系统提供了一个整体的解决方案,开发者可以利用它本身提供的功能外,也可以与第三方框架和技术整合应用,可以自由选择采用哪种技术进行开发。

 

1.2.如何控制 Bean 对象的作用域,默认的作用域是什么?

1)可以通过 <bean> 定义的 scope 属性指定 Bean 对象的作用域,或者通过注解的形式 @scope 指定 Bean 对象的作用域。

2)默认 Bean 的作用域为 singleton。singleton 作用域是 spring 的缺省作用域,singleton 是单例类型,在创建容器时就会自动创建一个 bean 的对象,无论你是否使用,它都存在,且每次获取的对象都是同一个对象。如下图所示:

<bean id="..." class="..." scope="singleton">
</bean>

3)prototype 是原型类型,在创建容器时没有实例化,每次获取 bean 时都会创建一个新的对象。根据经验,对有状态的 bean 应该使用 prototype 作用域,对无状态的 bean 应该使用 singleton 作用域。如下图所示:

<bean id="..." class="..." scope="prototype">
...
</bean>

4)Bean 的生命周期一般为创建、初始化、使用、销毁,在创建(init)前后,可使用后置处理器 BeanPostProcessor 实现更复杂的逻辑。ApplicationContext 会自动扫描 BeanPostProcessor 接口实现的 bean,注册这些 bean 为后置处理器,然后通过在容器中创建 bean,在适当的时候去调用它。

 

1.3.描述常见注解及其作用?

1)@Component 为通用注解;

2)@Repository 为持久层组件注解;

3)@Service 为业务层组件注解;

4)@Scope 为 Bean 的作用域注解;

5)@Autowired 和 @Inject 为指定 Bean 之间依赖关系的注解;

6)@Value 为注入 Spring 表达式值的注解。

 

1.4.描述 Spring Web MVC 的工作流程?

1)浏览器发出 Spring MVC 请求后,请求交给前端控制器 DispacherServlet 处理。

2)控制器通过 HandlerMapping 维护的请求和 Controller 映射信息,找到相应的 Controller 组件处理请求。

3)执行 Controller 组件约束方法处理请求,在约束方法中可以调用 Service 和 DAO 等组件完成数据库操作。约束方法可以返回一个 ModelAndView 对象,封装了模型数据和视图名称信息。

4)控制器接收 ModelAndView 之后,调用 ViewResolver 组件,定位 View 的 JSP 并传递 Model 信息,生成响应界面结果。

 

1.5.Spring 有哪些缺点?

1)JSP 中需要写很多的代码;

2)控制器过于灵活,没有一个公共的控制器;

3)不支持分布式部署。

 

1.6.Spring 中的 IOC 和 AOP 是什么含义?

IOC:控制反转,是一种设计模式。一层含义是控制权的转移:由传统的在程序中控制依赖转移到由容器控制依赖;第二层是依赖注入:将相互依赖的对象分离,在 Spring 配置文件中描述他们的依赖关系。他们的依赖关系只有在使用时才建立。

AOP:面向切面,是一种编程思想,OOP 的延续。将系统中的非核心的业务提取出来,进行单独处理。

Spring 中的 IOC 和 AOP 都是为了解决系统代码耦合度过高的问题,使代码重用度高、易于维护。比如事务、日志、安全等。

 

1.7.简述 Spring 事务共有几种管理方式?

编程式事务(代码中嵌入)和声明式事务(利用注解方式,XML)

 

1.8.简述事务拦截器的原理?

Spring 中的事务拦截器是通过 AOP 代理来实现的。对被代理的每个方法进行拦截,在方法执行前启动事务,方法执行后根据是否有异常和异常的种类进行提交或回滚。

 

1.9.Spring 中的 Bean 有哪些作用域?

1)singleton:Spring IOC 容器只会创建该 Bean 的唯一实例;

2)prototype:每次请求都会创建一个实例;

3)request:每次 http 都会生成一个新的 Bean。需要注意的是该作用域仅在基于 Web 的 ApplicationContext 情形下有效,以下的 session 和 global Session 也是如此;

4)session:每次会话创建一个实例;

5)global session:全局的 HttpSession 中,容器会返回 bean 的同一个实例。

 

1.10.Spring 提倡面向接口编程,请讲一下对它的理解?

在一个对象对象的系统中,系统中的各种功能是由许许多多的不同的对象协作完成的。基于这样的一个事实,对象内部是如何实现的,对于系统设计人员来讲就不那么重要了;而各个对象之间的协作关系成为系统设计的关键。小到不同类之间的通信,大到各模块之间的交互,在系统设计之初都是要着重考虑的,这也是系统设计的主要工作内容。面向接口编程就是按照这种思想来编程。

 

1.11.谈谈你对用 SSH 框架进行开发的理解?

SSH 框架指的是 Struts、Spring、Hibernate。其中,Struts 主要用于流程控制;Spring 的控制反转起到解耦合额作用;Hibernate 主要用于数据持久化。

 

1.12.简述 Spring IOC 和 AOP?

IOC 控制反转就是将某一接口具体实现类的控制从调用类移除,转交给第三方,即 Spring 容器;

在业务系统中除了要实现业务代码外,还是实现权限拦截、性能监控、事务管理等非业务功能。通常的做法是将非业务代码穿插在业务代码中,从而导致业务组件和非业务组件的耦合。AOP 面向切面编程,就是将这些分散在各个业务逻辑代码中的非业务代码,通过横向切割的方式抽取到一个独立的模块中,从而实现业务组件与非业务组件的解耦。

 

1.13.什么是 Spring bean 定义继承?

bean 定义可以包含很多的配置信息,包括构造函数的参数、属性值、容器的具体信息,如初始化方法、静态工厂方法名等。

子 bean 的定义可以继承父 bean 的配置数据,自定义可以根据需要重写一些值或者添加其他值。Spring bean 的继承与 java 类的继承无关,但是继承的概念是一样的,定义一个父 bean 作为模板,其他子 bean 可以从父 bean 中继承所需要的配置。

<bean id="helloWorld" class="com.tutorialspoint.HelloWorld">
      <property name="message1" value="Hello World!"/>
      <property name="message2" value="Hello Second World!"/>
</bean>

<bean id="helloIndia" class="com.tutorialspoint.HelloIndia" parent="helloWorld">
      <property name="message1" value="Hello India!"/>
      <property name="message3" value="Namaste India!"/>
</bean>

这里是 HelloWorld.java 文件的内容:

package com.tutorialspoint;
public class HelloWorld {
   private String message1;
   private String message2;
   public void setMessage1(String message){
      this.message1  = message;
   }
   public void setMessage2(String message){
      this.message2  = message;
   }
   public void getMessage1(){
      System.out.println("World Message1 : " + message1);
   }
   public void getMessage2(){
      System.out.println("World Message2 : " + message2);
   }
}

这里是 HelloIndia.java 文件的内容:

package com.tutorialspoint;

public class HelloIndia {
   private String message1;
   private String message2;
   private String message3;

   public void setMessage1(String message){
      this.message1  = message;
   }

   public void setMessage2(String message){
      this.message2  = message;
   }

   public void setMessage3(String message){
      this.message3  = message;
   }

   public void getMessage1(){
      System.out.println("India Message1 : " + message1);
   }

   public void getMessage2(){
      System.out.println("India Message2 : " + message2);
   }

   public void getMessage3(){
      System.out.println("India Message3 : " + message3);
   }
}

下面是 MainApp.java 文件的内容:

package com.tutorialspoint;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {
   public static void main(String[] args) {
      ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");

      HelloWorld objA = (HelloWorld) context.getBean("helloWorld");

      objA.getMessage1();
      objA.getMessage2();

      HelloIndia objB = (HelloIndia) context.getBean("helloIndia");
      objB.getMessage1();
      objB.getMessage2();
      objB.getMessage3();
   }
}

一旦你创建源代码和 bean 配置文件完成后,我们就可以运行该应用程序。如果你的应用程序一切都正常,将输出以下信息:

World Message1 : Hello World!
World Message2 : Hello Second World!
India Message1 : Hello India!
India Message2 : Hello Second World!
India Message3 : Namaste India!

在这里你可以观察到,我们创建 “helloIndia” bean 的同时并没有传递 message2,但是由于 Bean 定义的继承,所以它传递了 message2。

 

1.14.什么是 Bean 定义模板?

你可以创建一个 Bean 定义模板,不需要花太多功夫它就可以被其他子 bean 定义使用。在定义一个 Bean 定义模板时,你不应该指定的属性,而应该指定带 true 值的抽象属性,如下所示:

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

   <bean id="beanTeamplate" abstract="true">
      <property name="message1" value="Hello World!"/>
      <property name="message2" value="Hello Second World!"/>
      <property name="message3" value="Namaste India!"/>
   </bean>

   <bean id="helloIndia" class="com.tutorialspoint.HelloIndia" parent="beanTeamplate">
      <property name="message1" value="Hello India!"/>
      <property name="message3" value="Namaste India!"/>
   </bean>

</beans>

父 bean 自身不能被实例化,因为它是不完整的,而且它也被明确地标记为抽象的。当一个定义是抽象的,它仅仅作为一个纯粹的模板 bean 定义来使用的,充当子定义的父定义使用。

 

1.15.什么是基于构造函数的依赖注入?

当容器调用带有一组参数的类构造函数时,基于构造函数的 DI 就完成了,其中每个参数代表一个对其他类的依赖。

接下来,我们将通过示例来理解 Spring 基于构造函数的依赖注入。

这是 TextEditor.java 文件的内容:

package com.tutorialspoint;
public class TextEditor {
   private SpellChecker spellChecker;
   public TextEditor(SpellChecker spellChecker) {
      System.out.println("Inside TextEditor constructor." );
      this.spellChecker = spellChecker;
   }
   public void spellCheck() {
      spellChecker.checkSpelling();
   }
}

下面是另一个依赖类文件 SpellChecker.java 的内容:

package com.tutorialspoint;
public class SpellChecker {
   public SpellChecker(){
      System.out.println("Inside SpellChecker constructor." );
   }
   public void checkSpelling() {
      System.out.println("Inside checkSpelling." );
   } 
}

以下是 MainApp.java 文件的内容:

package com.tutorialspoint;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainApp {
   public static void main(String[] args) {
      ApplicationContext context = 
             new ClassPathXmlApplicationContext("Beans.xml");
      TextEditor te = (TextEditor) context.getBean("textEditor");
      te.spellCheck();
   }
}

下面是配置文件 Beans.xml 的内容,它有基于构造函数注入的配置:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

   <!-- Definition for textEditor bean -->
   <bean id="textEditor" class="com.tutorialspoint.TextEditor">
      <constructor-arg ref="spellChecker"/>
   </bean>

   <!-- Definition for spellChecker bean -->
   <bean id="spellChecker" class="com.tutorialspoint.SpellChecker">
   </bean>

</beans>

当你完成了创建源和 bean 配置文件后,让我们开始运行应用程序。如果你的应用程序运行顺利的话,那么将会输出下述所示消息:

Inside SpellChecker constructor.
Inside TextEditor constructor.
Inside checkSpelling.

1.16.什么是 Spring Beans 自动装配?

Spring 容器可以在不使用 <constructor-arg>和 <property>元素的情况下自动装配相互协作的 bean 之间的关系,这有助于减少编写一个大的基于 Spring 的应用程序的 XML 配置的数量。 

下列自动装配模式,它们可用于指示 Spring 容器为来使用自动装配进行依赖注入。你可以使用<bean>元素的 autowire 属性为一个 bean 定义指定自动装配模式。

模式描述
no这是默认的设置,它意味着没有自动装配,你应该使用显式的bean引用来连线。你不用为了连线做特殊的事。在依赖注入章节你已经看到这个了。
byName由属性名自动装配。Spring 容器看到在 XML 配置文件中 bean 的自动装配的属性设置为 byName。然后尝试匹配,并且将它的属性与在配置文件中被定义为相同名称的 beans 的属性进行连接。
byType由属性数据类型自动装配。Spring 容器看到在 XML 配置文件中 bean 的自动装配的属性设置为 byType。然后如果它的类型匹配配置文件中的一个确切的 bean 名称,它将尝试匹配和连接属性的类型。如果存在不止一个这样的 bean,则一个致命的异常将会被抛出。
constructor类似于 byType,但该类型适用于构造函数参数类型。如果在容器中没有一个构造函数参数类型的 bean,则一个致命错误将会发生。
autodetectSpring首先尝试通过 constructor 使用自动装配来连接,如果它不执行,Spring 尝试通过 byType 来自动装配。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值