Spring面试题

Spring

1. Spring 的理解

  • Spring 是一个开源框架,为简化企业级应用开发而生。Spring 可以是使简单的JavaBean 实现以前只有EJB 才能实现的功能。Spring 是一个开源的控制反转(Inversion of Control,IoC)和面向切面(AOP)的容器框架。它的主要目的是使现有技术更加易用,推荐编码最佳实现,从而简化企业开发。
  • Spring致力于Java EE 应用的各种解决方案,而不是仅仅专注于某一层面的方案。可以说,Spring是企业应用开发的“一站式”选择,Spring贯穿表示层、业务层、持久层。然而,Spring并不想取代那些已有的框架,而以高度的开发性与他们无缝整合。
  • Spring 容器的主要核心是:
    • 控制反转(IOC),传统的 java 开发模式中,当需要一个对象时,我们会自己使用 new 或者 getInstance 等直接或者间接调用构造方法创建一个对象。而在 spring 开发模式中,spring 容器使用了工厂模式为我们创建了所需要的对象,不需要我们自己创建了,直接调用spring 提供的对象就可以了,这是控制反转的思想。
    • 依赖注入(DI),spring 使用 javaBean 对象的 set 方法或者带参数的构造方法为我们在创建所需对象时将其属性自动设置所需要的值的过程,就是依赖注入的思想。
    • 面向切面编程(AOP),在面向对象编程(oop)思想中,我们将事物纵向抽成一个个的对象。而在面向切面编程中,我们将一个个的对象某些类似的方面横向抽成一个切面,对这个切面进行一些如权限控制、事物管理,记录日志等公用操作处理的过程就是面向切面编程的思想。AOP 底层是动态代理,如果是接口采用 JDK 动态代理,如果是类采用CGLIB 方式实现动态代理。

2. Spring 中的设计模式

  • 单例模式——spring 中两种代理方式,若目标对象实现了若干接口,spring 使用jdk java.lang.reflect.Proxy 类代理。若目标兑现没有实现任何接口,spring 使用 CGLIB 库生成目标类的子类。单例模式——在 spring 的配置文件中设置 bean 默认为单例模式。
  • 模板方式模式——用来解决代码重复的问题。
    • 比如:RestTemplate、JmsTemplate、JpaTemplate
  • 工厂模式——在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用同一个接口来指向新创建的对象。Spring 中使用beanFactory 来创建对象的实例。
  • 代理模式-----AOP

3. Spring 的常用注解

  • 常用的注解:
    • @Autowired: 自动装配,spring提供
    • @Controller、@Service、@Repository、@Component
    • @RequesMapping,@GetMapping,@PutMapping,@DeleteMapping,@PostMapping
    • @ResponseBody,@RequstBody
    • @PathVariable

4. 什么是Spring beans?

  • Spring beans 是那些形成 Spring 应用的主干的 java 对象。它们被 Spring IOC 容器初始化,装配,和管理。这些 beans 通过容器中配置的元数据创建。比如,以 XML 文件中 的形式定义。
  • Spring 框架定义的bean 都是单例 bean。

5. 简单介绍一下Spring bean 的生命周期

  • bean 定义:在配置文件里面用来进行定义。
  • bean 初始化:有两种方式初始化:
    • 在配置文件中通过指定 init-method 属性来完成
    • 实现 org.springframwork.beans.factory.InitializingBean 接口 ,知道一下,我们没讲
  • bean 调用:有三种方式可以得到 bean 实例,并进行调用
  • bean 销毁:销毁有两种方式
    • 使用配置文件指定的 destroy-method 属性
    • 实现org.springframwork.bean.factory.DisposeableBean 接口,知道一下,我们没讲

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

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

7. 什么是Spring 的内部 bean?

  • 当一个 bean 仅被用作另一个 bean 的属性时,它能被声明为一个内部 bean,为了定义 inner bean,在
  • Spring 的 基于 XML 的 配置元数据中,可以在 或 元素内使用bean/> 元素,内部 bean 通常是匿名的,它们的 Scope 一般是 prototype。

