面试高频知识点:Spring 互联网大厂高频面试题(持续收录)

前言

分享互联网大厂Spring高频面试知识点(持续更新中)

一、Spring

1、什么是spring?有什么优势?

  Spring是一个开源的Java/Java EE开发框架,用于构建企业级应用。它提供了一系列的功能,如依赖注入(DI)和面向切面编程(AOP),使得开发者能够更容易地创建和管理企业级应用。

Spring框架的主要优势包括:

1.简化开发:Spring通过提供大量的基础功能,如事务管理、数据访问、Web集成等,使得开发者能够更专注于业务逻辑的实现,而无需关心底层细节。

2.轻量级:Spring框架本身非常轻量,它只提供了必要的核心功能,而其他的功能则由用户根据需要选择性的引入。这使得Spring框架能够灵活地适应各种规模和复杂度的应用。

3.控制反转(IOC)和依赖注入(DI):这是Spring框架的核心特性之一。通过IOC和DI,Spring能够自动地管理对象之间的依赖关系,降低了对象之间的耦合度,提高了代码的可维护性和可重用性。

4.面向切面编程(AOP):Spring支持AOP编程范式,允许开发者将横切关注点(如日志、安全、事务等)从业务逻辑中分离出来,提高了代码的可读性和可维护性。

5.集成性:Spring能够轻松地与其他技术框架(如Struts、Hibernate等)集成,这使得开发者能够选择最适合自己项目的技术栈。

6.扩展性:Spring框架具有良好的扩展性,开发者可以根据自己的需求定制或扩展Spring的功能。

2、Spring有哪些模块组成?

1.Spring Core:核心类库,提供IOC服务。

2.Spring Context:提供框架式的Bean访问方式,以及企业级功能(JNDI、定时任务等)。

3.Spring AOP:AOP服务。

4.Spring DAO:对JDBC的抽象,简化了数据访问异常的处理。

5.Spring ORM:对现有的ORM框架的支持。

6.Spring Web:提供了基本的面向Web的综合特性,例如多方文件上传。

7.Spring MVC:提供面向Web应用的Model-View-Controller实现。

3、Autowired和Resource关键字的区别?

  @Resource和@Autowired都是做bean的注入时使用,其实@Resource并不是Spring的注解,它的包是javax.annotation.Resource,需要导入,但是Spring支持该注解的注入。

1. 共同点
  两者都可以写在字段和setter方法上。两者如果都写在字段上,那么就不需要再写setter方法。

2. 不同点

①. @Autowired
  @Autowired为Spring提供的注解,需要导入org.springframework.beans.factory.annotation.Autowired。只按照byType注入。

publicclassTestServiceImpl {
// 用于字段上
@Autowired
privateUserDaouserDao; 

@Autowired
public void setUserDao(UserDaouserDao) { 
	// 用于属性的方法上
	this.userDao=userDao;
   }
}

  @Autowired注解是按照类型(byType)装配依赖对象,默认情况下它要求依赖对象必须存在,如果允许null值,可以设置它的required属性为false。如果我们想使用按照名称(byName)来装配,可以结合@Qualifier注解一起使用。如下:

publicclassTestServiceImpl {
@Autowired
@Qualifier("userDao")
privateUserDaouserDao;

}

②. @Resource

publicclassTestServiceImpl {
// 下面两种@Resource只要使用一种即可
@Resource(name="userDao")

private UserDao userDao; // 用于字段上

@Resource(name="userDao")
public void setUserDao(UserDaouserDao) { // 用于属性的setter方法上
	this.userDao=userDao;
  }
}

注:最好是将@Resource放在setter方法上,因为这样更符合面向对象的思想,通过set、get去操作属性,而不是直接去操作属性。

@Resource装配顺序:
  ①. 如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常。

  ②. 如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常。

  ③. 如果指定了type,则从上下文中找到类似匹配的唯一bean进行装配,找不到或是找到多个,都会抛出异常。

  ④. 如果既没有指定name,又没有指定type,则自动按照byName方式进行装配;如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配。

