84道Spring高频题整理(附答案背诵版)
解释一下Spring 框架?
Spring框架是一个开源的企业级应用开发框架,由Rod Johnson创建,并于2003年首次发布。Spring 是在全方位提供企业级服务的基础上,用Java实现的。Spring的核心思想是使现代Java开发更加简单。
Spring框架以其灵活性和透明性闻名,几乎可以用在任何Java环境中。Spring的核心是控制反转(IoC)或依赖注入(DI)和面向切面编程(AOP)。
以下是Spring框架的主要特点:
- 依赖注入:Spring框架通过依赖注入的方式来管理对象。这样有助于降低对象之间的耦合度,并提高代码的可测试性和可维护性。
- 面向切面编程:Spring支持面向切面编程,这样可以把业务逻辑和系统服务分离开来。比如日志记录、事务管理、安全等,这些可以通过AOP的方式插入到业务逻辑中。
- 事务管理:Spring提供了一套事务管理接口,可以和多种事务管理平台进行集成。
- MVC框架:Spring还包含了一个灵活的MVC Web应用框架,用于搭建Web应用。
Spring 中常用的注解有哪些?
Spring框架中有一些常见的注解,这些注解大大简化了Java开发人员的工作。以下是一些常见的Spring注解:
- @Component:这是一个通用的注解,表示该类是一个Spring管理的组件。所有的Spring注解,例如@Service、@Repository和@Controller,都是@Component的特化形式。
- @Autowired:这个注解用于自动注入依赖。Spring会查找并注入标记为@Component的类,这个类的类型与@Autowired注解字段的类型相匹配。
- @Service:这个注解用于标记服务层的组件。
- @Repository:这个注解用于标记数据访问组件,即DAO组件。
- @Controller:这个注解用于标记控制器组件,主要用在Spring MVC中。
- @RequestMapping:这个注解用于指定处理器函数或者控制器类能处理的URL路径。
- @PathVariable:这个注解用于处理URL中的动态部分,并将其传递给处理器函数作为参数。
- @RequestParam:这个注解用于从请求参数中获取值。
- @ResponseBody:这个注解用于将返回值转化为HTTP响应体。
- @Configuration:这个注解表明该类包含一个或多个@Bean方法,并且Spring容器需要处理这些方法以生成bean定义。
- @Bean:这个注解用于将方法的返回值注册为Spring应用上下文中的bean。
Spring 框架的好处?
Spring框架为企业级Java开发带来了很多好处:
- 便捷的依赖管理:Spring框架的核心是控制反转(IoC)和依赖注入(DI),这让组件间的依赖关系变得更加清晰,代码更加松耦合。
- 面向切面的编程:Spring的AOP模块让关注点的分离变得简单,提升了程序的可重用性。例如,事务管理、日志记录、权限控制等都可以被定义为切面,并在适当的时机应用到业务逻辑代码上。
- 事务管理:Spring提供了一套事务管理接口,可以与多种事务管理平台进行集成,使得事务管理变得非常方便。
- 强大的Web MVC:Spring的Web MVC框架是一个设计良好的Web层框架,它完全整合了其他Spring组件。
- 与主流技术的集成:Spring提供了对主流对象关系映射(ORM)框架的集成,如Hibernate、MyBatis等,也提供了对Java EE标准的支持,如JMS、EJB、JPA等。
- 测试便捷:Spring的测试模块提供了强大的单元测试和集成测试功能,可以方便地进行测试驱动开发(TDD)。
Spring 的主要模块有哪些?
Spring框架主要由以下模块组成:
-
Spring Core:这是Spring框架的核心模块,提供了控制反转(IoC)和依赖注入(DI)功能。
-
Spring AOP:面向切面编程(AOP)模块支持面向切面编程,允许定义方法拦截器和切点来解决企业级应用的横切关注点。
-
Spring DAO:数据访问对象(DAO)模块为数据访问提供了JDBC抽象层,消除了常见的数据访问相关的重复性代码。
-
Spring ORM:对象关系映射(ORM)模块为流行的ORM API,如JPA,JDO,Hibernate,MyBatis等,提供了集成层。
-
Spring Web MVC:这是一个用于创建Web应用的模块。Spring的Web模块是一个全功能的MVC模块,提供了更强大和更灵活的Web应用开发选项。
-
Spring Context:这个模块支持国际化(i18n)等企业级服务,提供了框架式的方式来管理bean和bean之间的依赖关系。
-
Spring Test:这个模块支持对Spring组件的JUnit或TestNG测试。
解释一下Spring IOC ?
Spring的控制反转(IoC)容器是Spring框架核心的一部分。IoC容器负责实例化、配置和装配应用中所需的对象。这些对象在Spring中被称为beans,它们是应用的主体部分和应用业务逻辑的实现。
Spring IoC容器的主要功能包括:
-
Bean实例化:Spring IoC容器会负责创建对象实例。你只需要在配置文件中定义需要的对象,以及这些对象的属性和依赖关系,然后Spring IoC容器就会自动创建这些实例。
-
依赖注入:Spring IoC容器通过依赖注入(DI)的方式来管理对象的依赖关系。这意味着,如果一个对象需要另一个对象才能正确工作,那么Spring IoC容器会自动把所需的对象注入到依赖它的对象中。
-
Bean配置:Spring IoC容器允许你在配置文件中定义对象的各种属性。这意味着,你可以在配置文件中改变对象的行为,而无需修改对象的源代码。
-
生命周期管理:Spring IoC容器还负责管理对象的生命周期。这包括对象的创建、初始化、使用和销毁。
Spring IoC容器的这些功能,使得应用的组件可以更容易地解耦合,并且在修改、测试和重用时更加灵活。
例如,你可能有一个BookService
类,它依赖于BookRepository
接口的某个实现。在没有Spring的情况下,你需要手动创建BookRepository
的实现,并将其传递给BookService
。但是在Spring中,你只需要在BookService
中注解@Autowired
,然后Spring IoC容器就会自动创建一个BookRepository
的实现,并注入到BookService
中。
@Service
public class BookService {
private final BookRepository bookRepository;
@Autowired
public BookService(BookRepository bookRepository) {
this.bookRepository = bookRepository;
}
// ...
}
在这个例子中,Spring IoC容器管理了BookRepository
的生命周期,并在需要的时候将其注入到BookService
中,这样你就不需要手动管理这些依赖了。
Spring IOC 的好处?
Spring IoC(控制反转)提供了很多好处,主要包括以下几点:
- 解耦:通过IoC,对象之间的依赖关系由Spring框架负责管理和装配,而不是由对象自己控制。这样可以降低代码的耦合度,使得代码更加灵活和易于维护。
- 代码简化:Spring IoC容器负责创建和管理对象,我们只需要简单地声明依赖即可。这大大简化了代码,使得开发更加快捷。
- 易于测试:由于依赖注入,我们可以很容易地用mock对象替换掉真实的依赖,进行单元测试。
- 配置集中:Spring IoC容器可以集中管理所有bean的配置信息,使得配置更加集中和一致。
- 生命周期管理:Spring IoC容器负责管理bean的完整生命周期,从创建到销毁,包括初始化和清理等操作。
- 延迟加载/懒加载:Spring IoC容器默认情况下,只有当应用实际请求一个bean时,才会创建这个bean,这叫做懒加载或延迟加载,可以提高应用的启动速度。
什么是Spring 中的 BeanFactory ?
BeanFactory 是 Spring 框架中的基础类型的工厂模式接口,它提供了高级的 IoC(Inversion of Control)功能来管理你的 beans。它主要负责初始化、配置和管理 beans,以及解决依赖关系。
当你在 Spring 的配置文件中定义一个 bean,那么 Spring IoC 容器就会通过 BeanFactory 创建一个对象(bean 实例),并根据你的配置管理这个对象的生命周期和依赖关系。
在 Spring 中,有许多 BeanFactory 的实现,如 XmlBeanFactory、DefaultListableBeanFactory 等。但在实际应用中,我们通常使用 ApplicationContext,它是 BeanFactory 的子接口,提供了更多高级特性。
例如,如果我们在 Spring 的配置文件中定义了一个名为 "myBean" 的 bean,我们可以使用 BeanFactory 来获取这个 bean 的实例:
BeanFactory factory = new XmlBeanFactory(new FileSystemResource("beans.xml"));
MyBean myBean = (MyBean) factory.getBean("myBean");
在这个例子中,"myBean" 是在 XML 配置文件中定义的 bean 的 id,getBean()
方法用于从 BeanFactory 中获取一个 bean 的实例。
什么是Spring 中的 ApplicationContext ?
ApplicationContext 是 Spring 框架中的一个核心接口,它是 BeanFactory 的子接口,也就是说,它包含了 BeanFactory 的所有功能。但是,ApplicationContext 提供了更多面向应用的功能,比如更方便的集成 Spring 的 AOP 特性,消息资源处理(用于 i18n)、事件发布、应用层的上下文(如 WebApplicationContext)等。
当启动一个 Spring 应用时,它会创建一个 ApplicationContext 实例,然后由这个实例负责初始化和配置应用中的所有对象(beans)。ApplicationContext 通过读取配置元数据(可以是 XML 文件、Java 注解、Java 代码等)来管理这些 beans 的生命周期和依赖关系。
在实际开发中,我们通常使用 ApplicationContext 的一些常见实现,如 ClassPathXmlApplicationContext、FileSystemXmlApplicationContext、AnnotationConfigApplicationContext 等。
例如,我们可以通过 ClassPathXmlApplicationContext 来加载 classpath 下的一个 XML 配置文件:
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
MyBean myBean = (MyBean) context.getBean("myBean");
在这个例子中,"myBean" 是在 XML 配置文件中定义的 bean 的 id,getBean()
方法用于从 ApplicationContext 中获取一个 bean 的实例。
Spring 常用的 ApplicationContext 有哪些?
Spring 提供了几种常用的 ApplicationContext 实现,来满足不同的环境和需求:
-
ClassPathXmlApplicationContext:这是最常用的 ApplicationContext 实现。它从类路径下的一个或多个 XML 配置文件中加载上下文定义,支持在实际应用中的各种环境。
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
-
FileSystemXmlApplicationContext:它也是一个常用的 ApplicationContext 实现。它从文件系统的某个位置加载上下文定义。
ApplicationContext context = new FileSystemXmlApplicationContext("D:/applicationContext.xml");
-
AnnotationConfigApplicationContext:它用于基于 Java 的配置类,而非 XML 文件来加载上下文定义。适用于全注解的项目,或者对源代码有控制的环境。
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
-
WebApplicationContext:它是专为 Web 应用而准备的,是个接口,分别有两个实现:XmlWebApplicationContext 和 AnnotationConfigWebApplicationContext,可以分别从 XML 文件或者注解配置中加载 Spring 应用上下文。
以上就是 Spring 常用的 ApplicationContext 实现。根据项目的需要,我们可以选择不同的 ApplicationContext 实现。
Spring 中 BeanFactory 和 ApplicationContext 的区别有哪些?
BeanFactory 和 ApplicationContext 都是 Spring 容器的核心接口,它们都可以用来获取、配置和管理 bean。但是,ApplicationContext 提供了更多高级特性,以下是它们的一些主要区别:
-
功能:BeanFactory 是最基本的容器,提供了完整的 IoC 服务支持。而 ApplicationContext 是 BeanFactory 的子接口,除了拥有 BeanFactory 的全部功能外,还添加了大量企业级的特性,如国际化支持、事件机制、更便捷的资源访问等。
-
初始化:当你创建一个 BeanFactory 实例时,它并不会立即初始化 bean,只有当你尝试获取一个 bean 时,才会触发 bean 的创建和依赖注入。而 ApplicationContext 在启动时就会创建所有的 singleton bean。这就意味着,ApplicationContext 启动会比 BeanFactory 慢,但获取 bean 的速度会更快。
-
资源访问:ApplicationContext 提供了一种更方便的方式来访问资源,如图片、音频、视频等。
-
AOP 集成:ApplicationContext 更容易集成 Spring 的 AOP 特性。
-
消息资源处理:ApplicationContext 提供了一种统一的方式来加载消息资源,这对于国际化处理非常有用。
-
Web 应用支持:ApplicationContext 提供了一种准备好的方式来构建 Web 应用。例如,它可以读取 Web.xml 中的参数,并将它们作为 bean 的属性。
总的来说,ApplicationContext 是一个更完整、更强大的容器,适合大多数应用场景。而 BeanFactory 更轻量级,适合资源有限、需要更精细控制的场景。
说一说Spring 获取 ApplicationContext 的方法?
在 Spring 中,我们可以通过多种方式获取 ApplicationContext 对象。以下是一些常见的方法:
-
在普通类中:如果你的类是由 Spring 管理的,你可以通过 @Autowired 注解将 ApplicationContext 注入到你的类中。
@Autowired private ApplicationContext context;
-
在 Spring MVC 控制器中:在 Spring MVC 控制器中,你可以通过实现 ApplicationContextAware 接口来获取 ApplicationContext。
public class MyController implements ApplicationContextAware { private ApplicationContext context; @Override public void setApplicationContext(ApplicationContext applicationContext) { this.context = applicationContext; } }
-
在 Spring Boot 应用中:在 Spring Boot 应用中,你可以在 main 方法中保存 ApplicationContext 到一个静态变量中。
public class Application { private static ApplicationContext context; public static void main(String[] args) { context = SpringApplication.run(Application.class, args); } }
-
在配置类中:在 Java 配置类中,你可以直接将 ApplicationContext 作为一个 @Bean 方法的参数。
@Configuration public class AppConfig { @Bean public MyBean myBean(ApplicationContext context) { // ... } }
以上就是在不同场景中获取 ApplicationContext 的一些方法。获取到 ApplicationContext 后,你就可以使用它来获取、查询和操作 bean 了。
解释一下Spring 依赖注入?
依赖注入(Dependency Injection,简称 DI)是 Spring 框架的核心功能之一。依赖注入是一种实现控制反转(Inversion of Control,简称 IoC)的技术,它可以帮助我们解耦代码,并提高代码的可测试性和可维护性。
依赖注入的基本思想是,一个类不应该自己去创建它依赖的对象,而应该由外部(如 Spring 容器)来负责创建和注入这些依赖对象。
例如,假设我们有一个 UserService 类,它依赖于一个 UserRepository 接口。在没有使用依赖注入的情况下,我们可能需要在 UserService 中自己去创建一个 UserRepository 的实现类:
public class UserService {
private UserRepository userRepository = new UserRepositoryImpl();
// ...
}
这样的代码存在一些问题:首先,UserService 与 UserRepositoryImpl 耦合度高,如果我们想替换另一个 UserRepository 的实现,就需要修改 UserService 的代码;其次,这样的代码很难进行单元测试,因为我们无法模拟 UserRepository。
使用依赖注入后,我们可以让 Spring 容器来创建 UserRepository 的实现类,并注入到 UserService 中:
@Service
public class UserService {
private UserRepository userRepository;
@Autowired
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
// ...
}
这样,UserService 就不再直接依赖于 UserRepositoryImpl,而是依赖于 UserRepository 接口。当我们需要替换 UserRepository 的实现,或者进行单元测试时,都可以更加容易地操作。
Spring 依赖注入的方式有哪些?
Spring 框架支持三种主要的依赖注入方式:
-
构造器注入:这是最常用的依赖注入方式。在这种方式中,我们会在类的构造器中声明依赖,然后 Spring 在创建这个 bean 时,会通过构造器参数将依赖注入进来。这种方式的优点是,可以确保 bean 的不变性和必要性,因为一旦 bean 被创建,它的依赖就不能被改变,而且必须提供所有的依赖。
@Service public class UserService { private UserRepository userRepository; @Autowired public UserService(UserRepository userRepository) { this.userRepository = userRepository; } // ... }
-
Setter 注入:在这种方式中,我们会为每个依赖提供一个 setter 方法,然后 Spring 在创建 bean 时,通过调用这些 setter 方法来注入依赖。这种方式的优点是,可以在 bean 创建后改变它的依赖,但也可能导致 bean 的状态不一致。
@Service public class UserService { private UserRepository userRepository; @Autowired public void setUserRepository(UserRepository userRepository) { this.userRepository = userRepository; } // ... }
-
字段注入:在这种方式中,我们直接在字段上使用 @Autowired 注解,然后 Spring 会在创建 bean 时,自动注入这个字段的依赖。这种方式的优点是,代码更简洁,但缺点是,我们不能在构造器中检查依赖的存在,而且很难进行单元测试。
@Service public class UserService { @Autowired private UserRepository userRepository; // ... }
以上就是 Spring 支持的三种依赖注入方式。在实际开发中,我们通常推荐使用构造器注入,因为它可以确保 bean 的不变性和必要性,而且更容易进行单元测试。
Spring 可以注入 null 和空字符串吗?
是的,Spring可以注入null值和空字符串。
对于null值的注入,可以通过在Spring配置文件中使用<null/>
标签来实现。例如:
<bean id="exampleBean" class="com.example.ExampleBean">
<property name="exampleProperty" >
<null/>
</property>
</bean>
在上述配置中,exampleProperty
属性被设置为null。
对于空字符串的注入,可以直接在配置文件中使用空的<value/>
标签或者直接将值设置为""。例如:
<bean id="exampleBean" class="com.example.ExampleBean">
<property name="exampleProperty" value=""/>
</bean>
或者
<bean id="exampleBean" class="com.example.ExampleBean">
<property name="exampleProperty">
<value></value>
</property>
</bean>
在上述两个配置中,exampleProperty
属性被设置为一个空字符串。
Spring Bean 支持哪几种作用域?
Spring框架支持以下五种作用域:
-
Singleton(单例):这是默认的作用域。在这个作用域中,Spring IoC 容器只会创建一个实例,每次请求都会返回同一个实例。这对于需要共享状态的对象非常有用。
-
Prototype(原型):在这个作用域中,每次请求都会创建一个新的实例。这对于需要独立状态的对象非常有用。
-
Request(请求):在这个作用域中,每个HTTP请求都会创建一个新的Bean。这个作用域仅在Web应用环境下有效。
-
Session(会话):在这个作用域中,每个HTTP会话都会创建一个新的Bean。这个作用域也仅在Web应用环境下有效。
-
Application(应用):在这个作用域中,Bean的生命周期与ServletContext的生命周期相同。也就是说,Bean的生命周期与整个Web应用的生命周期相同。
-
WebSocket(WebSocket会话):在这个作用域中,每个WebSocket会话都会创建一个新的Bean。这个作用域也仅在Web应用环境下有效。
通过在@Bean注解或XML配置中指定作用域,可以控制Spring Bean的生命周期。例如,下面的代码将BookService的作用域设置为Prototype,这意味着每次注入BookService时,都会创建一个新的实例:
@Bean(scope = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public BookService bookService() {
return new BookService();
}
由于内容太多,更多内容以链接形势给大家,点击进去就是答案了
22. Spring 防止相同类型 Bean 注入异常的方法?
25. Spring 中 @Component, @Service, @Repository, @Controller 的区别是什么?
26. Spring 中的 @Bean 与 @Component 注解的区别有哪些?
27. Spring 中的 @Bean 与 @Component 注解用在同一个类上,会怎么样? 容器中Bean的数量?
28. Spring 中的 @Autowired 注解的作用?
29. Spring 中的 @Autowired 注解的用法有哪些?
30. Spring 中的 @Autowired 注解默认按什么方式装配?
31. Spring 中的 @Autowired 注入 request 是线程安全的吗?
32. Spring 中使用 @Resource,@Autowired,@lnject 的区别有哪些?
33. Spring 不推荐使用 @Autowired 字段注入的原因是什么? 应该怎么使用?
34. Spring 中的 @Required 注解的作用?
35. Spring 中的 @Qualifier 注解的作用?
37. Spring 中的 Bean 有多个实现类,该怎么指定注入?
45. Spring 需要三级缓存解决循环依赖,而不是二级缓存的原因是什么?
49. Spring AOP和 AspectJ AOP 的区别有哪些?
58. Spring 中的 @Transactional 事务注解支持哪些参数?