8. 你怎样定义类的作用域,五个

  • spring 支持 5 种作用域,如下:
    • singleton:spring ioc 容器中只存在一个 bean 实例,bean 以单例模式存在,是系统默认值;
    • prototype:每次从容器调用 bean 时都会创建一个新的示例,既每次 getBean()相当于执行 new Bean()操作;
    • Web 环境下的作用域:
    • request:每次 http 请求都会创建一个 bean;
    • session:同一个 http session 共享一个 bean 实例;
    • global-session:用于 web容器,因为每个 web有单独的 session,globalsession 提供一个全局性的 http session。
      注意: 使用 prototype 作用域需要慎重的思考,因为频繁创建和销毁 bean 会带来很大的性能开销。

9. spring xml自动装配 bean 有哪些方式?

  • no:默认值,表示没有自动装配,应使用显式 bean 引用进行装配。
  • byName:它根据 bean 的名称注入对象依赖项。
  • byType:它根据类型注入对象依赖项。
  • 构造函数:通过构造函数来注入依赖项,需要设置大量的参数。
  • default:在beans里配置的是啥就是啥

10. 什么是依赖,什么是依赖注入?

  • 依赖:两个元素中一个定义发生改变则会引起另一个元素发生改变,则称这两个元素之间存在依赖关系。
  • 控制反转(IoC):在传统的程序设计过程中,都是在应用内部创建及维护依赖的对象。 控制反转就是应用本身不负责依赖对象的创建及维护,依赖对象的创建及维护是由外部容器负责的。这样控制权就由应用转移到外部容器,控制权的转移就是控制反转。
  • 依赖注入:是指 在运行期,由外部容器动态地将依赖对象注入到组件中。
    依赖注入让Bean与Bean之间以配置文件组织在一起,而不是以硬编码的方式耦合在一起。

11. Spring自动装配的优缺点

  • 优点:
    • 自动装配能显著减少配置的数量。不过,采用bean模板(见这里)也可以达到同样的目的。
    • 自动装配可以使配置与java代码同步更新。例如,如果你需要给一个java类增加一个依赖,那么该依赖将被自动实现而不需要修改配置。因此强烈推荐在开发过程中采用自动装配,而在系统趋于稳定的时候改为显式装配的方式。
  • 缺点:
    • 尽管自动装配比显式装配更神奇,但是,正如上面所提到的,Spring会尽量避免在装配不明确的时候进行猜测,因为装配不明确可能出现难以预料的结果,而且Spring所管理的对象之间的关联关系也不再能清晰的进行文档化。
    • 对于那些根据Spring配置文件生成文档的工具来说,自动装配将会使这些工具没法生成依赖信息。

12. 解释一下什么是 ioc?

ioc:Inversionof Control(中文:控制反转)是 spring 的核心,对于 spring 框架来说,就是由 spring 来负责控制对象的生命周期和对象间的关系。

简单来说,控制指的是当前对象对内部成员的控制权;控制反转指的是,这种控制权不由当前对象管理了,由其他(类,第三方容器)来管理。

13. 有哪些不同类型的 IOC(依赖注入)方式?

Spring 提供了多种依赖注入的方式。

  • Set 注入
  • 构造器注入
  • 静态工厂的方法注入
  • 实例工厂的方法注入

14. Spring主要包含哪些模块?

  • spring core:框架的最基础部分,提供 ioc 和依赖注入特性。
  • spring context:构建于 core 封装包基础上的 context 封装包,提供了一种框架式的对象访问方法。
  • spring dao:Data Access Object 提供了JDBC的抽象层。
  • spring aop:提供了面向切面的编程实现,让你可以自定义拦截器、切点等。
  • spring Web:提供了针对 Web 开发的集成特性,例如文件上传,利用 servlet listeners 进行 ioc 容器初始化和针对 Web 的 ApplicationContext。
  • spring Web mvc:spring 中的 mvc 封装包提供了 Web 应用的 Model-View-Controller(MVC)的实现。

15. ApplicationContext 的实现类有哪些?

  • FileSystemXmlApplicationContext :此容器从一个XML 文件中加载beans 的定义,XML Bean 配置文件的全路径名必须提供给它的构造函数。
  • ClassPathXmlApplicationContext:此容器也从一个 XML 文件中加载 beans 的定义,这里,你需要正确设置
  • WebXmlApplicationContext:此容器加载一个 XML 文件,此文件定义了一个WEB 应用的所有 bean。