@Resource的作用相当于@Autowired,只不过@Autowired按照byType自动注入。

4、依赖注入的方式有几种分别是什么?

  依赖注入(Dependency Injection,简称DI)的方式主要有三种:构造器注入(Constructor Injection)、Setter方法注入(Setter Injection)和接口注入(Interface Injection,但较少使用)。

以下是这三种方式的优缺点:

1.构造器注入(Constructor Injection)
  在构造方法中明确体现对其他类的依赖,代码可读性高。一旦对象初始化成功,其状态肯定是正确的。脱离了IOC框架,这个类仍然可以工作,符合POJO(Plain Old Java Object)的概念。

  缺点
  1.当依赖的类很多时,构造函数可能会有很多参数,导致代码可读性下降(也被认为是代码坏味道)。

  2.有些类(如MVC框架的Controller类)可能需要默认构造函数,一旦使用构造函数注入,就无法再使用默认构造函数。

  3.类中的一些方法可能并不需要使用到所有的依赖。

2.Setter方法注入(Setter Injection)
  在对象的整个生命周期内,可以随时动态地改变依赖,灵活性高。

  缺点:
  对象在创建后,被设置依赖对象之前这段时间状态可能是不正确的。

  不直观,无法清晰地表示哪些属性是必须的。

  与构造方法注入一样,当依赖的类很多时,Setter方法也可能有很多参数。

3.接口注入(Interface Injection) :
  依赖类必须要实现指定的接口,然后实现该接口中的一个函数,该函数就是用于依赖注入。该函数的参数就是要注入的对象。

  优点接口注入中,接口的名字、函数的名字都不重要,只要保证函数的参数是要注入的对象类型即可。
  缺点:侵入行太强,不建议使用。

5、谈谈你对Spring的IOC(控制反转)的理解?

  IOC是由专门的容器(如Spring容器)来帮忙创建对象,所有的类都在容器中登记。当需要某个对象时,不再需要主动new一个对象,而是告诉Spring容器,Spring容器会在适当的时机将对象主动创建并返回给调用者。

6、谈谈你对Spring的AOP理解?

  在Spring AOP中,一个应用程序被划分为多个切面(Aspect),每个切面都定义了一些通知(Advice)和切入点(Pointcut)。通知是切面的动作,它描述了切面要做什么,而切入点则描述了何时执行这些动作。通过这些定义,Spring AOP可以在程序运行期间,将切面中的通知织入到目标对象中,从而在不修改目标对象代码的情况下,增加新的功能。

  Spring AOP的实现原理主要是基于动态代理技术。当程序运行时,Spring容器会为那些需要被代理的目标对象创建代理对象。这些代理对象会拦截对目标对象的调用,并在调用前后执行相应的通知。通过这种方式,Spring AOP可以在不修改目标对象代码的情况下,实现对目标对象的功能增强。

应用场景:

  1.事务管理:在数据库操作或其他需要事务管理的操作中,使用AOP可以将事务管理的逻辑与业务逻辑分离,使得事务的控制更加简单和集中。

  2.安全性检查:通过AOP,可以在方法调用前进行安全性检查,例如检查用户的权限或身份验证,以确保只有授权用户可以访问特定的方法或资源。

  3.性能监控:通过AOP,可以在方法调用前后记录方法的执行时间,以监控和优化系统的性能。

  4.异常处理:使用AOP,可以集中处理方法中抛出的异常,例如将异常转换为统一的错误码或进行日志记录。

  5.缓存管理:通过AOP,可以在方法调用前检查缓存中是否存在结果,并在方法调用后将结果存储到缓存中,以提高系统的响应速度。

