1. 解释Spring框架的核心设计理念(IoC/DI)及其优势?
答案:
Spring的核心设计理念是控制反转(IoC)和依赖注入(DI)。
- IoC:将对象的创建和管理权从代码中转移到容器,降低组件间的耦合度。
- DI:通过容器自动将依赖注入到对象中,支持构造器注入、Setter注入和字段注入。
优势:解耦组件、提高可测试性、支持AOP、统一资源管理。
2. Spring Bean的作用域有哪些?默认作用域是什么?
答案:
singleton:全局单例(默认)。prototype:每次请求创建新实例。request:HTTP请求生命周期内有效。session:HTTP会话生命周期内有效。application:ServletContext生命周期内有效。
3. @Autowired和@Resource的区别是什么?
答案:
@Autowired:按类型匹配Bean,支持required=false允许注入为null。@Resource:默认按名称匹配,可配置按类型(需指定type属性)。@Autowired是Spring特有,@Resource是JSR-250标准。
4. 如何配置Spring Bean的初始化与销毁回调?
答案:
- 注解方式:
@PostConstruct public void init() { ... } @PreDestroy public void destroy() { ... } - XML方式:
<bean init-method="init" destroy-method="destroy" />
5. Spring中ApplicationContext和BeanFactory的区别?
答案:
BeanFactory:基础接口,延迟加载Bean。ApplicationContext:扩展接口,支持国际化、事件发布、AOP等高级功能,启动时预加载Bean。
6. Spring AOP的核心术语有哪些?
答案:
- 切面(Aspect):横切关注点的模块化(如日志、事务)。
- 连接点(JoinPoint):程序执行点(如方法调用)。
- 通知(Advice):切面在连接点的具体行为(如
@Before、@After)。 - 切入点(Pointcut):定义通知应用的连接点。
- 织入(Weaving):将切面与目标对象结合的过程。
7. 基于XML和注解的AOP配置方式有何不同?
答案:
- XML配置:
<aop:config> <aop:aspect ref="loggingAspect"> <aop:before method="logBefore" pointcut="execution(* com.example.service.*.*(..))"/> </aop:aspect> </aop:config> - 注解配置:
@Aspect @Component public class LoggingAspect { @Before("execution(* com.example.service.*.*(..))") public void logBefore() { ... } }
8. Spring如何管理数据库事务?
答案:
- 使用
@Transactional注解声明事务边界。 - 配置
PlatformTransactionManager(如DataSourceTransactionManager)。 - 支持传播行为(如
REQUIRED、REQUIRES_NEW)和隔离级别。
9. JdbcTemplate的作用是什么?相比原生JDBC有何优势?
答案:
- 作用:简化JDBC操作,封装资源管理和异常转换。
- 优势:
- 自动管理
Connection、Statement、ResultSet。 - 将
SQLException转换为Spring的DataAccessException。 - 支持模板方法模式(如
queryForObject、update)。
- 自动管理
10. Spring MVC的请求处理流程是怎样的?
答案:
DispatcherServlet接收请求。- 查找匹配的
HandlerMapping(如@RequestMapping)。 - 调用
HandlerAdapter执行控制器方法。 - 返回
ModelAndView。 ViewResolver解析视图名称。- 渲染视图并返回响应。
11. Spring中Bean的生命周期包括哪些阶段?
答案:
- 实例化(Instantiation)。
- 属性注入(Populate Properties)。
- 初始化(Initialization):调用
@PostConstruct或init-method。 - 使用(In Use)。
- 销毁(Destruction):调用
@PreDestroy或destroy-method。
12. 如何解决Bean的循环依赖问题?
答案:
- Spring通过三级缓存解决:
- 提前暴露半成品Bean(一级缓存)。
- 完成依赖注入后存入二级缓存。
- 初始化完成后存入三级缓存。
- 使用
@Lazy延迟加载或重构代码消除循环。
13. Spring的ApplicationContext初始化流程?
答案:
- 加载Bean定义(XML、注解)。
- 解析Bean定义(作用域、依赖关系)。
- 实例化Bean(按需创建单例Bean)。
- 注入依赖。
- 调用初始化方法。
- 发布
ContextRefreshedEvent事件。
14. Spring事件机制的实现原理?
答案:
- 发布者通过
ApplicationEventPublisher发布事件。 - 监听器实现
ApplicationListener接口。 - 容器通过
ApplicationEventMulticaster异步或同步分发事件。 - 示例:
// 发布事件 applicationContext.publishEvent(new CustomEvent(this, "Data")); // 监听事件 @Component public class CustomListener implements ApplicationListener<CustomEvent> { @Override public void onApplicationEvent(CustomEvent event) { ... } }
15. Spring如何集成第三方框架(如MyBatis)?
答案:
- 配置
SqlSessionFactoryBean:<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> </bean> - 使用
@MapperScan扫描Mapper接口:@Configuration @MapperScan("com.example.mapper") public class MyBatisConfig { ... }
16. @Configuration和@Component注解的区别?
答案:
@Configuration:标记类为配置类,Spring会通过CGLIB代理确保Bean的单例性。@Component:通用注解,标记类为Spring组件,不保证单例性(需配合@Scope)。
17. Spring中@Import注解的三种使用场景?
答案:
- 导入配置类:
@Import(DatabaseConfig.class)。 - 动态导入Bean:通过
ImportSelector接口。 - 注册Bean定义:通过
ImportBeanDefinitionRegistrar接口。
18. 如何动态注册Bean?
答案:
实现BeanDefinitionRegistryPostProcessor接口:
public class CustomBeanRegistrar implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
GenericBeanDefinition definition = new GenericBeanDefinition();
definition.setBeanClass(MyBean.class);
registry.registerBeanDefinition("myBean", definition);
}
}
19. Spring的国际化(i18n)支持如何实现?
答案:
- 配置
MessageSource:<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource"> <property name="basename" value="messages"/> </bean> - 使用
LocaleResolver解析请求语言。 - 通过
#{messageSource.getMessage('key', null, locale)}获取消息。
20. Spring如何处理文件上传?
答案:
- 配置
MultipartResolver:<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"/> - 控制器方法接收
MultipartFile参数:@PostMapping("/upload") public String upload(@RequestParam("file") MultipartFile file) { ... }
21. Spring的@Conditional注解家族有哪些典型应用场景?
答案:
@Conditional根据条件决定是否注册Bean,典型场景包括:
- 按操作系统类型:
@Conditional(WindowsCondition.class) @Bean public String windowsService() { return "Windows"; } - 按配置文件存在性:
@ConditionalOnProperty(name = "feature.enabled", havingValue = "true") - 按类路径是否存在:
@ConditionalOnClass(DataSource.class)
22. Spring的FactoryBean和普通Bean的区别?
答案:
FactoryBean用于创建复杂对象(如代理、连接池)。- 示例:
public class CarFactoryBean implements FactoryBean<Car> { @Override public Car getObject() { return new Car(); } @Override public Class<?> getObjectType() { return Car.class; } } - 普通Bean直接通过构造函数或工厂方法实例化。
23. 如何自定义Spring的Scope?
答案:
- 实现
Scope接口:public class ThreadLocalScope implements Scope { private final ThreadLocal<Map<String, Object>> threadScope = new ThreadLocal<>(); // 实现get、remove、registerDestructionCallback等方法 } - 注册到容器:
@Configuration public class AppConfig { @Bean public static CustomScopeConfigurer scopeConfigurer() { CustomScopeConfigurer configurer = new CustomScopeConfigurer(); configurer.addScope("thread", new ThreadLocalScope()); return configurer; } }
24. Spring的@Profile注解如何实现环境隔离?
答案:
- 通过
@Profile("dev")标记Bean仅在开发环境激活。 - 激活方式:
或启动时指定:# application.properties spring.profiles.active=devSpringApplication.run(App.class, "--spring.profiles.active=prod");
25. Spring的缓存抽象(Cache Abstraction)如何工作?
答案:
- 启用缓存:
@EnableCaching。 - 使用
@Cacheable缓存结果:@Cacheable("users") public User getUser(String id) { ... } - 配置缓存管理器(如Redis):
@Bean public CacheManager cacheManager(RedisConnectionFactory factory) { return RedisCacheManager.builder(factory).build(); }
26. Spring的@Scheduled注解如何实现定时任务?
答案:
- 启用调度:
@EnableScheduling。 - 配置任务:
@Scheduled(fixedRate = 5000) public void reportCurrentTime() { ... } - 线程池配置:
@Bean public TaskScheduler taskScheduler() { ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); scheduler.setPoolSize(10); return scheduler; }
27. Spring的TaskExecutor接口有哪些实现类?
答案:
SimpleAsyncTaskExecutor:简单异步执行。SyncTaskExecutor:同步执行(默认)。ThreadPoolTaskExecutor:线程池实现(推荐):@Bean public TaskExecutor taskExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(5); executor.setMaxPoolSize(10); return executor; }
28. Spring如何集成JUnit 5进行单元测试?
答案:
- 使用
@ExtendWith(SpringExtension.class)。 - 配置测试上下文:
@SpringBootTest @ContextConfiguration(classes = TestConfig.class) public class UserServiceTest { @Autowired private UserService userService; }
29. Spring的@Value注解如何注入配置值?
答案:
- 注入属性文件值:
@Value("${app.name}") private String appName; - 注入SpEL表达式:
@Value("#{systemProperties['user.home']}") private String userHome;
30. Spring框架在JDK 8+中的新特性适配?
答案:
- Lambda表达式:简化监听器注册(如
@EventListener)。 - 重复注解:
@Repeatable支持多个@Scheduled任务。 - 接口默认方法:增强
ApplicationContext的扩展性。
31. Spring中Bean的初始化方法有哪些配置方式?
答案:
@PostConstruct注解。InitializingBean接口:public class MyBean implements InitializingBean { @Override public void afterPropertiesSet() { ... } }- XML配置
init-method属性。
32. @Autowired(required=false)的作用是什么?
答案:
- 允许依赖为
null,避免因Bean不存在导致启动失败。 - 示例:
@Autowired(required = false) private Optional<DataSource> dataSource;
33. 如何在Spring中配置多个数据源?
答案:
- 使用
@Primary标记主数据源:@Bean @Primary public DataSource primaryDataSource() { ... } - 动态路由数据源:
@Bean public DataSource dataSource() { AbstractRoutingDataSource router = new AbstractRoutingDataSource(); router.setDefaultTargetDataSource(primaryDataSource()); return router; }
34. Spring MVC的@Controller与@RestController有何区别?
答案:
@RestController=@Controller+@ResponseBody。- 示例:
@RestController public class UserController { @GetMapping("/user") public User getUser() { return new User(); } // 直接返回JSON }
35. @Transactional注解在什么情况下会失效?
答案:
- 异常被捕获未抛出。
- 非public方法。
- 自调用(同一类内方法调用)。
- 错误的事务传播行为配置。
36. 如何自定义Spring的BeanFactoryPostProcessor?
答案:
- 实现接口:
public class CustomBeanFactoryPostProcessor implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { // 修改Bean定义属性 } } - 注册为Bean:
@Bean public static BeanFactoryPostProcessor customBeanFactoryPostProcessor() { return new CustomBeanFactoryPostProcessor(); }
37. Spring事件机制中,如何实现异步事件监听?
答案:
- 配置事件多播器:
@Bean public ApplicationEventMulticaster simpleApplicationEventMulticaster() { SimpleApplicationEventMulticaster multicaster = new SimpleApplicationEventMulticaster(); multicaster.setTaskExecutor(new SimpleAsyncTaskExecutor()); return multicaster; } - 发布异步事件:
applicationEventPublisher.publishEvent(new CustomEvent(this, "Data"));
38. @ImportResource注解的作用及典型场景?
答案:
- 作用:导入XML配置文件到注解驱动的上下文。
- 场景:混合使用XML和注解配置(如遗留系统迁移)。
- 示例:
@Configuration @ImportResource("classpath:legacy-context.xml") public class AppConfig { ... }
39. Spring如何集成JUnit 5进行模块化测试?
答案:
- 使用
@ContextConfiguration指定配置类:@SpringJUnitConfig(TestConfig.class) public class ModuleTest { ... } - 结合
@MockBean隔离依赖:@MockBean private RemoteService remoteService;
40. @Cacheable注解支持哪些条件表达式?举例说明。
答案:
unless:否定条件(不缓存结果):@Cacheable(value = "users", unless = "#result.size() < 1")condition:肯定条件(仅当满足时缓存):@Cacheable(value = "users", condition = "#name.length() > 3")- SpEL表达式:
#root.method.name、#p0(方法参数)。
41. Spring如何处理BeanCreationException?常见原因有哪些?
答案:
- 异常链分析:检查根因(如循环依赖、Bean配置错误)。
- 常见原因:
- 循环依赖未解决。
- Bean定义错误(如缺少构造函数参数)。
- 资源加载失败(如文件路径错误)。
- 事务管理器配置错误。
42. @Lazy注解在单例Bean中的作用是什么?
答案:
- 延迟初始化Bean,减少启动时间。
- 示例:
@Bean @Lazy public HeavyBean heavyBean() { return new HeavyBean(); } - 结合
@DependsOn解决初始化顺序问题。
43. 如何在Spring中注册自定义属性编辑器(PropertyEditor)?
答案:
- 实现
PropertyEditor接口:public class CustomDateEditor extends PropertyEditorSupport { @Override public void setAsText(String text) { setValue(LocalDate.parse(text)); } } - 注册到
CustomEditorConfigurer:@Bean public CustomEditorConfigurer customEditorConfigurer() { CustomEditorConfigurer configurer = new CustomEditorConfigurer(); configurer.setCustomEditors(Collections.singletonMap(LocalDate.class, new CustomDateEditor())); return configurer; }
44. Spring的MessageSource如何实现国际化?
答案:
- 配置资源文件:
# messages.properties greeting=Hello # messages_zh_CN.properties greeting=你好 - 使用
MessageSource:@Autowired private MessageSource messageSource; public String getGreeting(Locale locale) { return messageSource.getMessage("greeting", null, locale); }
45. @Autowired与@Inject注解的异同?
答案:
- 相同点:均支持依赖注入。
- 不同点:
@Inject是JSR-330标准,无required属性。@Autowired是Spring特有,支持required=false。
46. 如何实现方法级别的切面(Method-level Aspect)?
答案:
- 定义切面:
@Aspect @Component public class LoggingAspect { @Around("execution(* com.example.service.*.*(..))") public Object logMethod(ProceedingJoinPoint joinPoint) throws Throwable { System.out.println("Before method: " + joinPoint.getSignature()); Object result = joinPoint.proceed(); System.out.println("After method: " + joinPoint.getSignature()); return result; } } - 启用AOP:
@EnableAspectJAutoProxy。
47. @Profile与@Conditional如何协同工作?
答案:
@Profile激活Bean,@Conditional细化条件。- 示例:
@Profile("dev") @ConditionalOnProperty(name = "debug.enabled", havingValue = "true") @Bean public DebugLogger debugLogger() { ... }
48. 如何在Spring中定义自定义XML标签(如<mytag:config>)?
答案:
- 实现
NamespaceHandler:public class MyNamespaceHandler extends NamespaceHandlerSupport { @Override public void init() { registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser()); } } - 实现
BeanDefinitionParser:public class ConfigBeanDefinitionParser implements BeanDefinitionParser { @Override public BeanDefinition parse(Element element, ParserContext parserContext) { // 解析XML元素并创建Bean定义 } } - 注册到
META-INF/spring.handlers:http\://example.com/schema/mytag=com.example.MyNamespaceHandler
49. TaskExecutor接口有哪些实现类?如何配置异步任务?
答案:
- 实现类:
SimpleAsyncTaskExecutor、SyncTaskExecutor、ThreadPoolTaskExecutor。 - 配置异步任务:
@Bean public TaskExecutor taskExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(5); executor.setMaxPoolSize(10); executor.setQueueCapacity(25); return executor; }
50. @PostConstruct与InitializingBean的使用场景对比?
答案:
@PostConstruct:注解方式更简洁,推荐用于新代码。InitializingBean:接口方式适用于类无法修改的场景(如第三方库)。- 示例:
// 注解方式 @PostConstruct public void init() { ... } // 接口方式 public class LegacyService implements InitializingBean { @Override public void afterPropertiesSet() { ... } }
51. Spring如何解决循环依赖中的代理对象问题?
答案:
Spring通过三级缓存机制解决循环依赖中的代理问题:
- 一级缓存(singletonObjects):存储完全初始化的Bean。
- 二级缓存(earlySingletonObjects):存储已实例化但未注入依赖的半成品Bean。
- 三级缓存(singletonFactories):存储Bean工厂对象,用于生成代理(如AOP增强)。
流程:
- BeanA实例化后暴露工厂到三级缓存。
- BeanB注入BeanA时,从三级缓存获取工厂并提前生成代理对象。
- BeanA完成初始化后存入一级缓存,BeanB使用代理对象完成注入。
52. 如何在Spring中集成Hibernate作为ORM框架?
答案:
- 添加依赖:
<dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> </dependency> - 配置
LocalSessionFactoryBean:@Bean public LocalSessionFactoryBean sessionFactory(DataSource dataSource) { LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean(); sessionFactory.setDataSource(dataSource); sessionFactory.setPackagesToScan("com.example.entity"); Properties hibernateProps = new Properties(); hibernateProps.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL8Dialect"); sessionFactory.setHibernateProperties(hibernateProps); return sessionFactory; } - 启用事务管理:
@Bean public PlatformTransactionManager transactionManager(SessionFactory sessionFactory) { return new HibernateTransactionManager(sessionFactory); }
53. @EventListener如何与事务阶段绑定?
答案:
使用@TransactionalEventListener的phase属性:
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void handleEvent(CustomEvent event) {
// 事务提交后执行
}
阶段选项:
BEFORE_COMMIT:事务提交前。AFTER_COMMIT:事务提交后(默认)。AFTER_ROLLBACK:事务回滚后。AFTER_COMPLETION:事务完成(提交或回滚)后。
54. @Order注解在多个切面中的优先级如何控制?
答案:
- 值越小优先级越高。
- 示例:
@Aspect @Order(1) // 高优先级 public class LoggingAspect { ... } @Aspect @Order(2) // 低优先级 public class AuditAspect { ... } - 或通过实现
Ordered接口:public class CustomAspect implements Ordered { @Override public int getOrder() { return 1; } }
55. 如何自定义BeanPostProcessor实现Bean的动态增强?
答案:
- 实现接口:
public class CustomBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) { // 初始化前处理 return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) { // 初始化后处理(如动态代理) if (bean instanceof TargetInterface) { return Proxy.newProxyInstance(...); } return bean; } } - 注册为Bean:
@Bean public static BeanPostProcessor customBeanPostProcessor() { return new CustomBeanPostProcessor(); }
56. @Scheduled注解支持哪些触发器配置?
答案:
fixedRate:固定速率(毫秒)。fixedDelay:固定延迟(毫秒)。cron:Cron表达式。zone:时区配置。
示例:
@Scheduled(cron = "0 0 8 * * ?", zone = "Asia/Shanghai")
public void dailyTask() { ... }
57. @Qualifier注解在自动装配中的底层逻辑?
答案:
- 根据Bean名称或限定符名称匹配候选Bean。
- 示例:
@Autowired @Qualifier("primaryDataSource") private DataSource dataSource; - 底层通过
QualifierAnnotationAutowireCandidateResolver解析注解。
58. 如何实现AOP的环绕通知(Around Advice)?
答案:
- 定义切面:
@Aspect @Component public class LoggingAspect { @Around("execution(* com.example.service.*.*(..))") public Object logMethod(ProceedingJoinPoint joinPoint) throws Throwable { System.out.println("Before method: " + joinPoint.getSignature()); Object result = joinPoint.proceed(); // 执行目标方法 System.out.println("After method: " + joinPoint.getSignature()); return result; } } - 启用AOP:
@EnableAspectJAutoProxy。
59. ApplicationContextAware接口如何获取应用上下文?
答案:
- 实现接口:
@Component public class ContextHolder implements ApplicationContextAware { private static ApplicationContext context; @Override public void setApplicationContext(ApplicationContext applicationContext) { context = applicationContext; } public static <T> T getBean(Class<T> type) { return context.getBean(type); } } - 通过静态方法获取Bean:
UserService userService = ContextHolder.getBean(UserService.class);
60. @Import与@ComponentScan的扫描机制有何不同?
答案:
@Import:显式导入配置类或Bean定义。@ComponentScan:按包路径扫描组件(如@Service、@Repository)。- 示例:
@Configuration @Import(DatabaseConfig.class) // 导入配置类 @ComponentScan("com.example.service") // 扫描服务层组件 public class AppConfig { ... }
61. Spring中Bean的初始化方法有哪些配置方式?
答案:
@PostConstruct注解。InitializingBean接口。- XML配置
init-method属性。 - 优先级:
@PostConstruct>InitializingBean.afterPropertiesSet()>init-method。
62. @Autowired(required=false)的作用是什么?
答案:
- 允许依赖为
null,避免因Bean不存在导致启动失败。 - 示例:
@Autowired(required = false) private Optional<DataSource> dataSource;
63. Spring MVC的DispatcherServlet如何处理请求映射?
答案:
- 查找匹配的
HandlerMapping(如@RequestMapping)。 - 调用
HandlerAdapter执行控制器方法。 - 返回
ModelAndView。 - 通过
ViewResolver解析视图名称。 - 渲染视图并返回响应。
64. 事务的Propagation.REQUIRES_NEW行为具体表现?
答案:
- 无论外层事务是否存在,始终开启新事务。
- 外层事务回滚不影响内层事务。
- 示例:
@Transactional(propagation = Propagation.REQUIRES_NEW) public void innerTransactionalMethod() { ... }
65. 如何配置Spring管理多个数据源?
答案:
- 使用
@Primary标记主数据源:@Bean @Primary public DataSource primaryDataSource() { ... } - 动态路由数据源:
@Bean public DataSource dataSource() { AbstractRoutingDataSource router = new AbstractRoutingDataSource(); router.setDefaultTargetDataSource(primaryDataSource()); return router; }
66. @PreDestroy注解在Bean销毁时的触发条件?
答案:
- Bean从容器移除前调用(如
ConfigurableApplicationContext.close())。 - 示例:
@PreDestroy public void cleanup() { ... }
67. Spring的依赖注入方式有哪些?
答案:
- 构造器注入:推荐方式,支持不可变对象。
- Setter注入:适用于可选依赖。
- 字段注入:简洁但不利于单元测试(不推荐)。
示例:
@Service
public class UserService {
private final UserRepository userRepository;
@Autowired // 构造器注入
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
}
68. prototype作用域的Bean在依赖注入时的行为特点?
答案:
- 每次注入时创建新实例。
- 需结合
@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)解决代理问题:@Bean @Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS) public PrototypeBean prototypeBean() { ... }
69. Spring如何解决三级缓存中的循环依赖?
答案:
- 通过早期暴露对象引用(半成品Bean)的机制。
- 流程:
- BeanA实例化后存入三级缓存。
- BeanB注入BeanA时,从三级缓存获取工厂并生成代理。
- BeanA完成初始化后存入一级缓存,BeanB使用代理对象。
70. JdbcTemplate相比原生JDBC的优势?
答案:
- 自动管理
Connection、Statement、ResultSet。 - 异常转换(
SQLException→DataAccessException)。 - 支持模板方法模式(如
queryForObject、update)。 - 集成事务管理。
71. 如何自定义Spring事件监听器并实现异步处理?
答案:
- 定义事件:
public class CustomEvent extends ApplicationEvent { ... } - 实现监听器:
@Component public class CustomListener { @Async @EventListener public void handleEvent(CustomEvent event) { ... } } - 配置异步支持:
@EnableAsync @Configuration public class AsyncConfig implements AsyncConfigurer { @Override public Executor getAsyncExecutor() { return Executors.newFixedThreadPool(10); } }
72. Spring国际化(i18n)的完整配置流程?
答案:
- 配置资源文件:
# messages.properties greeting=Hello # messages_zh_CN.properties greeting=你好 - 定义
MessageSource:@Bean public MessageSource messageSource() { ResourceBundleMessageSource source = new ResourceBundleMessageSource(); source.setBasename("messages"); return source; } - 使用
LocaleResolver解析语言:@Bean public LocaleResolver localeResolver() { SessionLocaleResolver resolver = new SessionLocaleResolver(); resolver.setDefaultLocale(Locale.ENGLISH); return resolver; }
73. @Cacheable的key生成策略有哪些?
答案:
- 默认使用方法参数。
- SpEL自定义表达式:
@Cacheable(value = "users", key = "#userId") public User getUser(String userId) { ... } - 复合键:
@Cacheable(value = "orders", key = "#userId + '-' + #orderId")
74. @Scheduled如何配置固定延迟任务?
答案:
- 使用
fixedDelay属性:@Scheduled(fixedDelay = 5000) public void processTask() { ... } - 线程池隔离:
@Bean public TaskScheduler taskScheduler() { ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); scheduler.setPoolSize(5); return scheduler; }
75. 如何自定义属性编辑器(PropertyEditor)?
答案:
- 实现接口:
public class CustomDateEditor extends PropertyEditorSupport { @Override public void setAsText(String text) { setValue(LocalDate.parse(text)); } } - 注册到
CustomEditorConfigurer:@Bean public CustomEditorConfigurer customEditorConfigurer() { CustomEditorConfigurer configurer = new CustomEditorConfigurer(); configurer.setCustomEditors(Collections.singletonMap(LocalDate.class, new CustomDateEditor())); return configurer; }
76. 注解驱动的AOP配置与XML方式的区别?
答案:
- 注解驱动:
@EnableAspectJAutoProxy @Configuration public class AppConfig { ... } - XML方式:
<aop:aspectj-autoproxy/> - 区别:注解方式更简洁,XML方式适合遗留系统或复杂切面配置。
77. Spring测试如何加载部分配置类?
答案:
- 使用
@ContextConfiguration指定配置类:@SpringJUnitConfig(classes = {TestConfig.class, DatabaseConfig.class}) public class UserServiceTest { ... }
78. @Conditional注解如何实现条件化Bean注册?
答案:
- 通过
Condition接口判断条件:public class WindowsCondition implements Condition { @Override public boolean matches(ConditionContext ctx, AnnotatedTypeMetadata metadata) { return ctx.getEnvironment().getProperty("os.name").contains("Windows"); } } - 使用注解:
@Bean @Conditional(WindowsCondition.class) public String windowsService() { ... }
79. 如何自定义Spring的Scope?
答案:
- 实现
Scope接口:public class ThreadLocalScope implements Scope { private final ThreadLocal<Map<String, Object>> threadScope = new ThreadLocal<>(); // 实现get、remove、registerDestructionCallback等方法 } - 注册到容器:
@Bean public static CustomScopeConfigurer scopeConfigurer() { CustomScopeConfigurer configurer = new CustomScopeConfigurer(); configurer.addScope("thread", new ThreadLocalScope()); return configurer; }
80. 动态注册Bean的两种方式?
答案:
BeanDefinitionRegistryPostProcessor:public class CustomRegistrar implements BeanDefinitionRegistryPostProcessor { @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) { GenericBeanDefinition definition = new GenericBeanDefinition(); definition.setBeanClass(MyBean.class); registry.registerBeanDefinition("myBean", definition); } }DefaultListableBeanFactory.registerBeanDefinition:DefaultListableBeanFactory factory = (DefaultListableBeanFactory) applicationContext.getAutowireCapableBeanFactory(); factory.registerBeanDefinition("dynamicBean", new RootBeanDefinition(DynamicBean.class));
81. 自定义BeanFactoryPostProcessor的典型场景?
答案:
- 修改Bean定义属性(如替换占位符)。
- 动态注入属性:
public class CustomBeanFactoryPostProcessor implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { BeanDefinition bd = beanFactory.getBeanDefinition("dataSource"); bd.getPropertyValues().add("url", "jdbc:mysql://new-host:3306/db"); } }
82. Spring性能优化的关键策略?
答案:
- 延迟加载:使用
@Lazy减少启动时间。 - 缓存配置:启用
@Cacheable减少重复计算。 - 减少Bean作用域:避免
prototype作用域。 - 异步事件处理:使用
@Async解耦耗时操作。 - 避免自调用事务:确保
@Transactional生效。
83. Spring集成JUnit 5的扩展点?
答案:
@ExtendWith(SpringExtension.class):启用Spring测试上下文。@TestConfiguration:定义测试专用配置:@TestConfiguration public class TestConfig { @Bean public DataSource dataSource() { return new EmbeddedDatabaseBuilder().build(); } }
84. 如何定义自定义XML命名空间?
答案:
- 实现
NamespaceHandler:public class MyNamespaceHandler extends NamespaceHandlerSupport { @Override public void init() { registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser()); } } - 实现
BeanDefinitionParser:public class ConfigBeanDefinitionParser implements BeanDefinitionParser { @Override public BeanDefinition parse(Element element, ParserContext parserContext) { // 解析XML元素并创建Bean定义 } } - 注册到
META-INF/spring.handlers:http\://example.com/schema/mytag=com.example.MyNamespaceHandler
85. Spring事务管理器的选择依据?
答案:
DataSourceTransactionManager:单机数据库事务(JDBC、MyBatis)。JtaTransactionManager:分布式事务(需JTA实现,如Atomikos)。HibernateTransactionManager:Hibernate专属事务管理。
86. 自定义BeanPostProcessor实现AOP的原理?
答案:
- 通过
postProcessAfterInitialization方法包装Bean为代理对象:public Object postProcessAfterInitialization(Object bean, String beanName) { if (bean instanceof TargetInterface) { return Proxy.newProxyInstance(getClass().getClassLoader(), new Class<?>[] { TargetInterface.class }, new InvocationHandler() { ... }); } return bean; }
87. Spring事件发布机制的底层实现?
答案:
- 基于观察者模式,通过
ApplicationEventMulticaster分发事件。 - 流程:
- 发布者调用
ApplicationEventPublisher.publishEvent()。 - 多播器查找匹配的监听器。
- 异步或同步调用监听器方法。
- 发布者调用
88. Spring缓存抽象(Cache Abstraction)的扩展点?
答案:
- 实现
CacheManager(如Redis):@Bean public CacheManager cacheManager(RedisConnectionFactory factory) { return RedisCacheManager.builder(factory).build(); } - 实现
Cache接口自定义缓存行为。
89. Spring AOP默认使用哪种动态代理?
答案:
- JDK动态代理:基于接口实现(默认)。
- CGLIB代理:基于类代理(需
proxyTargetClass=true):@EnableAspectJAutoProxy(proxyTargetClass = true)
90. 如何配置Spring测试的分层上下文?
答案:
- 使用
@ActiveProfiles隔离环境配置:@ActiveProfiles("test") @SpringBootTest public class TestClass { ... } - 使用
@TestPropertySource覆盖属性:@TestPropertySource(properties = "app.name=test-app")
91. Spring中Bean的默认作用域是什么?如何修改?
答案:
- 默认作用域:
singleton(全局单例)。 - 修改方式:
@Scope注解:@Bean @Scope("prototype") public PrototypeBean prototypeBean() { ... }- XML配置:
<bean id="bean" class="com.example.Bean" scope="prototype"/>
92. @Autowired与@Resource的注入顺序优先级如何?
答案:
@Autowired:按类型匹配,若存在多个候选Bean,结合@Qualifier按名称匹配。@Resource:默认按名称匹配,若未找到,按类型匹配。- 优先级:
@Resource的名称匹配优先级高于@Autowired的类型匹配。
93. Spring MVC的DispatcherServlet如何处理静态资源?
答案:
- 配置静态资源映射:
@Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/static/**") .addResourceLocations("classpath:/static/"); } } - 或XML配置:
<mvc:resources mapping="/static/**" location="/static/"/>
94. 事务的Propagation.NESTED行为与REQUIRES_NEW有何不同?
答案:
NESTED:在嵌套事务内提交/回滚,外层事务回滚可能导致内层回滚(取决于数据库支持)。REQUIRES_NEW:始终独立事务,外层事务回滚不影响内层。- 示例:
@Transactional(propagation = Propagation.NESTED) public void nestedTransactionalMethod() { ... }
95. JdbcTemplate的queryForObject方法在查询空结果时的行为?
答案:
- 抛出
EmptyResultDataAccessException异常。 - 处理方式:
try { User user = jdbcTemplate.queryForObject("SELECT * FROM users WHERE id = ?", new Object[]{id}, userRowMapper); } catch (EmptyResultDataAccessException e) { // 处理空结果 }
96. 如何配置Spring的国际化消息源?
答案:
- 定义资源文件:
# messages.properties greeting=Hello # messages_zh_CN.properties greeting=你好 - 配置
MessageSource:@Bean public MessageSource messageSource() { ResourceBundleMessageSource source = new ResourceBundleMessageSource(); source.setBasename("messages"); return source; }
97. @PostConstruct和@PreDestroy注解的生命周期阶段?
答案:
@PostConstruct:Bean初始化后执行(属性注入完成后)。@PreDestroy:Bean销毁前执行(容器关闭时)。- 对应Bean生命周期阶段:
实例化 → 属性注入 → @PostConstruct → 使用 → @PreDestroy → 销毁
98. Spring如何解决单例Bean的循环依赖?
答案:
- 通过三级缓存提前暴露对象引用(半成品Bean)。
- 流程:
- BeanA实例化后存入三级缓存。
- BeanB注入BeanA时,从三级缓存获取工厂并生成代理。
- BeanA完成初始化后存入一级缓存,BeanB使用代理对象完成注入。
99. 注解驱动配置与XML配置的混合使用场景?
答案:
- 使用
@ImportResource导入XML配置:@Configuration @ImportResource("classpath:legacy-context.xml") public class AppConfig { ... } - 或通过
@ComponentScan扫描注解类:@Configuration @ComponentScan("com.example") public class AppConfig { ... }
100. @Cacheable的sync属性作用是什么?
答案:
- 启用同步缓存,避免缓存击穿(需Spring 4.3+)。
- 示例:
@Cacheable(value = "users", sync = true) public User getUser(String id) { ... }
101. 如何自定义Spring的Bean作用域?
答案:
- 实现
Scope接口:public class ThreadLocalScope implements Scope { private final ThreadLocal<Map<String, Object>> threadScope = new ThreadLocal<>(); // 实现get、remove、registerDestructionCallback等方法 } - 注册到容器:
@Bean public static CustomScopeConfigurer scopeConfigurer() { CustomScopeConfigurer configurer = new CustomScopeConfigurer(); configurer.addScope("thread", new ThreadLocalScope()); return configurer; }
102. Spring事件驱动架构的典型应用场景?
答案:
- 解耦业务逻辑(如订单创建后发送通知)。
- 示例:
// 发布事件 applicationEventPublisher.publishEvent(new OrderCreatedEvent(order)); // 监听事件 @Component public class OrderNotifier { @EventListener public void handleOrderCreated(OrderCreatedEvent event) { sendNotification(event.getOrder()); } }
103. AOP中@Around通知如何控制目标方法执行?
答案:
- 通过
ProceedingJoinPoint.proceed()决定是否执行目标方法:@Around("execution(* com.example.service.*.*(..))") public Object logMethod(ProceedingJoinPoint joinPoint) throws Throwable { System.out.println("Before method: " + joinPoint.getSignature()); Object result = joinPoint.proceed(); // 执行目标方法 System.out.println("After method: " + joinPoint.getSignature()); return result; }
104. 动态注册Bean的两种方式及适用场景?
答案:
BeanDefinitionRegistryPostProcessor:- 适用场景:启动时动态注册Bean。
- 示例:
public class CustomRegistrar implements BeanDefinitionRegistryPostProcessor { @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) { GenericBeanDefinition definition = new GenericBeanDefinition(); definition.setBeanClass(MyBean.class); registry.registerBeanDefinition("myBean", definition); } }
DefaultListableBeanFactory.registerBeanDefinition:- 适用场景:运行时动态注册Bean。
- 示例:
DefaultListableBeanFactory factory = (DefaultListableBeanFactory) applicationContext.getAutowireCapableBeanFactory(); factory.registerBeanDefinition("dynamicBean", new RootBeanDefinition(DynamicBean.class));
105. Spring测试中@DirtiesContext的作用?
答案:
- 标记测试方法会修改应用上下文,强制重新加载Bean。
- 示例:
@DirtiesContext @Test public void testModifyContext() { ... }
106. 如何集成Hibernate作为Spring的ORM框架?
答案:
- 添加依赖:
<dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> </dependency> - 配置
LocalSessionFactoryBean:@Bean public LocalSessionFactoryBean sessionFactory(DataSource dataSource) { LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean(); sessionFactory.setDataSource(dataSource); sessionFactory.setPackagesToScan("com.example.entity"); Properties hibernateProps = new Properties(); hibernateProps.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL8Dialect"); sessionFactory.setHibernateProperties(hibernateProps); return sessionFactory; } - 启用事务管理:
@Bean public PlatformTransactionManager transactionManager(SessionFactory sessionFactory) { return new HibernateTransactionManager(sessionFactory); }
107. 选择DataSourceTransactionManager还是JtaTransactionManager的依据?
答案:
DataSourceTransactionManager:单机数据库事务(JDBC、MyBatis)。JtaTransactionManager:分布式事务(需JTA实现,如Atomikos)。- 示例:
@Bean public PlatformTransactionManager transactionManager(DataSource dataSource) { return new DataSourceTransactionManager(dataSource); }
108. 自定义属性编辑器(PropertyEditor)的步骤?
答案:
- 实现接口:
public class CustomDateEditor extends PropertyEditorSupport { @Override public void setAsText(String text) { setValue(LocalDate.parse(text)); } } - 注册到
CustomEditorConfigurer:@Bean public CustomEditorConfigurer customEditorConfigurer() { CustomEditorConfigurer configurer = new CustomEditorConfigurer(); configurer.setCustomEditors(Collections.singletonMap(LocalDate.class, new CustomDateEditor())); return configurer; }
109. @Scheduled如何配置固定速率任务?
答案:
- 使用
fixedRate属性:@Scheduled(fixedRate = 5000) public void processTask() { ... } - 线程池隔离:
@Bean public TaskScheduler taskScheduler() { ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); scheduler.setPoolSize(5); return scheduler; }
110. 多数据源路由的两种实现方式?
答案:
AbstractRoutingDataSource:- 抽象类,通过
determineCurrentLookupKey()动态路由。 - 示例:
public class DynamicDataSource extends AbstractRoutingDataSource { @Override protected Object determineCurrentLookupKey() { return DataSourceContextHolder.getDataSourceKey(); } }
- 抽象类,通过
@Primary注解:- 标记主数据源,其他数据源通过
@Qualifier指定:@Bean @Primary public DataSource primaryDataSource() { ... } @Bean public DataSource secondaryDataSource() { ... }
- 标记主数据源,其他数据源通过
111. Spring IoC容器初始化的底层流程?
答案:
- 资源加载:解析配置文件(XML、注解)。
- Bean定义解析:创建
BeanDefinition对象。 - 依赖注入:实例化Bean并注入属性。
- 初始化回调:调用
@PostConstruct或init-method。 - 事件发布:触发
ContextRefreshedEvent事件。
112. Spring性能优化的关键策略?
答案:
- 延迟加载:使用
@Lazy减少启动时间。 - 缓存配置:启用
@Cacheable减少重复计算。 - 减少Bean作用域:避免
prototype作用域。 - 异步事件处理:使用
@Async解耦耗时操作。 - 避免自调用事务:确保
@Transactional生效。
113. 集成测试与单元测试在Spring中的区别?
答案:
- 集成测试:加载完整应用上下文,验证组件间协作。
- 示例:
@SpringBootTest public class IntegrationTest { ... }
- 示例:
- 单元测试:使用Mock对象(如
@MockBean)隔离依赖。- 示例:
@ExtendWith(MockitoExtension.class) public class UnitTest { @Mock private RemoteService remoteService; }
- 示例:
114. 如何定义自定义XML命名空间?
答案:
- 实现
NamespaceHandler:public class MyNamespaceHandler extends NamespaceHandlerSupport { @Override public void init() { registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser()); } } - 实现
BeanDefinitionParser:public class ConfigBeanDefinitionParser implements BeanDefinitionParser { @Override public BeanDefinition parse(Element element, ParserContext parserContext) { // 解析XML元素并创建Bean定义 } } - 注册到
META-INF/spring.handlers:http\://example.com/schema/mytag=com.example.MyNamespaceHandler
115. Spring缓存抽象的扩展点有哪些?
答案:
- 实现
CacheManager(如Redis):@Bean public CacheManager cacheManager(RedisConnectionFactory factory) { return RedisCacheManager.builder(factory).build(); } - 实现
Cache接口自定义缓存行为。
116. JDK动态代理与CGLIB代理的选择策略?
答案:
- JDK动态代理:基于接口实现(默认)。
- CGLIB代理:基于类代理(需
proxyTargetClass=true):@EnableAspectJAutoProxy(proxyTargetClass = true)
117. 如何实现事件监听器的异步处理?
答案:
- 配置异步支持:
@EnableAsync @Configuration public class AsyncConfig implements AsyncConfigurer { @Override public Executor getAsyncExecutor() { return Executors.newFixedThreadPool(10); } } - 发布异步事件:
applicationEventPublisher.publishEvent(new CustomEvent(this, "Data"));
118. 自定义Scope需实现哪些关键方法?
答案:
get(String name, ObjectFactory<?> objectFactory):获取Bean实例。remove(String name):移除Bean。registerDestructionCallback(String name, Runnable callback):注册销毁回调。resolveContextualObject(String key):解析上下文对象。
119. 测试上下文的分层配置策略?
答案:
- 使用
@ActiveProfiles隔离环境配置:@ActiveProfiles("test") @SpringBootTest public class TestClass { ... } - 使用
@TestPropertySource覆盖属性:@TestPropertySource(properties = "app.name=test-app")
120. Spring 5+对响应式编程的支持?
答案:
- WebFlux模块:基于Reactor的响应式Web框架。
- ReactiveAdapterRegistry:支持响应式类型转换。
- 示例:
@Bean public RouterFunction<ServerResponse> route(UserHandler userHandler) { return RouterFunctions.route(GET("/users"), userHandler::getAllUsers); }
1106

被折叠的 条评论
为什么被折叠?



