第14篇:深入详解Spring框架基础
Spring框架是Java企业级应用开发的事实标准,其核心思想是 控制反转(IoC) 和 面向切面编程(AOP)。本文将从Spring容器、Bean管理、依赖注入、AOP实现出发,结合配置方式演进与核心源码解析,系统剖析Spring框架的基础架构与核心机制。
1. Spring生态全景
模块 | 核心功能 | 典型应用场景 |
---|---|---|
Spring Core | IoC容器、Bean管理、资源加载 | 所有Spring应用的基础 |
Spring AOP | 切面编程、动态代理 | 日志、事务等横切关注点 |
Spring MVC | Web层框架,支持RESTful开发 | Web应用开发 |
Spring Data | 统一数据访问抽象(JPA、MongoDB、Redis) | 数据库操作 |
Spring Security | 认证与授权框架 | 系统安全管控 |
Spring Boot | 自动化配置、快速启动 | 微服务开发 |
2. IoC容器与Bean管理
2.1 容器核心接口
BeanFactory
:基础容器接口,提供Bean的注册与获取(延迟初始化)ApplicationContext
:扩展自BeanFactory
,增加事件发布、国际化等企业级功能(立即初始化)
// 示例:ClassPathXmlApplicationContext使用
ApplicationContext context =
new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = context.getBean(UserService.class);
2.2 Bean作用域
作用域类型 | 说明 |
---|---|
singleton | 默认作用域,容器中唯一实例 |
prototype | 每次请求创建新实例 |
request | Web应用中每个HTTP请求一个实例 |
session | Web应用中每个用户会话一个实例 |
application | Web应用中ServletContext生命周期内唯一实例 |
配置示例:
<bean id="user" class="com.example.User" scope="prototype"/>
2.3 Bean生命周期
- 实例化(Instantiation)
- 属性填充(Population)
- BeanNameAware接口回调
- BeanFactoryAware接口回调
- 前置初始化(BeanPostProcessor.postProcessBeforeInitialization)
- 初始化方法(@PostConstruct、InitializingBean)
- 后置初始化(BeanPostProcessor.postProcessAfterInitialization)
- 销毁(@PreDestroy、DisposableBean)
3. 依赖注入(DI)实现方式
3.1 注入类型对比
方式 | 优点 | 缺点 |
---|---|---|
构造器注入 | 保证依赖不可变,避免NPE | 参数较多时代码冗长 |
Setter注入 | 灵活性高,适合可选依赖 | 可能产生部分初始化的对象 |
字段注入 | 代码简洁 | 破坏封装性,测试困难 |
注解示例:
@Component
public class OrderService {
// 构造器注入(推荐)
private final UserService userService;
public OrderService(UserService userService) {
this.userService = userService;
}
// Setter注入
private PaymentService paymentService;
@Autowired
public void setPaymentService(PaymentService paymentService) {
this.paymentService = paymentService;
}
}
3.2 自动装配模式
模式 | 说明 |
---|---|
byType | 根据类型自动装配(需确保类型唯一) |
byName | 根据Bean名称匹配属性名 |
constructor | 类似byType,但应用于构造器参数 |
@Qualifier | 指定具体Bean名称解决歧义 |
4. AOP实现原理
4.1 核心概念
- 切面(Aspect):横切关注点的模块化(如日志、事务)
- 连接点(Joinpoint):程序执行点(方法执行、异常处理)
- 通知(Advice):切面在连接点的动作(前置、后置、环绕等)
- 切点(Pointcut):匹配连接点的表达式
4.2 JDK动态代理 vs CGLIB代理
特性 | JDK动态代理 | CGLIB代理 |
---|---|---|
代理对象要求 | 必须实现接口 | 可代理普通类 |
性能 | 生成快,调用慢 | 生成慢,调用快 |
方法拦截 | 通过InvocationHandler 接口 | 通过方法拦截器MethodInterceptor |
配置强制使用CGLIB:
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class AppConfig {}
4.3 AOP实战:日志切面
@Aspect
@Component
public class LogAspect {
// 定义切点:所有Service层方法
@Pointcut("execution(* com.example.service.*.*(..))")
public void serviceLayer() {}
// 前置通知
@Before("serviceLayer()")
public void logBefore(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
System.out.println("Method " + methodName + " starts");
}
// 环绕通知
@Around("serviceLayer()")
public Object logAround(ProceedingJoinPoint pjp) throws Throwable {
long start = System.currentTimeMillis();
Object result = pjp.proceed();
long duration = System.currentTimeMillis() - start;
System.out.println("Method executed in " + duration + "ms");
return result;
}
}
5. 配置方式演进
5.1 XML配置(传统方式)
<!-- Bean定义 -->
<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource">
<property name="jdbcUrl" value="${db.url}"/>
<property name="username" value="${db.user}"/>
</bean>
<!-- AOP配置 -->
<aop:config>
<aop:aspect ref="logAspect">
<aop:pointcut id="serviceMethods"
expression="execution(* com.example.service.*.*(..))"/>
<aop:before method="logBefore" pointcut-ref="serviceMethods"/>
</aop:aspect>
</aop:config>
5.2 Java Config(现代方式)
@Configuration
@PropertySource("classpath:app.properties")
@ComponentScan("com.example")
@EnableAspectJAutoProxy
public class AppConfig {
@Bean
public DataSource dataSource(
@Value("${db.url}") String url,
@Value("${db.user}") String user) {
HikariDataSource ds = new HikariDataSource();
ds.setJdbcUrl(url);
ds.setUsername(user);
return ds;
}
}
5.3 注解驱动(主流方式)
@Service
public class UserService {
@Autowired
private UserRepository userRepo;
@Transactional
public User createUser(User user) {
return userRepo.save(user);
}
}
6. Spring核心源码解析
6.1 Bean创建流程
- BeanDefinition加载:解析配置生成Bean定义
- 实例化:通过反射或工厂方法创建对象
- 属性填充:注入依赖的Bean
- 初始化:调用初始化方法和BeanPostProcessor
- 注册销毁方法:记录@PreDestroy方法
6. 循环依赖解决
- 三级缓存机制:
- singletonFactories(三级缓存,存放ObjectFactory)
- earlySingletonObjects(二级缓存,存放早期对象)
- singletonObjects(一级缓存,存放完整Bean)
处理流程:
- A创建时将自己提前暴露到三级缓存
- A填充属性时发现依赖B,触发B的创建
- B填充属性时从三级缓存获取A的ObjectFactory
- B完成初始化后,A继续完成属性填充和初始化
7. 常见问题与解决方案
7.1 Bean注入失败排查
- 检查@ComponentScan包路径是否正确
- 确认Bean是否被正确标记(@Service/@Component)
- 使用
context.getBeanDefinitionNames()
查看所有注册Bean - 检查是否存在多个同类型Bean导致歧义(使用@Qualifier解决)
7.2 事务失效场景
- 原因:
- 非public方法使用@Transactional
- 同一类内方法调用(未经过代理)
- 异常类型未被捕获(默认只回滚RuntimeException)
- 解决:
- 通过AopContext.currentProxy()获取代理对象
- 配置rollbackFor属性
8. 最佳实践与进阶建议
-
配置规范:
- 生产环境使用Java Config或注解驱动
- 敏感信息(如密码)使用加密或外部化配置
-
性能优化:
- 合理设置Bean作用域(避免无意义的prototype)
- 延迟初始化非关键Bean(@Lazy)
-
学习路径:
- 掌握Spring官方文档核心章节
- 调试Spring源码(从BeanFactory入手)
- 实践Spring Boot自动配置原理
附:Spring核心注解速查表
注解 | 作用 | 等效XML配置 |
---|---|---|
@Component | 通用组件声明 | <bean class="..."/> |
@Autowired | 自动装配依赖 | <property name ref="..."/> |
@Configuration | 标记配置类 | <beans>...</beans> |
@Bean | 声明Bean定义 | <bean id="..."> |
@Profile | 环境特定配置激活 | <beans profile="..."> |
@Enable* | 模块功能开关(如@EnableCaching) | <cache:annotation-driven/> |
通过深入理解Spring框架的核心机制,开发者能够构建松耦合、易维护的企业级应用,并为掌握Spring Boot、Spring Cloud等进阶技术奠定坚实基础。