16. context:annotation-config和 context:component-scan的区别

  • context:annotation-config 是用于激活那些已经在spring容器里注册过的bean(无论是通过xml的方式还是通过package sanning的方式)上面的注解。
  • context:component-scan除了具有context:annotation-config的功能之外,context:component-scan还可以在指定的package下扫描以及注册javabean 。

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

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

  • 类型用于注入一列值,允许有相同的值。
  • 类型用于注入一组值,不允许有相同的值。
  • 类型用于注入一组键值对,键和值都可以为任意类型。
  • 类型用于注入一组键值对,键和值都只能为 String 类型。

18. 解释一下什么是 aop?

aop 是面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。

简单来说就是统一处理某一“切面”(类)的问题的编程思想,比如统一处理日志、异常等。

19. AOP核心概念

  • Aspect(切面)
    • 横切关注点,一般一个切面对应一个额外功能。
  • Joinpoint(连接点)
    • 被拦截到的点,因为 Spring 只支持方法类型的连接点,所以在 Spring 中连接点指的就是被拦截到的方法,
  • Advice(通知)
    • 通知,用于方法上,表示方法执行方位。共有5种
  • Pointcut(切入点)
    • 切入点是一个或一组连接点,通知将在这些位置执行。可以通过表达式或匹配的方式指明切入点。
  • Weaving(织入)
    • 织入,指将通知插入到目标对象。
  • Target(目标对象)
    • 目标对象,指需要织入切面的对象。
  • Proxy(代理对象)
    • 代理对象,指切面织入目标对象之后形成的对象。

20. Spring中的通知类型?

1) before:前置通知,在一个方法执行前被调用。

2) after: 在方法执行之后调用的通知,无论方法执行是否成功。

3) after-returning: 仅当方法成功完成后执行的通知。

4) after-throwing: 在方法抛出异常退出时执行的通知。

5) around: 在方法执行之前和之后调用的通知。

21. Spring AOP原理

  • Spring采用动态代理模式来实现AOP机制。
  • Spring AOP采用动态代理的过程:
    • 将切面使用动态代理的方式动态织入到目标对象(被代理类),形成一个代理对象;
    • 目标对象如果没有实现代理接口,那么Spring会采用CGLib来生成代理对象,该代理对象是目标对象的子类;
    • 目标对象如果是final类,并且也没实现代理接口,就不能运用AOP。

22. AOP的配置(额外功能)

22.1. 基于注解的AOP

四步曲:

  • 第一步:要使用到的注解@Aspect,先加下如下jar包
    pom.xml

    4.3.21.RELEASE
    1.6.11

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aop</artifactId>
        <version>${spring-version}</version>
    </dependency>
    
    <!--使用AspectJ方式注解需要相应的包-->
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjrt</artifactId>
        <version>${aspectj-version}</version>
    </dependency>
    
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>${aspectj-version}</version>
    </dependency>
    
  • 第二步:applicationContext.xml中要进行配置

    • 加入aop命名空间

    • 在beans标签下启动动态代理

          <!--  启动代理-->
          <aop:aspectj-autoproxy/>
      
  • 第三步:使用Aspect注解声明切面,切面只是一个带有@Aspect注解的Java类,里边写的内容其它就通知,此切面也要加上@Component注解
    //切面
    @Aspect
    @Component
    public class LogAspect {

    }

  • 第四步在:标注连接点(位置),有如下注解 ,在此连接点中的织语表达式中要声明到Bean

    • @Before : 在核心方法之前
      @Before(value=“execution(public * net.wanho.service….(…))”)
      public void before(){
      System.out.println(“before…”);
      }

    • @After : 在核心方法之后

    • @AfterRunning : 在方法返回结果之后执行

    • @AfterThrowing : 在方法抛出异常执行

    • @Around : 在方法前后都执行

      //切面
      @Aspect
      @Component
      public class LogAspect {
      // 第一个*:任意返回类型 service…:service下的任意子包 .:类.方法 (…) 任意参数
      @Before(value=“execution(public * net.wanho.service….(…))”)
      public void before(JoinPoint joinPoint){
      System.out.println(“before…”+joinPoint.getSignature().getName());
      }

      @After(value="execution(public * net.wanho.service..*.*(..))")
      public void after(JoinPoint joinPoint){
          System.out.println("after");
      }
      
      //@Around(value="execution(public * net.wanho.service..*.*(..))")
      public Object around(ProceedingJoinPoint joinPoint){
          Object result = null;
          try {
              System.out.println("before2");
              result = joinPoint.proceed();
              System.out.println("after2");
          } catch (Throwable throwable) {
              throwable.printStackTrace();
          }
          return result;
      }
      
      //@AfterReturning(value="execution(public * net.wanho.service..*.*(..))",returning = "res")
      public void afterRunning(JoinPoint joinPoint,Object res){
          System.out.println("afterRunning"+joinPoint.getSignature().getName()+res);
      }
      
      @AfterThrowing(value="execution(public * net.wanho.service..*.*(..))", throwing = "e")
      public void afterThrowing(JoinPoint joinPoint,Exception e){
          System.out.println("afterThrowing"+e);
      }
      

      }

  • 指定切面的优先级