7、SpringMVC的拦截器和过滤器有什么区别?执行顺序?

  拦截器和过滤器在Web应用中都扮演着请求和响应处理的角色,但它们之间存在一些关键区别。

  首先,归属不同。拦截器是SpringMVC框架的一部分,而过滤器是Servlet规范的一部分。拦截器主要用于对控制器层的请求进行处理,它们提供了更细粒度的控制,可以在请求进入控制器之前和之后执行特定的逻辑,例如身份验证、日志记录和权限检查。过滤器独立于SpringMVC,用于处理通用的请求和响应内容,例如字符编码、压缩和安全性。

  其次,执行顺序也不同。拦截器的执行顺序由配置文件中的顺序决定,可以有多个拦载器,它们按照配置的顺序依次执行。而过滤器的执行顺序由web.xml文件中的配置顺序决定,同样可以有多个过滤器,按照配置的顺序执行。一般来说,首先执行过滤器,然后再执行拦截器。

  最后,用途不同。拦截器用于对SpringMVC的请求和响应进行特定的业务处理,通常与控制器层的请求处理有关。过滤器用于对所有Servlet清求和响应进行通用性的处理,通常关注请求和响应内容,而不涉及具体的业务逻辑。总的来说,了解拦截器和过滤器之间的这些区别非常重要。在面试中,这种理解将有助于说明您在Web应用程序中如何处理请求和响应以及如何利用SpringMVC和Servlet规范的不同功能。

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

1. 简单工厂
  BeanFactory:Spring的BeanFactory充当工厂,负责根据配置信息创建Bean实例。它是一种工厂模式的应用,根据指定的类名或ID创建Bean对象。

2. 工厂方法
  Factoryean:FactoryBean接口允许用户自定义Bean的创建逻辑,实现了工厂方法模式。开发人员可以使用FactoryBean来创建复杂的Bean实例。

3. 单例模式
  Bean实例:Spring默认将Bean配置为单例,确保在容器中只有一个共享的实例,这有助于节省资源和提高性能。

4. 适配器模式
  SpringMVC中的HandlerAdapter:SpringMVC的HandlerAdapter允许不同类型的处理器适配到处理器接口,以实现统一的处理器调用。这是适配器模式的应用。

5. 装饰器模式
  BeanWrapper:Spring的BeanWrapper允许在不修改原始Bean类的情况下添加额外的功能,这是装饰器模式的实际应用。

6. 代理模式
  AOP底层:Spring的AOP(面向切面编程)底层通过代理模式来实现切面功能,包括JDK动态代理和CGLIB代理。

7. 观察者模式
  Spring的事件监听:Spring的事件监听机制是观察者模式的应用,它允许组件监听和响应特定类型的事件,实现了松耦合的组件通信。

8. 策略模式
  excludeFilters、includefilters:spring允许使用策略模式来定义包扫描时的过滤策略,如在@Componentscan注解中使用的excludeFilters和includeFilters。

9. 模板方法模式
  Spring几乎所有的外接扩展:Spring框架的许多模块和外部扩展都采用模板方法模式,例如JdbcTemplate、HibernateTemplate等

10. 责任链模式
  AOP的方法调用:Spring AOP通过责任链模式实现通知(Advice)的调用,确保通知按顺序执行。

9、Spring事件监听的核心机制是什么?

  Spring事件监听的核心机制围绕观察者模式展开:

  观察者模式: 它允许一个对象(称为主题或被观察者)维护一组依赖于它的对象(称为观察者),并在主题状态发生变化时通知观察者。

它包含三个核心:

  1.事件:事件是观察者模式中的主题状态变化的具体表示,它封装了事件发生时的信息。在Spring中,事件通常是普通的Java对象,用于传递数据或上下文信息。

  2.事件发布者:在Spring中,事件发布者充当主题的角色,负责触发并发布事件。它通常实现了ApplicationEventpublisher接口或使用注解@Autowired来获得事件发布功能。

  3.事件监听器:事件监听器充当观察者的角色,负青监听并响应事件的发生。它实现了Applicationlistener接口,通过onApplicationEvent方法来处理事件。

