目录
5.1.1 BeanFactory与ApplicationContext
一、软件架构演进与三层架构概述
1.1 从单体架构到分层架构
在软件开发初期,应用程序通常采用单体架构(Monolithic Architecture),所有功能模块紧密耦合在一起。随着业务复杂度增加,这种架构暴露出诸多问题:
代码维护困难
功能扩展性差
团队协作效率低
技术栈升级困难
分层架构(Layered Architecture)应运而生,通过将系统划分为多个职责分明的层次,解决了上述问题。其中,三层架构是最经典且广泛采用的分层模式。
1.2 经典三层架构详解
三层架构将应用程序划分为三个主要层次:
表示层(Presentation Layer)
负责用户界面和交互
处理用户输入和展示输出
典型实现:Web MVC框架、客户端应用
业务逻辑层(Business Logic Layer)
核心业务规则和流程实现
数据处理和业务验证
典型实现:服务组件、领域模型
数据访问层(Data Access Layer)
与数据存储系统交互
提供数据的CRUD操作
典型实现:DAO模式、ORM框架
1.3 三层架构的优势
解耦性:各层职责明确,降低耦合度
可维护性:修改某层不影响其他层
可扩展性:可独立扩展某层功能
可测试性:便于单元测试和集成测试
团队协作:不同团队可并行开发不同层次
二、分层解耦的核心思想
2.1 耦合与解耦的基本概念
耦合(Coupling)指软件模块间的依赖程度,高耦合系统存在以下问题:
牵一发而动全身
难以复用单个模块
测试困难
解耦(Decoupling)是通过设计手段降低模块间依赖程度的技术,目标是实现:
模块独立演化
接口契约编程
依赖关系清晰
2.2 分层解耦的实现手段
面向接口编程
// 紧耦合实现 public class OrderService { private OrderRepository repository = new MySQLOrderRepository(); } // 解耦实现 public class OrderService { private OrderRepository repository; public OrderService(OrderRepository repository) { this.repository = repository; } }
依赖注入
构造函数注入
Setter方法注入
接口注入
工厂模式
public class RepositoryFactory { public static OrderRepository createOrderRepository() { return new MySQLOrderRepository(); } }
服务定位器模式
public class ServiceLocator { private static Map<String, Object> services = new HashMap<>(); public static void register(String name, Object service) { services.put(name, service); } public static Object getService(String name) { return services.get(name); } }
2.3 分层解耦的实践原则
依赖倒置原则(DIP)
高层模块不应依赖低层模块,二者都应依赖抽象
抽象不应依赖细节,细节应依赖抽象
单一职责原则(SRP)
每个类/模块只负责一个功能领域
接口隔离原则(ISP)
客户端不应被迫依赖它不使用的接口
迪米特法则(LoD)
一个对象应当对其他对象有尽可能少的了解
三、控制反转(IOC)深度解析
3.1 IOC概念与演进历史
控制反转(Inversion of Control)是一种软件设计原则,最早由Michael Mattson在1996年提出,后由Martin Fowler推广。其核心思想是:
"传统程序流程由开发者控制,而IOC将流程控制权交给框架/容器"
3.1.1 传统控制流程
public class TraditionalApp {
public static void main(String[] args) {
// 开发者控制所有对象创建和调用顺序
Service service = new ServiceImpl();
service.execute();
}
}
3.1.2 IOC控制流程
public class IOCApp {
public static void main(String[] args) {
// 框架容器控制对象生命周期
ApplicationContext context = new ClassPathXmlApplicationContext("config.xml");
Service service = context.getBean(Service.class);
service.execute();
}
}
3.2 IOC的实现方式
3.2.1 模板方法模式
public abstract class TemplateMethod {
// 框架控制流程
public void execute() {
step1();
step2();
customStep();
step3();
}
protected abstract void customStep();
}
public class MyImplementation extends TemplateMethod {
@Override
protected void customStep() {
// 子类实现特定步骤
}
}
3.2.2 回调函数
public class EventDispatcher {
private Map<String, List<EventListener>> listeners = new HashMap<>();
public void register(String eventType, EventListener listener) {
listeners.computeIfAbsent(eventType, k -> new ArrayList<>()).add(listener);
}
public void dispatch(String eventType) {
listeners.getOrDefault(eventType, Collections.emptyList())
.forEach(EventListener::onEvent);
}
}
public interface EventListener {
void onEvent();
}
3.2.3 依赖注入
最常见的IOC实现方式,详见第四章。
3.3 IOC容器的核心功能
现代IOC容器(如Spring、Guice)提供以下核心能力:
组件管理
生命周期管理
作用域控制(单例、原型等)
依赖解析
自动装配
循环依赖处理
配置管理
多种配置源支持
环境抽象
AOP支持
代理创建
切面织入
扩展点
Bean后处理器
工厂钩子
3.4 IOC的优缺点分析
优点:
降低组件耦合度
提高代码可测试性
统一生命周期管理
便于集中配置
促进面向接口编程
缺点:
学习曲线较陡
调试复杂度增加
启动时间可能变长
过度使用会导致"配置地狱"
四、依赖注入(DI)全面剖析
4.1 DI基本概念与实现方式
依赖注入(Dependency Injection)是IOC的一种具体实现技术,由组件外部注入依赖项,而非组件自行创建。
4.1.1 构造函数注入
public class OrderService {
private final OrderRepository repository;
// 通过构造函数注入依赖
public OrderService(OrderRepository repository) {
this.repository = repository;
}
}
优点:
依赖不可变(final)
完全初始化的对象
易于测试
4.1.2 Setter方法注入
public class OrderService {
private OrderRepository repository;
// 通过setter方法注入依赖
public void setRepository(OrderRepository repository) {
this.repository = repository;
}
}
优点:
可选依赖
可重新配置
符合JavaBean标准
4.1.3 接口注入
public interface RepositoryAware {
void setRepository(OrderRepository repository);
}
public class OrderService implements RepositoryAware {
private OrderRepository repository;
@Override
public void setRepository(OrderRepository repository) {
this.repository = repository;
}
}
特点:
显式接口契约
较少使用
4.2 现代DI框架的高级特性
4.2.1 自动装配(Autowiring)
@Component
public class OrderService {
@Autowired
private OrderRepository repository;
}
类型:
按类型(byType)
按名称(byName)
构造函数自动装配
4.2.2 限定符(Qualifiers)
@Repository("jdbcRepo")
public class JdbcOrderRepository implements OrderRepository {}
@Repository("jpaRepo")
public class JpaOrderRepository implements OrderRepository {}
@Service
public class OrderService {
@Autowired
@Qualifier("jpaRepo")
private OrderRepository repository;
}
4.2.3 条件化装配
@Configuration
public class AppConfig {
@Bean
@ConditionalOnProperty(name = "db.type", havingValue = "mysql")
public OrderRepository mysqlRepo() {
return new MySQLOrderRepository();
}
}
4.2.4 延迟初始化
@Lazy
@Service
public class HeavyService {
// 延迟到第一次使用时初始化
}
4.3 DI的最佳实践
优先使用构造函数注入
特别是强制依赖
保持不可变性
合理使用接口
针对抽象编程
便于模拟测试
避免循环依赖
设计时注意依赖方向
必要时引入第三方类
控制注入范围
避免过度注入
合理划分组件边界
结合模块化设计
@Configuration public class RepositoryConfig { @Bean public OrderRepository orderRepository() { return new JpaOrderRepository(); } }
五、Spring框架中的IOC与DI实现
5.1 Spring IOC容器体系
5.1.1 BeanFactory与ApplicationContext
// 基础容器
BeanFactory factory = new XmlBeanFactory(new ClassPathResource("beans.xml"));
// 高级容器(推荐)
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
功能对比:
特性 | BeanFactory | ApplicationContext |
---|---|---|
Bean实例化/装配 | ✓ | ✓ |
自动Bean后处理器注册 | × | ✓ |
便捷的MessageSource访问 | × | ✓ |
应用事件发布 | × | ✓ |
5.1.2 容器初始化过程
配置元数据读取
XML配置
注解扫描
Java配置类
Bean定义解析
BeanDefinition注册
BeanFactory后处理
BeanDefinitionRegistryPostProcessor
BeanFactoryPostProcessor
Bean实例化
依赖查找
依赖注入
初始化回调
InitializingBean
@PostConstruct
5.2 Spring DI的注解驱动开发
5.2.1 核心注解
声明Bean
@Component
@Service
@Repository
@Controller
@Configuration
依赖注入
@Autowired
@Inject (JSR-330)
@Resource (JSR-250)
配置相关
@Bean
@PropertySource
@Value
5.2.2 典型配置示例
@Configuration
@ComponentScan("com.example")
@PropertySource("classpath:app.properties")
public class AppConfig {
@Bean
@Profile("dev")
public DataSource devDataSource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.build();
}
@Bean
@Profile("prod")
public DataSource prodDataSource(
@Value("${db.url}") String url,
@Value("${db.user}") String user) {
return new BasicDataSource(url, user);
}
}
5.3 Spring高级DI特性
5.3.1 生命周期管理
public class LifecycleBean implements
InitializingBean, DisposableBean {
@PostConstruct
public void customInit() {
// 注解方式初始化
}
@Override
public void afterPropertiesSet() {
// 接口方式初始化
}
@PreDestroy
public void customDestroy() {
// 注解方式销毁
}
@Override
public void destroy() {
// 接口方式销毁
}
}
5.3.2 作用域扩展
@Scope("thread")
public class ThreadScopedBean {
// 线程作用域的Bean
}
// 自定义作用域实现
public class ThreadScope implements Scope {
private final ThreadLocal<Map<String, Object>> threadLocal =
ThreadLocal.withInitial(HashMap::new);
@Override
public Object get(String name, ObjectFactory<?> objectFactory) {
Map<String, Object> scope = threadLocal.get();
return scope.computeIfAbsent(name, k -> objectFactory.getObject());
}
// 其他方法实现...
}
5.3.3 延迟依赖解析
@Service
public class OrderService {
@Autowired
private Provider<OrderRepository> repositoryProvider;
public void process() {
OrderRepository repository = repositoryProvider.get();
// 每次调用get()获取新实例(根据作用域)
}
}
六、实战:构建三层架构的Spring应用
6.1 项目结构与依赖配置
Maven依赖:
<dependencies>
<!-- Spring Core -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.8</version>
</dependency>
<!-- Database -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.8</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.200</version>
</dependency>
<!-- Web -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.8</version>
</dependency>
</dependencies>
项目结构:
src/
├── main/
│ ├── java/
│ │ └── com/
│ │ └── example/
│ │ ├── config/
│ │ ├── controller/
│ │ ├── service/
│ │ ├── repository/
│ │ ├── model/
│ │ └── Application.java
│ └── resources/
│ ├── application.properties
│ └── db/
└── test/
└── java/
└── com/example/
6.2 各层实现详解
6.2.1 数据访问层(Repository)
public interface UserRepository {
User findById(Long id);
List<User> findAll();
void save(User user);
}
@Repository
public class JdbcUserRepository implements UserRepository {
private final JdbcTemplate jdbcTemplate;
@Autowired
public JdbcUserRepository(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
@Override
public User findById(Long id) {
return jdbcTemplate.queryForObject(
"SELECT * FROM users WHERE id = ?",
new Object[]{id},
(rs, rowNum) -> new User(
rs.getLong("id"),
rs.getString("username")
));
}
// 其他方法实现...
}
6.2.2 业务逻辑层(Service)
public interface UserService {
User getUserById(Long id);
List<User> getAllUsers();
void registerUser(User user);
}
@Service
@Transactional
public class UserServiceImpl implements UserService {
private final UserRepository userRepository;
@Autowired
public UserServiceImpl(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Override
public User getUserById(Long id) {
return userRepository.findById(id);
}
// 其他方法实现...
@Transactional(readOnly = true)
@Override
public List<User> getAllUsers() {
return userRepository.findAll();
}
}
6.2.3 表示层(Controller)
@RestController
@RequestMapping("/api/users")
public class UserController {
private final UserService userService;
@Autowired
public UserController(UserService userService) {
this.userService = userService;
}
@GetMapping("/{id}")
public ResponseEntity<User> getUser(@PathVariable Long id) {
return ResponseEntity.ok(userService.getUserById(id));
}
@PostMapping
public ResponseEntity<Void> createUser(@RequestBody User user) {
userService.registerUser(user);
return ResponseEntity.created(URI.create("/users/" + user.getId())).build();
}
}
6.3 配置与集成
6.3.1 主配置类
@Configuration
@ComponentScan("com.example")
@EnableTransactionManagement
@PropertySource("classpath:application.properties")
public class AppConfig {
@Bean
public DataSource dataSource(
@Value("${db.url}") String url,
@Value("${db.username}") String username,
@Value("${db.password}") String password) {
return new DriverManagerDataSource(url, username, password);
}
@Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}
6.3.2 Web配置
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(new MappingJackson2HttpMessageConverter());
}
@Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
return resolver;
}
}
6.4 测试策略
6.4.1 单元测试
@ExtendWith(MockitoExtension.class)
class UserServiceTest {
@Mock
private UserRepository userRepository;
@InjectMocks
private UserServiceImpl userService;
@Test
void getUserById_shouldReturnUser() {
User expected = new User(1L, "test");
when(userRepository.findById(1L)).thenReturn(expected);
User actual = userService.getUserById(1L);
assertEquals(expected, actual);
verify(userRepository).findById(1L);
}
}
6.4.2 集成测试
@SpringJUnitConfig(classes = TestConfig.class)
@Transactional
class UserServiceIntegrationTest {
@Autowired
private UserService userService;
@Autowired
private JdbcTemplate jdbcTemplate;
@Test
void registerUser_shouldPersistUser() {
User user = new User(null, "integration");
userService.registerUser(user);
assertNotNull(user.getId());
Integer count = jdbcTemplate.queryForObject(
"SELECT COUNT(*) FROM users WHERE id = ?",
Integer.class, user.getId());
assertEquals(1, count.intValue());
}
}
七、IOC与DI的高级主题与最佳实践
7.1 解决复杂依赖场景
7.1.1 循环依赖处理
Spring的三级缓存解决方案:
一级缓存:存放完全初始化好的Bean
二级缓存:存放早期暴露的原始Bean(未填充属性)
三级缓存:存放Bean工厂,用于生成原始Bean
最佳实践:
尽量避免循环依赖
使用setter注入替代构造器注入(Spring可解决)
引入第三方类打破循环
7.1.2 条件化装配策略
@Configuration
public class DataSourceConfig {
@Bean
@ConditionalOnClass(name = "org.h2.Driver")
public DataSource h2DataSource() {
return new EmbeddedDatabaseBuilder()
.setType(H2)
.build();
}
@Bean
@ConditionalOnProperty("mysql.enabled")
public DataSource mysqlDataSource(
@Value("${mysql.url}") String url) {
return new MysqlDataSource(url);
}
}
7.2 性能优化技巧
懒加载策略
@Lazy @Service public class HeavyInitService { // 延迟初始化 }
合理使用作用域
无状态服务使用单例(默认)
有状态组件使用原型或自定义作用域
避免过度注入
检查注入点数量(建议不超过5-7个)
考虑拆分过大的类
启动时优化
@SpringBootApplication public class MyApp { public static void main(String[] args) { new SpringApplicationBuilder(MyApp.class) .lazyInitialization(true) .run(args); } }
7.3 设计模式与DI的结合
7.3.1 装饰器模式
public interface DataService {
String fetchData();
}
@Primary
@Service
public class CacheDataService implements DataService {
private final DataService delegate;
@Autowired
public CacheDataService(@Qualifier("mainDataService") DataService delegate) {
this.delegate = delegate;
}
@Override
public String fetchData() {
// 添加缓存逻辑
return delegate.fetchData();
}
}
7.3.2 策略模式
public interface PaymentStrategy {
void pay(BigDecimal amount);
}
@Service
@Qualifier("creditCard")
public class CreditCardPayment implements PaymentStrategy {
@Override
public void pay(BigDecimal amount) {
// 信用卡支付实现
}
}
@Service
public class PaymentService {
private final Map<String, PaymentStrategy> strategies;
@Autowired
public PaymentService(List<PaymentStrategy> strategyList) {
this.strategies = strategyList.stream()
.collect(Collectors.toMap(
s -> s.getClass().getAnnotation(Qualifier.class).value(),
Function.identity()
));
}
public void processPayment(String type, BigDecimal amount) {
strategies.get(type).pay(amount);
}
}
7.4 现代Java中的DI趋势
Jakarta CDI (JSR 365)
标准化的DI规范
与Spring注解兼容
在Jakarta EE/微服务中广泛使用
Micronaut
编译时DI处理
极低启动时间
适合Serverless场景
Quarkus
面向云原生
结合CDI和Spring DI
GraalVM原生支持
Dagger 2
纯编译时DI
高性能
Android开发首选
八、常见问题与解决方案
8.1 IOC/DI实施中的典型问题
问题1:Bean创建异常
症状:
Error creating bean with name 'userService':
Injection of autowired dependencies failed
解决方案:
检查依赖Bean是否已定义
确认包扫描路径包含所有组件
检查循环依赖
问题2:依赖注入冲突
症状:
No qualifying bean of type 'com.example.Repository' available:
expected single matching bean but found 2: jdbcRepo, jpaRepo
解决方案:
使用@Primary标记首选Bean
使用@Qualifier明确指定
重构接口设计,避免同一类型多实现
问题3:作用域不匹配
症状:
Scope 'request' is not active for the current thread
解决方案:
检查Bean的作用域是否与使用场景匹配
对于Web请求作用域,确保有活跃的请求上下文
考虑使用代理模式:
@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
8.2 调试技巧与工具
Spring Bean依赖图
@Autowired private ConfigurableListableBeanFactory beanFactory; public void printBeanDependencies() { for (String name : beanFactory.getBeanDefinitionNames()) { BeanDefinition definition = beanFactory.getBeanDefinition(name); if (definition instanceof AbstractBeanDefinition) { String[] dependsOn = ((AbstractBeanDefinition) definition).getDependsOn(); if (dependsOn != null) { System.out.println(name + " depends on: " + Arrays.toString(dependsOn)); } } } }
使用Spring Boot Actuator
management: endpoints: web: exposure: include: beans
访问
/actuator/beans
查看所有Bean信息IDE工具支持
IntelliJ IDEA的Diagram功能
Eclipse的Spring Tools插件
8.3 性能调优指南
启动时间优化
减少@ComponentScan范围
使用延迟初始化
避免启动时阻塞操作
内存占用优化
合理使用原型作用域
及时销毁不再需要的Bean
避免过度使用AOP
依赖查找优化
// 避免的写法(每次调用都查找) public void process() { MyService service = applicationContext.getBean(MyService.class); service.execute(); } // 推荐的写法(一次性注入) @Autowired private MyService service;
九、总结与展望
9.1 关键要点回顾
三层架构是构建可维护企业应用的基础
表示层:用户交互
业务层:核心逻辑
数据层:持久化操作
分层解耦通过以下方式实现:
面向接口编程
依赖注入
控制反转
IOC容器的核心价值:
管理组件生命周期
解耦依赖关系
提供统一配置
DI最佳实践:
优先使用构造函数注入
合理划分组件作用域
避免过度复杂的依赖关系
9.2 未来发展趋势
云原生DI
轻量级容器
编译时处理
原生镜像支持
反应式编程整合
响应式依赖注入
非阻塞组件管理
函数式风格
Java函数式Bean注册
Kotlin DSL配置
多运行时支持
跨环境配置
混合云部署
9.3 学习资源推荐
经典书籍
《Expert One-on-One J2EE Development without EJB》Rod Johnson
《Dependency Injection》Dhanji R. Prasanna
《Spring in Action》Craig Walls
在线资源
Spring官方文档
Martin Fowler的IOC文章
Java EE CDI规范
实践项目
从零实现简易IOC容器
重构传统应用为分层架构
性能对比测试不同DI框架
通过本指南的系统学习,您应该已经掌握了三层架构与分层解耦的核心思想,深入理解了IOC和DI的设计原理与实现方式,并具备了在实际项目中应用这些技术的能力。架构之路永无止境,希望这些知识能成为您构建高质量软件系统的坚实基础。