Spring面试题及详细答案 125道(16-25) -- 核心概念与基础2
《前后端面试题
》专栏集合了前后端各个知识模块的面试题,包括html,javascript,css,vue,react,java,Openlayers,leaflet,cesium,mapboxGL,threejs,nodejs,mangoDB,SQL,Linux… 。

文章目录
- 一、本文面试题目录
- 16. 什么是Spring的自动装配?有哪些自动装配模式?
- 17. 如何禁用Spring的自动装配?
- 18. Spring中的@Qualifier注解的作用是什么?
- 19. 什么是Spring的事件机制?请举例说明。
- 20. Spring中的BeanPostProcessor有什么作用?如何使用?
- 21. Spring中的FactoryBean和BeanFactory有什么区别?请举例说明FactoryBean的应用场景。
- 22. 什么是Spring的占位符配置(如${})?如何解析?
- 23. Spring中如何处理循环依赖?三级缓存的作用是什么?
- 24. @Value注解的作用是什么?如何使用它注入配置文件中的值?
- 25. Spring中的@Profile注解有什么作用?如何通过它实现环境隔离?
- 二、125道Spring面试题目录列表
一、本文面试题目录
16. 什么是Spring的自动装配?有哪些自动装配模式?
- 定义:Spring的自动装配是指容器在创建Bean时,根据特定规则自动识别并注入该Bean所依赖的其他Bean,无需开发者在配置中显式声明依赖关系,从而减少配置工作量。
- 自动装配模式:
- no(默认):不启用自动装配,需手动通过
<property>
或@Autowired
等方式配置依赖。 - byName:根据属性名自动匹配容器中同名的Bean(如属性名为
userDao
,则匹配id="userDao"
的Bean)。<bean id="userService" class="com.example.UserService" autowire="byName"/> <bean id="userDao" class="com.example.UserDao"/> <!-- 与属性名匹配 -->
- byType:根据属性类型自动匹配容器中同类型的Bean,若存在多个同类型Bean会抛出异常。
<bean id="userService" class="com.example.UserService" autowire="byType"/> <bean class="com.example.UserDao"/> <!-- 与属性类型匹配 -->
- constructor:类似
byType
,但用于构造器参数,根据参数类型匹配依赖的Bean。 - autodetect(已过时):优先尝试
constructor
,失败则使用byType
。
- no(默认):不启用自动装配,需手动通过
17. 如何禁用Spring的自动装配?
- XML配置:在
<bean>
标签中显式设置autowire="no"
(默认值),或全局禁用自动装配:<!-- 单个Bean禁用 --> <bean id="userService" class="com.example.UserService" autowire="no"/><!-- 全局禁用(仅适用于Spring旧版本) --> <beans default-autowire="no">...</beans>
- 注解配置:
- 不使用
@Autowired
、@Resource
等自动装配注解,手动通过@Bean
方法参数注入依赖。 - 对类添加
@Autowired(required = false)
并结合@Qualifier
强制指定依赖(本质是控制装配而非禁用)。
- 不使用
- Java配置类:通过
@Bean
方法显式声明依赖,不依赖容器自动注入:@Configuration public class AppConfig {@Beanpublic UserService userService() {UserService service = new UserService();service.setUserDao(userDao()); // 手动注入return service;}@Beanpublic UserDao userDao() {return new UserDao();} }
18. Spring中的@Qualifier注解的作用是什么?
- 作用:当容器中存在多个同类型的Bean时,
@Qualifier
用于指定具体要注入的Bean名称,解决@Autowired
按类型自动装配的歧义问题。 - 使用场景:配合
@Autowired
使用,明确依赖的Bean标识。@Service public class UserService {// 容器中存在多个UserDao类型的Bean(如userDaoImpl1、userDaoImpl2)@Autowired@Qualifier("userDaoImpl1") // 指定注入id为userDaoImpl1的Beanprivate UserDao userDao; }
- XML配置对应方式:通过
<qualifier>
标签指定:<bean id="userService" class="com.example.UserService"><property name="userDao"><qualifier value="userDaoImpl1"/></property> </bean>
19. 什么是Spring的事件机制?请举例说明。
- 定义:Spring的事件机制基于观察者模式,允许Bean通过发布事件(Event)和监听事件(Listener)实现松耦合通信。核心组件包括:
ApplicationEvent
:事件基类,自定义事件需继承此类。ApplicationListener
:事件监听器接口,或使用@EventListener
注解。ApplicationEventPublisher
:事件发布器,由容器自动注入。
- 示例:
- 定义自定义事件:
public class OrderCreatedEvent extends ApplicationEvent {private String orderId;public OrderCreatedEvent(Object source, String orderId) {super(source);this.orderId = orderId;}public String getOrderId() {return orderId;} }
- 创建事件监听器:
@Component public class OrderListener {// 方式1:实现ApplicationListener接口@Componentpublic static class OrderCreatedListener implements ApplicationListener<OrderCreatedEvent> {@Overridepublic void onApplicationEvent(OrderCreatedEvent event) {System.out.println("监听订单创建:" + event.getOrderId());}}// 方式2:使用@EventListener注解(推荐)@EventListenerpublic void handleOrderEvent(OrderCreatedEvent event) {System.out.println("处理订单:" + event.getOrderId());} }
- 发布事件:
@Service public class OrderService {@Autowiredprivate ApplicationEventPublisher publisher;public void createOrder(String orderId) {// 业务逻辑...publisher.publishEvent(new OrderCreatedEvent(this, orderId));} }
- 定义自定义事件:
20. Spring中的BeanPostProcessor有什么作用?如何使用?
- 作用:
BeanPostProcessor
是Spring的后置处理器接口,用于在Bean初始化前后对其进行增强或修改,是AOP实现的基础机制之一。 - 核心方法:
postProcessBeforeInitialization
:在Bean初始化方法(如@PostConstruct
、afterPropertiesSet
)执行前调用。postProcessAfterInitialization
:在Bean初始化方法执行后调用。
- 使用示例:对Bean进行属性加密处理
@Component public class EncryptBeanPostProcessor implements BeanPostProcessor {// 初始化前处理@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {if (bean instanceof User) {User user = (User) bean;user.setPassword(encrypt(user.getPassword())); // 加密密码}return bean;}// 初始化后处理(可返回代理对象实现AOP)@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {return bean;}private String encrypt(String password) {// 加密逻辑...return password + "_encrypted";} }
- 注意:
BeanPostProcessor
会作用于容器中所有Bean,可通过beanName
或类型判断进行针对性处理。
21. Spring中的FactoryBean和BeanFactory有什么区别?请举例说明FactoryBean的应用场景。
-
区别:
特性 FactoryBean BeanFactory 本质 是一个Bean,用于创建复杂对象 是IoC容器接口,管理所有Bean 作用 自定义Bean的创建逻辑 负责Bean的注册、实例化、依赖注入 接口方法 getObject()
返回实际对象getBean()
获取容器中的Bean -
FactoryBean示例:创建数据库连接池(复杂对象)
public class DataSourceFactoryBean implements FactoryBean<DataSource> {private String url;private String username;private String password;// 设置配置参数public void setUrl(String url) { this.url = url; }public void setUsername(String username) { this.username = username; }public void setPassword(String password) { this.password = password; }// 自定义对象创建逻辑@Overridepublic DataSource getObject() throws Exception {DruidDataSource dataSource = new DruidDataSource();dataSource.setUrl(url);dataSource.setUsername(username);dataSource.setPassword(password);return dataSource;}@Overridepublic Class<?> getObjectType() {return DataSource.class;} }
-
配置与使用:
<bean id="dataSource" class="com.example.DataSourceFactoryBean"><property name="url" value="jdbc:mysql://localhost:3306/test"/><property name="username" value="root"/><property name="password" value="123456"/> </bean>
// 获取的是FactoryBean创建的DataSource对象,而非FactoryBean本身 DataSource dataSource = context.getBean("dataSource", DataSource.class);
-
应用场景:
- 创建复杂对象(如连接池、线程池、MyBatis的
SqlSessionFactory
)。 - 隐藏对象创建细节,简化配置。
- 动态生成代理对象(如AOP代理)。
- 创建复杂对象(如连接池、线程池、MyBatis的
22. 什么是Spring的占位符配置(如${})?如何解析?
- 定义:占位符配置(
${key}
)允许在Spring配置中使用外部化参数(如配置文件、环境变量),实现配置与代码分离,便于多环境部署。 - 解析方式:
- 基于XML配置:通过
PropertyPlaceholderConfigurer
或context:property-placeholder
标签:<!-- 引入配置文件 --> <context:property-placeholder location="classpath:db.properties"/><!-- 使用占位符 --> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="url" value="${db.url}"/><property name="username" value="${db.username}"/> </bean>
- 基于注解配置:结合
@PropertySource
和@Value
:@Configuration @PropertySource("classpath:db.properties") // 加载配置文件 public class DataSourceConfig {@Value("${db.url}")private String url;@Value("${db.username}")private String username;@Beanpublic DataSource dataSource() {DruidDataSource dataSource = new DruidDataSource();dataSource.setUrl(url);dataSource.setUsername(username);return dataSource;} }
- Spring Boot自动解析:默认加载
application.properties
或application.yml
,直接使用@Value("${key}")
注入。
- 基于XML配置:通过
- 注意:若占位符未找到对应值,可通过
default-value
设置默认值:${db.url:jdbc:mysql://localhost:3306/test}
。
23. Spring中如何处理循环依赖?三级缓存的作用是什么?
- 循环依赖:指两个或多个Bean相互依赖(如A依赖B,B依赖A)。Spring通过三级缓存解决单例Bean的循环依赖,原型Bean无法解决(会抛出异常)。
- 三级缓存:
- 一级缓存(singletonObjects):存储完全初始化完成的单例Bean。
- 二级缓存(earlySingletonObjects):存储提前暴露的未完全初始化的Bean实例(原始对象或代理对象)。
- 三级缓存(singletonFactories):存储Bean的工厂对象(
ObjectFactory
),用于延迟创建代理对象。
- 处理流程:
- 创建A时,先将A的工厂对象放入三级缓存,再注入依赖B。
- 创建B时,注入依赖A,此时从三级缓存获取A的工厂,生成A的早期实例(放入二级缓存),并注入B。
- B初始化完成后,注入A,A继续完成初始化,最终放入一级缓存。
- 代码验证:
上述代码可正常运行,Spring通过三级缓存解决了循环依赖。@Service public class A {@Autowiredprivate B b; // A依赖B }@Service public class B {@Autowiredprivate A a; // B依赖A }
- 注意:构造器注入的循环依赖无法解决(因构造器执行前无法暴露实例),需改为setter注入。
24. @Value注解的作用是什么?如何使用它注入配置文件中的值?
- 作用:
@Value
注解用于将外部值(配置文件、系统变量、SpEL表达式等)注入到Bean的字段或方法参数中。 - 使用方式:
- 注入配置文件值:
# application.properties app.name=MyApp app.version=1.0.0
@Component public class AppConfig {@Value("${app.name}")private String appName;@Value("${app.version:2.0.0}") // 设默认值private String appVersion; }
- 注入系统变量或环境变量:
@Value("${user.home}") // 系统变量 private String userHome;@Value("${JAVA_HOME}") // 环境变量 private String javaHome;
- 注入SpEL表达式结果:
@Value("#{T(java.lang.Math).random() * 100}") // 随机数 private double randomValue;@Value("#{systemProperties['os.name']}") // 系统属性 private String osName;
- 注入Bean的属性:
@Component public class User {private String username = "admin";// getter }@Component public class UserService {@Value("#{user.username}") // 注入其他Bean的属性private String username; }
- 注入配置文件值:
25. Spring中的@Profile注解有什么作用?如何通过它实现环境隔离?
- 作用:
@Profile
注解用于标识Bean在特定环境(如开发、测试、生产)下才会被注册到容器中,实现不同环境的配置隔离。 - 使用方式:
- 标记Bean或配置类:
// 开发环境的数据源 @Configuration @Profile("dev") public class DevDataSourceConfig {@Beanpublic DataSource dataSource() {return new HikariDataSource(...); // 开发环境配置} }// 生产环境的数据源 @Configuration @Profile("prod") public class ProdDataSourceConfig {@Beanpublic DataSource dataSource() {return new HikariDataSource(...); // 生产环境配置} }
- 激活环境:
- XML配置:
<context:property-placeholder profile="dev"/>
- Java启动参数:
-Dspring.profiles.active=dev
- 代码激活:
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); context.getEnvironment().setActiveProfiles("dev"); // 激活dev环境 context.register(AppConfig.class); context.refresh();
- XML配置:
- 默认环境:使用
@Profile("default")
标识默认激活的Bean,当未指定环境时生效。
- 标记Bean或配置类:
- 优势:避免在不同环境切换时修改配置文件,通过激活不同Profile即可加载对应环境的Bean。
二、125道Spring面试题目录列表
文章序号 | Spring面试题125道 |
---|---|
1 | Spring面试题及详细答案125道(01-15) |
2 | Spring面试题及详细答案125道(16-25) |
3 | Spring面试题及详细答案125道(26-45) |
4 | Spring面试题及详细答案125道(46-65) |
5 | Spring面试题及详细答案125道(66-75) |
6 | Spring面试题及详细答案125道(76-90) |
7 | Spring面试题及详细答案125道(91-110) |
8 | Spring面试题及详细答案125道(111-125) |