10、Spring事务的失效原因?

  1.方法是private也会失效解决:改成public: spring的事务代理通常是通过Java动态代理或CGLIB动态代理生成的,这些代理要求目标方法是1.公开可访问的(public)。私有方法无法被代理,因此事务将无效。解决方法是将目标方法改为public或protected。

  2.目标类没有配置为Bean也会失效解决:配置为Bean:Spring的事务管理需要在Spring容器中配置的Bean上才能生效。如果目标类没有被配2置为Spring Bean,那么事务将无法被应用。解决方法是确保目标类被正确配置为Spring Bean。

  3.自己捕获了异常解决:不要捕获处理: Spring事务管理通常依赖于抛出未捕获的运行时异常来触发事务回滚。如果您在方法内部捕获了异常并处理了它,事务将不会回滚。解决方法是让异常在方法内部被抛出,以触发事务回滚。

  4.使用CGLIB动态代理,但@Transactional声明在接口上: 默认情况下,Spring的事务代理使用基于接口的JDK动态代理。如果您将@Transactional注解声明在接口上,而日标类是使用CGLIB代理的,事务将不会生效。解决方法是将@Transactional注解移到目标类的方法上,或者配置Spring以使用CGLIB代理接口。

  5.跨越多个线程的事务管理解决:使用编程式事务或分布式事务: 如果您的应用程序在多个线程之间共享数据库连接和事务上下文,事务可能会失效,除非适当地配置事务传播属性。

  6.事务传播属性或捕获异常等熟悉设置不正确:事务传播属性定义了事务如何传播到嵌套方法或外部方法。如果事务传播属性设置不正确,可能会导致事务失效或不符合预期的行为。

11、Spring是如何解决Bean的循环依赖?

  Spring是如何解决的循环依赖: 采用三级缓存解决的就是三个Map 。关键: 一定要有一个缓存保存它的早期对象作为死循环的出口。

1. 一级缓存 singletonObjects存放可以使用的单例。

2. 二级缓存 earlySingletonObjects存放的是早期的bean,即半成品,此时还无法使用。

3. 三级缓存 singletonFactories是一个对象工厂,用于创建对象并放入二级缓存中。同时,如果对象有Aop代理,则对象工厂返回代理对象。

面试官还可能问:
1.二级缓存能不能解决循环依赖?

  a.如果只是循环依赖导致的死循环的问题: 一级缓存就可以解决,但是解决在并发下获取不完整的Bean。

  b.二级缓存完全解决循环依赖: 只是需要在实例化后就创建动态代理,不优化也不符合spring生命周期规范

2.Spring有没有解决多例Bean的循环依赖?

  a.多例不会使用缓存进行存储(多例Bean每次使用都需要重新创建)

  b,不缓存早期对象就无法解决循环

3.Spring有没有解决构造函数参数Bean的循环依赖?

  a.构造函数的循环依赖也是会报错

  b.可以通过人工进行解决:@Lazy
    ①. 就不会立即创建依赖的bean了
    ②. 而是等到用到才通过动态代理进行创建

12、Spring中bean的生命周期?

Bean生命周期:指定的就是Bean从创建到销毁的整个过程分4大步:
1.实例化
  a.通过反射去推断构造函数进行实例化
  b.实例工厂、静态工厂

2.依赖注入(DI)
  a.解析自动装配(byname bytype constractor none @Autowired)

3.初始化

  a.调用很多Aware回调方法

  b.调用BeanPostProcessorpostProcessBeforelnitialization

  c.调用生命周期回调初始化方法

  d.调用BeanPostProcessor.postProcessAfterlnitialization,如果bean实现aop则会在这里创建动态代理

4.销毁
  a.在spring容器关闭的时候进行调用

  b.调用生命周期回调销毁方法