通过@Order注解

//切面
@Aspect
@Component
@Order(2)
public class EffectAspect {}
//切面
@Aspect
@Component
@Order(1)
public class LogAspect {
    
}
  • 抽取织语表达式

  • 通过注解方式配置,要在每个连接点前设置织语表达式,如果是同一个表达式,要设置多个位置,表达式有点重复

    //切面
    @Aspect
    @Component
    @Order(1)
    public class LogAspect {

      //抽取出织语表达式
      @Pointcut("execution(public * net.wanho.service..*.*(..))")
      public void expression(){
    
      }
    
      // 第一个*:任意返回类型    service..:service下的任意子包 *.*:类.方法   (..) 任意参数
      @Before(value="expression()")
      public void before(JoinPoint joinPoint){
          System.out.println("log_before..."+joinPoint.getSignature().getName());
      }
    
      //@After(value="expression()")
      public void after(JoinPoint joinPoint){
          System.out.println("after");
      }
    
      //@Around(value="expression()")
      public Object around(ProceedingJoinPoint joinPoint){
          Object result = null;
          try {
              System.out.println("before2");
              result = joinPoint.proceed();
              System.out.println("after2");
          } catch (Throwable throwable) {
              throwable.printStackTrace();
          }
          return result;
      }
    
      //@AfterReturning(value="expression()")
      public void afterRunning(JoinPoint joinPoint,Object res){
          System.out.println("afterRunning"+joinPoint.getSignature().getName()+res);
      }
    
      @AfterThrowing(value="expression()",throwing = "e")
      public void afterThrowing(JoinPoint joinPoint,Exception e){
          System.out.println("afterThrowing"+e);
      }
    

    }

22.2. 基于xml的AOP:[推荐]

  • 第一步:仍然要加个三个jar包
  • 第二步:在xml中进行配置
    • 加入命名空间
    • 声明Aspect类的bean对象
    • 声明<aop:cofnig ">
    • 声明切点,加织语表达式
    • 声明切面 <aop:aspect ref="ref=“logAspect”>
      • 声明连接点

        aop:config
        <aop:pointcut id=“pointcut” expression=“execution(public * net.wanho.service….(…))”/>

        <aop:aspect ref="logAspect" order="1">
            <aop:before method="before" pointcut-ref="pointcut"/>
            <aop:after method="after" pointcut-ref="pointcut"/>
            <aop:around method="around" pointcut-ref="pointcut"/>
            <aop:after-returning method="afterReturning"  pointcut-ref="pointcut" returning="res"/>
            <aop:after-throwing method="afterThrowing" pointcut-ref="pointcut" throwing="e"/>
        </aop:aspect>
        

        </aop:config>

23. spring 事务实现方式有哪些?

23.1. 基于XML的事务配置

  • 四步曲

  • 第一步:

    • 加入spring-jdbc
    • 加入druid
    • 加入mysql-connector
    • 数据源
  • 第二步: 配置事务管事器
    <context:property-placeholder location=“classpath:db.properties”/>






    </bean>
    <!--2.事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    
  • 第三步: aop配置

    aop:config
    <aop:pointcut id=“pointCut” expression=“execution(public * net.wanho.service….(…))”/>
    <aop:advisor advice-ref=“txAdvice” pointcut-ref=“pointCut”/>
    </aop:config>

  • 第四步:advice配置,前提是加tx的命名空间

    <tx:advice id=“txAdvice” transaction-manager=“transactionManager”>
    tx:attributes
    <tx:method name=“transfer” propagation=“REQUIRES_NEW”/>
    <tx:method name=“insert*” propagation=“REQUIRES_NEW”/>
    <tx:method name=“add*” propagation=“REQUIRES_NEW”/>
    <tx:method name=“update*” propagation=“REQUIRES_NEW”/>
    </tx:attributes>
    </tx:advice>

