Spring框架作为Java企业级开发的基石,其核心设计思想值得每一位开发者深入理解。让我们从一个实际案例开始:假设你正在开发一个电商系统,订单服务(OrderService)需要调用库存服务(InventoryService)。传统写法可能是:
java复制public class OrderService {
private InventoryService inventoryService = new InventoryServiceImpl();
//...
}
这种硬编码方式存在明显问题:当需要切换库存服务实现时,必须修改OrderService源码。Spring的IoC容器正是为解决这类耦合问题而生。
IoC不是魔法,其本质是将对象创建和依赖管理的控制权从程序员手中转移到容器。这种转变带来了三大优势:
Spring通过两种主要方式实现IoC:
提示:Spring团队推荐使用构造器注入强制依赖,这能保证对象在创建时就处于完整状态,避免了NPE风险。
DIP原则要求我们:
在Spring中,这意味着:
java复制@Service
public class OrderService {
private final InventoryService inventoryService;
@Autowired // Spring 4.3+ 可省略
public OrderService(InventoryService inventoryService) {
this.inventoryService = inventoryService;
}
}
即使InventoryService有多个实现,通过@Qualifier或Primary注解,Spring也能智能解决依赖问题。
Spring管理Bean的生命周期远比表面看起来复杂,完整流程包含10个关键节点:
java复制// 典型初始化方法示例
@Slf4j
@Component
public class InventoryService implements InitializingBean {
@PostConstruct
public void validateConfig() {
log.info("@PostConstruct验证配置");
}
@Override
public void afterPropertiesSet() {
log.info("InitializingBean初始化");
}
public void customInit() {
log.info("XML配置的init-method");
}
}
Spring通过三级缓存巧妙解决setter注入的循环依赖:
解决流程示例(A依赖B,B依赖A):
重要限制:构造器注入的循环依赖无法解决,因为必须完成构造才能将对象引用暴露给缓存。
当前Spring生态已全面转向注解配置,核心注解包括:
| 注解 | 作用域 | 说明 |
|---|---|---|
| @Component | 类 | 通用组件标记 |
| @Repository | 类 | 持久层专用 |
| @Service | 类 | 业务层专用 |
| @Controller | 类 | Web层专用 |
| @Configuration | 类 | 配置类标记 |
| @Bean | 方法 | 声明Bean定义 |
配置类典型写法:
java复制@Configuration
@ComponentScan("com.example")
@EnableTransactionManagement
@EnableAspectJAutoProxy
public class AppConfig {
@Bean
public DataSource dataSource() {
HikariDataSource ds = new HikariDataSource();
ds.setJdbcUrl("jdbc:mysql://localhost:3306/app");
//...
return ds;
}
@Bean
public PlatformTransactionManager txManager() {
return new DataSourceTransactionManager(dataSource());
}
}
面向切面编程能优雅解决横切关注点问题。实际项目中常见的切面应用:
java复制@Aspect
@Component
@Slf4j
public class PerformanceAspect {
@Around("execution(* com.example..service.*.*(..))")
public Object logPerformance(ProceedingJoinPoint pjp) throws Throwable {
long start = System.currentTimeMillis();
try {
return pjp.proceed();
} finally {
long duration = System.currentTimeMillis() - start;
log.info("{} executed in {} ms",
pjp.getSignature(), duration);
if(duration > 1000) {
log.warn("Performance warning!");
}
}
}
}
Spring Profile和Condition接口提供了灵活的Bean注册机制:
java复制@Configuration
public class DataSourceConfig {
@Bean
@Profile("dev")
public DataSource h2DataSource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.build();
}
@Bean
@Profile("prod")
@Conditional(CloudEnvironmentCondition.class)
public DataSource cloudDataSource() {
// 云环境数据源配置
}
}
public class CloudEnvironmentCondition implements Condition {
@Override
public boolean matches(ConditionContext context,
AnnotatedTypeMetadata metadata) {
return "true".equals(
context.getEnvironment()
.getProperty("app.cloud.enabled"));
}
}
Spring 5引入的WebFlux框架支持响应式编程:
java复制@RestController
@RequestMapping("/products")
public class ProductController {
private final ProductService productService;
public ProductController(ProductService productService) {
this.productService = productService;
}
@GetMapping
public Flux<Product> listProducts() {
return productService.getAllProducts();
}
@GetMapping("/{id}")
public Mono<Product> getProduct(@PathVariable String id) {
return productService.getProductById(id);
}
}
| 作用域 | 适用场景 | 线程安全 | 性能影响 |
|---|---|---|---|
| singleton | 无状态服务 | 需自行保证 | 最优 |
| prototype | 有状态Bean | 隔离 | 较差 |
| request | Web请求级 | 自动隔离 | 中等 |
| session | 用户会话级 | 自动隔离 | 中等 |
经验:90%的场景应使用singleton,只有确实需要每次获取新实例时才使用prototype。
问题1:事务不生效
问题2:自动注入失败
问题3:循环依赖
Spring框架的深度远不止于此,但掌握这些核心概念和实践已经能够应对大多数企业级开发场景。在实际项目中,建议结合Spring Boot使用,它能极大简化配置工作,让开发者更专注于业务逻辑实现。