13、BeanFactory 和FactoryBean有什么区别?

  BeanFactory 是Soring框架的核心接口之一,用于管理和获取Bean对象亦陈为bean的容器。使用了简单工厂模式,提供aetean方法用来获取bean。

  FactoryBean 是一个bean,但是它是一个特殊的bean。

14、Spring事务传播行为有哪些?

REQUIRED:这是Spring中事务传播行为的默认选项。如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。

REQUIRES_NEW:如果当前存在事务,则挂起当前事务并创建一个新的事务。如果当前没有事务,则创建一个新的事务。

SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。

MANDATORY:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。

NOT_SUPPORTED:以非事务的方式运行,如果当前存在事务,则把当前事务挂起。

NEVER:以非事务的方式运行,如果当前存在事务,则抛出异常。

NESTED:如果当前存在事务,则在嵌套事务内运行。如果当前没有事务,其行为与REQUIRED一样

15、使用@Lazy标注一个Bean类,会发生什么?

  如果一个类被@Lazy那么容器在启动过程中会判断当前类的注解信息中是否有@Lazy注解,如果有那么就不会实例化,只有你真正使用的时候才会去实例化,然后将该类注册到单例池中。

16、单例Bean中如何正确注入多例Bean?

1.使用@Lookup注解

@Component  
public class SingletonBean {  

    @Lookup("prototypeBean")  
    public PrototypeBean getPrototypeBean() {  
        // 这里每次调用都会返回一个新的PrototypeBean实例  
        return null; // Spring会覆盖这个方法的实现  
    }  

    // ... 其他方法 ...  
}  

@Component  
@Scope("prototype")  
public class PrototypeBean {  
    // ... 类的实现 ...  
}

2.使用ObjectFactory或ApplicationContext

@Component  
public class SingletonBean {  

    private final ObjectFactory<PrototypeBean> prototypeBeanObjectFactory;  

    @Autowired  
    public SingletonBean(ObjectFactory<PrototypeBean> prototypeBeanObjectFactory) {  
        this.prototypeBeanObjectFactory = prototypeBeanObjectFactory;  
    }  

    public PrototypeBean getPrototypeBean() {  
        // 每次调用都会返回一个新的PrototypeBean实例  
        return prototypeBeanObjectFactory.getObject();  
    }  

    // ... 其他方法 ...  
}  

@Component  
@Scope("prototype")  
public class PrototypeBean {  
    // ... 类的实现 ...  
}
@Component  
public class SingletonBean implements ApplicationContextAware {  

    private ApplicationContext applicationContext;  

    @Override  
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {  
        this.applicationContext = applicationContext;  
    }  

    public PrototypeBean getPrototypeBean() {  
        // 每次调用都会返回一个新的PrototypeBean实例  
        return applicationContext.getBean(PrototypeBean.class);  
    }  

    // ... 其他方法 ...  
}

17、抽象类能不能被注册为Bean?

  抽象类本身不能被直接注册为Spring框架中的Bean,因为抽象类不能被实例化。但是,有一些间接的方式可以让Spring管理基于抽象类的Bean。

1.使用FactoryBean:
  可以创建一个实现了FactoryBean接口的类,该接口允许你返回一个对象实例,而不是直接返回bean本身。在这个FactoryBean的实现中,你可以创建一个基于抽象类的子类实例(例如,使用匿名内部类),并返回这个实例。这样,虽然你注册的是一个FactoryBean,但你可以通过它来间接地获取基于抽象类的Bean实例。

2.使用Java配置:
  在Java配置类中,你可以使用@Bean注解来定义一个方法,该方法返回一个Bean实例。虽然你不能直接返回一个抽象类的实例,但你可以在这个方法中创建一个匿名子类(或者具体的子类)的实例并返回。