23.2. 基于annotation配置的事务配置

四步曲:

  • 第一步:

    • 加入spring-jdbc
    • 加入druid
    • 加入mysql-connector
    • 数据源
  • 第二步: 配置事务管事器
    <context:property-placeholder location=“classpath:db.properties”/>






    </bean>
    <!--2.事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    
  • 第三步:启用事务注解

    <tx:annotation-driven transaction-manager=“transactionManager”/>

  • 第四步:在所需要加事务的方法上加入@Transactional的注解,注意忘记加此注解的方法即不加事务
    @Service
    public class BankService {

        @Transactional
        public void transfer(String from,String to,int amount){
    
        }
        //4. 加入事务
        @Transactional
        public void add(){
            
        }
    }
    

24. 说一下 spring 的事务并发和隔离级别?

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

  • ISOLATION_DEFAULT:用底层数据库的设置隔离级别,数据库设置的是什么我就用什么;
  • ISOLATIONREADUNCOMMITTED:未提交读,最低隔离级别、事务未提交前,就可被其他事务读取(会出现幻读、脏读、不可重复读);
  • ISOLATIONREADCOMMITTED:提交读,一个事务提交后才能被其他事务读取到(会造成幻读、不可重复读),SQL server 的默认级别;
  • ISOLATIONREPEATABLEREAD:可重复读,保证多次读取同一个数据时,其值都和事务开始时候的内容是一致,禁止读取到别的事务未提交的数据(会造成幻读),MySQL 的默认级别;
  • ISOLATION_SERIALIZABLE:序列化,代价最高最可靠的隔离级别,该隔离级别能防止脏读、不可重复读、幻读。
  • 脏读 :表示一个事务能够读取另一个事务中还未提交的数据。比如,某个事务尝试插入记录 A,此时该事务还未提交,然后另一个事务尝试读取到了记录 A。
  • 不可重复读 :是指在一个事务内,多次读同一数据。
  • 幻读 :指同一个事务内多次查询返回的结果集不一样。比如同一个事务 A 第一次查询时候有 n 条记录,但是第二次同等条件下查询却有 n+1 条记录,这就好像产生了幻觉。发生幻读的原因也是另外一个事务新增或者删除或者修改了第一个事务结果集里面的数据,同一个记录的数据内容被修改了,所有数据行的记录就变多或者变少了。

25. 事务传播行为

  • 七大行为
    • required_new: 需要新的事务。之前有的事务挂起
    • required : 有则使用,无则创建
    • supports:有支持,没有也行
    • not_supported: 不支持事务,有则挂起
    • never : 不应该有事务,有则抛异常
    • mandatory : 强制要有事务,无则抛异常
    • nested: 有事务开启内嵌事务,外部仍然存在。无则创建新事务

26. 实际开发过程中为什么拆分Spring配置文件?

  • 当项目规模大的时候,配置文件可读性、可维护性差,庞大的Spring配置文件难以阅读。
  • 团队开发时,多人修改同一配置文件容易发生冲突,降低开发效率。

27. 采用何种策略拆分Spring配置文件?

  • 如每个开发人员负责一模块采用公用配置(包含数据源、事务等)+每个系统模块一个单独配置文件(包含dao、service及action)形式
  • 如采用分层负责或者DAO配置代码由代码生成工具生成时,我们采用公用配置(包含数据源、事务等)+ DAO Bean配置 + 业务逻辑Bean配置 + Action Bean配置形式

28. Spring对持久层的支持

JDBC,O/R Mapping(Hibernate,TopLink等)

Spring对持久层支持采用的策略:

  • Spring对持久层“不发明重复的轮子”,即没有重新实现新的持久层方案,对现有持久层方案做封装,更利于使用。
  • 采用DAO模式
  • 提供了大量的模板类来简化编程(JdbcTemplate等)
  • 重新设计了一套完善的异常体系结构
    • 类型丰富,细化异常类型
    • 全都是运行时异常(RuntimeException)
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值