Spring框架原理深度解析
概述
Spring框架是Java企业级开发的核心框架,深入理解其原理是高级开发工程师的必备技能。本文涵盖IoC容器、AOP机制、SpringBoot自动配置等核心面试内容。
核心面试问题
1. IoC容器核心原理
面试问题:Spring IoC容器的实现原理,Bean的生命周期是怎样的?
IoC容器架构
// 自定义简化版IoC容器实现
public class SimpleIoCContainer {
private final Map<String, Object> beanDefinitionMap = new ConcurrentHashMap<>();
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>();
// 注册Bean定义
public void registerBeanDefinition(String beanName, Class<?> beanClass) {
beanDefinitionMap.put(beanName, beanClass);
}
// 获取Bean实例
@SuppressWarnings("unchecked")
public <T> T getBean(String beanName, Class<T> requiredType) {
// 先从单例池中获取
Object bean = singletonObjects.get(beanName);
if (bean != null) {
return (T) bean;
}
// 创建新的Bean实例
Class<?> beanClass = (Class<?>) beanDefinitionMap.get(beanName);
if (beanClass == null) {
throw new RuntimeException("No bean definition found for: " + beanName);
}
try {
// 实例化
Object instance = beanClass.getDeclaredConstructor().newInstance();
// 依赖注入
performDependencyInjection(instance);
// 初始化回调
if (instance instanceof InitializingBean) {
((InitializingBean) instance).afterPropertiesSet();
}
// 放入单例池
singletonObjects.put(beanName, instance);
return (T) instance;
} catch (Exception e) {
throw new RuntimeException("Failed to create bean: " + beanName, e);
}
}
private void performDependencyInjection(Object instance) throws IllegalAccessException {
Field[] fields = instance.getClass().getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(Autowired.class)) {
field.setAccessible(true);
String dependencyName = field.getType().getSimpleName().toLowerCase();
Object dependency = getBean(dependencyName, field.getType());
field.set(instance, dependency);
}
}
}
// 简化的注解
@interface Autowired {}
interface InitializingBean {
void afterPropertiesSet() throws Exception;
}
}
Bean生命周期详解
@Component
public class LifecycleBean implements BeanNameAware, BeanFactoryAware,
ApplicationContextAware, InitializingBean, DisposableBean {
private String beanName;
private BeanFactory beanFactory;
private ApplicationContext applicationContext;
// 1. 构造器
public LifecycleBean() {
System.out.println("1. 构造器调用");
}
// 2. 属性注入
@Autowired
private SomeService someService;
// 3. Aware接口回调
@Override
public void setBeanName(String name) {
this.beanName = name;
System.out.println("3. BeanNameAware.setBeanName: " + name);
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
System.out.println("4. BeanFactoryAware.setBeanFactory");
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
System.out.println("5. ApplicationContextAware.setApplicationContext");
}
// 6. BeanPostProcessor前置处理
// 7. @PostConstruct注解方法
@PostConstruct
public void postConstruct() {
System.out.println("7. @PostConstruct注解方法");
}
// 8. InitializingBean.afterPropertiesSet
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("8. InitializingBean.afterPropertiesSet");
}
// 9. init-method指定的方法
public void initMethod() {
System.out.println("9. init-method指定的方法");
}
// 10. BeanPostProcessor后置处理
// Bean销毁阶段
@PreDestroy
public void preDestroy() {
System.out.println("销毁前: @PreDestroy注解方法");
}
@Override
public void destroy() throws Exception {
System.out.println("销毁中: DisposableBean.destroy");
}
public void destroyMethod() {
System.out.println("销毁中: destroy-method指定的方法");
}
}
// 自定义BeanPostProcessor
@Component
public class CustomBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof LifecycleBean) {
System.out.println("6. BeanPostProcessor前置处理: " + beanName);
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof LifecycleBean) {
System.out.println("10. BeanPostProcessor后置处理: " + beanName);
}
return bean;
}
}
2. AOP切面编程原理
面试问题:Spring AOP的实现原理,JDK动态代理与CGLIB的区别?
AOP核心概念实现
// 自定义切面注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LogExecution {
String value() default "";
}
// 切面定义
@Aspect
@Component
public class LoggingAspect {
// 切点表达式
@Pointcut("@annotation(LogExecution)")
public void logExecutionPointcut() {}
// 前置通知
@Before("logExecutionPointcut() && @annotation(logExecution)")
public void beforeExecution(JoinPoint joinPoint, LogExecution logExecution) {
String methodName = joinPoint.getSignature().getName();
String className = joinPoint.getTarget().getClass().getSimpleName();
System.out.println("开始执行: " + className + "." + methodName +
" - " + logExecution.value());
}
// 环绕通知
@Around("logExecutionPointcut()")
public Object aroundExecution(ProceedingJoinPoint joinPoint) throws Throwable {
long startTime = System.currentTimeMillis();
try {
Object result = joinPoint.proceed();
long endTime = System.currentTimeMillis();
System.out.println("执行成功,耗时: " + (endTime - startTime) + "ms");
return result;
} catch (Exception e) {
System.out.println("执行异常: " + e.getMessage());
throw e;
}
}
// 后置通知
@AfterReturning(pointcut = "logExecutionPointcut()", returning = "result")
public void afterReturning(JoinPoint joinPoint, Object result) {
System.out.println("方法返回: " + result);
}
// 异常通知
@AfterThrowing(pointcut = "logExecutionPointcut()", throwing = "exception")
public void afterThrowing(JoinPoint joinPoint, Exception exception) {
System.out.println("方法异常: " + exception.getMessage());
}
}
// 业务服务类
@Service
public class UserService {
@LogExecution("获取用户信息")
public User getUserById(Long id) {
if (id == null) {
throw new IllegalArgumentException("用户ID不能为空");
}
return new User(id, "用户" + id);
}
@LogExecution("保存用户")
public User saveUser(User user) {
// 模拟保存操作
user.setId(System.currentTimeMillis());
return user;
}
}
动态代理原理实现
// JDK动态代理实现
public class JdkProxyFactory {
@SuppressWarnings("unchecked")
public static <T> T createProxy(T target, InvocationHandler handler) {
return (T) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
handler
);
}
}
// 自定义InvocationHandler
public class LoggingInvocationHandler implements InvocationHandler {
private final Object target;
public LoggingInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("JDK代理 - 方法调用前: " + method.getName());
try {
Object result = method.invoke(target, args);
System.out.println("JDK代理 - 方法调用后: " + method.getName());
return result;
} catch (Exception e) {
System.out.println("JDK代理 - 方法异常: " + e.getMessage());
throw e;
}
}
}
// CGLIB代理实现
public class CglibProxyFactory {
@SuppressWarnings("unchecked")
public static <T> T createProxy(Class<T> targetClass) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(targetClass);
enhancer.setCallback(new LoggingMethodInterceptor());
return (T) enhancer.create();
}
}
// CGLIB方法拦截器
public class LoggingMethodInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("CGLIB代理 - 方法调用前: " + method.getName());
try {
Object result = proxy.invokeSuper(obj, args);
System.out.println("CGLIB代理 - 方法调用后: " + method.getName());
return result;
} catch (Exception e) {
System.out.println("CGLIB代理 - 方法异常: " + e.getMessage());
throw e;
}
}
}
// 代理对比测试
public class ProxyComparisonTest {
public static void main(String[] args) {
// JDK动态代理(需要接口)
UserService userService = new UserServiceImpl();
UserService jdkProxy = JdkProxyFactory.createProxy(userService,
new LoggingInvocationHandler(userService));
jdkProxy.getUserById(1L);
// CGLIB代理(不需要接口)
UserServiceImpl cglibProxy = CglibProxyFactory.createProxy(UserServiceImpl.class);
cglibProxy.getUserById(1L);
}
}
3. Spring Boot自动配置原理
面试问题:Spring Boot的自动配置是如何实现的?@SpringBootApplication注解的作用?
自动配置核心机制
// @SpringBootApplication注解分析
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration // 等同于@Configuration
@EnableAutoConfiguration // 启用自动配置
@ComponentScan(excludeFilters = { // 组件扫描
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
// ...
}
// 自定义自动配置类
@Configuration
@ConditionalOnClass(DataSource.class) // 当类路径存在DataSource时
@ConditionalOnMissingBean(DataSource.class) // 当容器中没有DataSource时
@EnableConfigurationProperties(DataSourceProperties.class) // 启用配置属性
public class CustomDataSourceAutoConfiguration {
@Autowired
private DataSourceProperties properties;
@Bean
@ConditionalOnProperty(name = "custom.datasource.enabled", havingValue = "true")
public DataSource dataSource() {
HikariDataSource dataSource = new HikariDataSource();
dataSource.setJdbcUrl(properties.getUrl());
dataSource.setUsername(properties.getUsername());
dataSource.setPassword(properties.getPassword());
dataSource.setDriverClassName(properties.getDriverClassName());
return dataSource;
}
}
// 配置属性类
@ConfigurationProperties(prefix = "custom.datasource")
@Data
public class DataSourceProperties {
private String url;
private String username;
private String password;
private String driverClassName = "com.mysql.cj.jdbc.Driver";
private boolean enabled = true;
}
// 自动配置注册
// 在META-INF/spring.factories文件中:
// org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
// com.example.CustomDataSourceAutoConfiguration
条件注解实现
// 自定义条件注解
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnRedisCondition.class)
public @interface ConditionalOnRedis {
String[] value() default {};
}
// 条件实现类
public class OnRedisCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
try {
// 检查Redis相关的类是否存在
context.getClassLoader().loadClass("redis.clients.jedis.Jedis");
// 检查配置属性
Environment env = context.getEnvironment();
String host = env.getProperty("redis.host");
String port = env.getProperty("redis.port");
return host != null && port != null;
} catch (ClassNotFoundException e) {
return false;
}
}
}
// 使用自定义条件
@Configuration
@ConditionalOnRedis
public class RedisAutoConfiguration {
@Bean
public RedisTemplate<String, Object> redisTemplate() {
RedisTemplate<String, Object> template = new RedisTemplate<>();
// 配置Redis模板
return template;
}
}
4. Spring事务管理原理
面试问题:Spring事务的传播机制,以及@Transactional注解的实现原理?
事务传播机制
@Service
public class TransactionService {
@Autowired
private UserRepository userRepository;
@Autowired
private OrderRepository orderRepository;
// REQUIRED:默认传播行为
@Transactional(propagation = Propagation.REQUIRED)
public void requiredMethod() {
userRepository.save(new User("user1"));
// 如果当前存在事务,则加入该事务;如果不存在,则创建新事务
}
// REQUIRES_NEW:总是创建新事务
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void requiresNewMethod() {
orderRepository.save(new Order("order1"));
// 总是创建新事务,如果当前存在事务,则挂起当前事务
}
// NESTED:嵌套事务
@Transactional(propagation = Propagation.NESTED)
public void nestedMethod() {
userRepository.save(new User("user2"));
// 如果当前存在事务,则在嵌套事务内执行
}
// 事务传播示例
@Transactional
public void businessMethod() {
try {
requiredMethod(); // 加入当前事务
requiresNewMethod(); // 创建新事务
nestedMethod(); // 嵌套事务
} catch (Exception e) {
// 异常处理
throw e;
}
}
// 事务隔离级别
@Transactional(
isolation = Isolation.READ_COMMITTED, // 隔离级别
timeout = 30, // 超时时间
readOnly = true, // 只读事务
rollbackFor = Exception.class, // 回滚异常
noRollbackFor = IllegalArgumentException.class // 不回滚异常
)
public User getUser(Long id) {
return userRepository.findById(id);
}
}
事务管理器实现
// 自定义事务管理器
@Configuration
@EnableTransactionManagement
public class TransactionConfig {
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
// 编程式事务模板
@Bean
public TransactionTemplate transactionTemplate(PlatformTransactionManager transactionManager) {
return new TransactionTemplate(transactionManager);
}
}
// 编程式事务使用
@Service
public class ProgrammaticTransactionService {
@Autowired
private TransactionTemplate transactionTemplate;
@Autowired
private UserRepository userRepository;
public User createUser(String name) {
return transactionTemplate.execute(status -> {
try {
User user = new User(name);
userRepository.save(user);
// 模拟业务逻辑
if (name.equals("error")) {
throw new RuntimeException("模拟异常");
}
return user;
} catch (Exception e) {
status.setRollbackOnly(); // 标记事务回滚
throw e;
}
});
}
// 事务回调
public void executeWithTransaction() {
transactionTemplate.executeWithoutResult(status -> {
userRepository.save(new User("test"));
// 无返回值的事务操作
});
}
}
5. Spring MVC工作原理
面试问题:SpringMVC的请求处理流程,DispatcherServlet的作用?
MVC核心组件
// 自定义拦截器
@Component
public class LoggingInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
System.out.println("请求前处理: " + request.getRequestURI());
return true; // 返回false会终止请求
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response,
Object handler, ModelAndView modelAndView) {
System.out.println("请求后处理: " + request.getRequestURI());
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) {
System.out.println("请求完成处理: " + request.getRequestURI());
}
}
// 全局异常处理
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(IllegalArgumentException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ResponseBody
public ErrorResponse handleIllegalArgument(IllegalArgumentException e) {
return new ErrorResponse("参数错误", e.getMessage());
}
@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ResponseBody
public ErrorResponse handleGenericException(Exception e) {
return new ErrorResponse("系统错误", e.getMessage());
}
// 数据绑定异常
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ResponseBody
public ErrorResponse handleValidationException(MethodArgumentNotValidException e) {
StringBuilder sb = new StringBuilder();
e.getBindingResult().getFieldErrors().forEach(error ->
sb.append(error.getField()).append(": ").append(error.getDefaultMessage()).append("; ")
);
return new ErrorResponse("验证失败", sb.toString());
}
}
// 自定义参数解析器
public class CustomArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasParameterAnnotation(CurrentUser.class);
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) {
// 从请求中解析当前用户信息
String userId = webRequest.getHeader("User-Id");
if (userId != null) {
return new User(Long.parseLong(userId), "CurrentUser");
}
return null;
}
}
// 配置类
@Configuration
@EnableWebMvc
public class WebMvcConfig implements WebMvcConfigurer {
@Autowired
private LoggingInterceptor loggingInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loggingInterceptor)
.addPathPatterns("/**")
.excludePathPatterns("/static/**");
}
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(new CustomArgumentResolver());
}
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
// 配置消息转换器
converters.add(new MappingJackson2HttpMessageConverter());
}
}
高频面试题目
1. 深度理解题目
Q: Spring如何解决循环依赖问题?
A: Spring通过三级缓存解决循环依赖:
- 一级缓存(singletonObjects):完整的Bean实例
- 二级缓存(earlySingletonObjects):早期的Bean引用
- 三级缓存(singletonFactories):Bean工厂
解决过程:
- 实例化Bean A,放入三级缓存
- 注入Bean B时,发现B依赖A
- 从三级缓存获取A的早期引用
- 完成B的创建,再完成A的初始化
Q: @Autowired和@Resource的区别?
A: 主要区别:
- @Autowired:Spring注解,按类型注入,可配合@Qualifier按名称
- @Resource:Java标准注解,按名称注入,找不到再按类型
- 优先级:@Resource优先按名称,@Autowired优先按类型
2. 实战应用题目
Q: 如何自定义Spring Boot Starter?
答题要点:
- 创建自动配置类
- 定义配置属性类
- 编写spring.factories文件
- 使用条件注解控制配置
- 提供默认配置和文档
Q: Spring事务失效的场景有哪些?
常见失效场景:
- 方法不是public的
- 同类内部方法调用
- 异常被捕获但不重新抛出
- 数据库不支持事务
- 没有被Spring管理的对象
总结
Spring框架面试重点:
- IoC原理:容器实现、Bean生命周期、依赖注入
- AOP机制:代理实现、切面编程、通知类型
- 自动配置:条件注解、配置属性、启动原理
- 事务管理:传播机制、隔离级别、实现原理
- MVC架构:请求处理流程、组件作用、扩展点
建议结合实际项目经验,能够描述Spring在项目中的具体应用和遇到的问题。