3.XML配置中的工厂方法:
  如果你使用XML配置,你可以定义一个工厂方法,该方法返回一个基于抽象类的Bean实例。与Java配置类似,你需要定义一个具体的方法,该方法返回基于抽象类的子类实例。

18、Spring支持的几种bean的作用域?

singleton(单例):这是Spring的默认作用域。在Spring IoC容器中,针对一个bean定义只会有一个对象实例存在。Spring IoC容器会在第一次请求该bean时创建这个bean实例,并将其保存在IoC容器中,之后再次请求该bean时,就会直接返回已经创建的bean实例。

prototype(原型):每次对Bean的请求都会创建一个新的实例。这意味着每次通过容器的getBean()方法获取prototype范围的bean时,都将返回一个新的bean实例。prototype作用域的bean适合用在无状态的服务中,比如Spring MVC中的Controller。

request(请求):在每个HTTP请求中创建一个新的Bean实例。这个Bean实例仅在当前HTTP请求内有效。请求作用域的bean适用于处理HTTP请求的控制器或服务。

session(会话):在每个用户会话(Session)中创建一个新的Bean实例。对于同一用户的所有请求,都将使用相同的Bean实例。这个Bean实例仅在当前HTTP会话内有效。会话作用域的bean适用于保存用户特定的数据或状态。

application(全局):一个bean定义对应于单个ServletContext的生命周期。在Web应用中,这相当于ServletContext的生命周期。全局作用域的bean在整个Web应用中都是共享的。

websocket(WebSocket):一个bean定义对应于单个WebSocket的生命周期。这通常用于处理WebSocket通信。

19、请解释Spring MVC框架及其工作原理?

  Spring MVC是一个基于Java的Web框架,它按照MVC设计模式设计,将Web应用划分为模型(Model)、视图(View)和控制器(Controller)三个部分。Spring MVC通过DispatcherServlet作为前端控制器来接收所有请求,并委托给相应的处理器映射、处理器适配器、处理器和视图解析器来处理这些请求。

20、Spring常用的注解?

1. @Autowired

  作用:自动装配bean,它可以对类成员变量、方法及构造函数进行标注,完成自动装配的工作。

  原理:当Spring容器启动的时候,Spring容器会自动扫描到@Autowired注解,然后把@Autowired注解标注的变量自动注入进来。

  注意:@Autowired默认按类型匹配的方式,在容器查找匹配的Bean,当有且仅有一个匹配的Bean时,Spring将其注入@Autowired标注的变量中。如果有多个匹配的Bean,则需要使用@Qualifier注解来指定Bean的名称。

2. @Component、@Service、@Repository、@Controller
  作用:这些注解都用于定义Bean,并将Bean交给Spring容器管理。

  原理:这四个注解都是@Component的衍生注解,只是表示了不同的层,作用还是一样的,都是将类定义成Bean类,然后交给Spring容器管理。

  区别:@Component泛指各种组件,@Service在业务逻辑层使用(service层),@Repository在数据访问层使用(dao层),@Controller在展现层使用,控制器的声明(C)。

3. @Qualifier

  作用:当存在多个同一类型的Bean时,可以用@Qualifier注解来指定。与@Autowired配合使用,消除特定bean自动装配的歧义。

4. @Resource

  作用:和@Autowired的功能一样,都是用来自动装配bean的,只是@Resource默认按名称来装配,当找不到与名称匹配的bean才会按类型来装配。

5. @RequestParam
  作用:用于处理Content-Type为application/x-www-form-urlencoded编码的内容,也可以用于其他类型的请求,如POST、DELETE等。

6. @RequestBody

  作用:接收的参数是来自requestBody中,即请求体。一般用于处理非Content-Type: application/x-www-form-urlencoded编码格式的数据,比如:application/json、application/xml等类型的数据。

7. @Aspect、@After、@Before、@Around

  作用:这些都是AOP(面向切面编程)相关的注解,用于定义切面、通知(advice)和切点(pointcut)等。

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值