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 来自动装配。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值