什么是Java bean的依赖注入
文章目录
- 什么是依赖注入
- 传统方式 vs 依赖注入
- 传统方式(紧耦合)
- 依赖注入方式(松耦合)
- 依赖注入的三种主要方式
- 1. 构造函数注入(Constructor Injection)
- 2. Setter注入(Setter Injection)
- 3. 字段注入(Field Injection)
- Spring框架中的依赖注入示例
- 使用@Autowired注解
- 使用配置类
- 依赖注入的优势
- 1. **松耦合**
- 2. **可测试性**
- 3. **配置集中化**
- 4. **重用性**
- 实际应用场景
- 多数据源切换
- 条件注入
- 最佳实践
Java Bean的依赖注入(Dependency Injection,DI)是一种设计模式,它是控制反转(IoC,Inversion of Control)原则的具体实现。
什么是依赖注入
依赖注入是指不在对象内部创建依赖对象,而是通过外部容器将依赖对象注入到需要它的对象中的技术。
传统方式 vs 依赖注入
传统方式(紧耦合)
public class UserService {private UserDao userDao;public UserService() {// 在构造函数中直接创建依赖对象this.userDao = new UserDaoImpl();}
}
依赖注入方式(松耦合)
public class UserService {private UserDao userDao;// 通过构造函数注入public UserService(UserDao userDao) {this.userDao = userDao;}// 或者通过setter方法注入public void setUserDao(UserDao userDao) {this.userDao = userDao;}
}
依赖注入的三种主要方式
1. 构造函数注入(Constructor Injection)
@Component
public class OrderService {private final PaymentService paymentService;private final InventoryService inventoryService;// Spring会自动注入这些依赖public OrderService(PaymentService paymentService, InventoryService inventoryService) {this.paymentService = paymentService;this.inventoryService = inventoryService;}
}
2. Setter注入(Setter Injection)
@Component
public class EmailService {private NotificationService notificationService;@Autowiredpublic void setNotificationService(NotificationService notificationService) {this.notificationService = notificationService;}
}
3. 字段注入(Field Injection)
@Component
public class ProductService {@Autowiredprivate ProductRepository productRepository;@Autowiredprivate CategoryService categoryService;
}
Spring框架中的依赖注入示例
使用@Autowired注解
@Service
public class BookService {@Autowiredprivate BookRepository bookRepository;@Autowiredprivate AuthorService authorService;public List<Book> findBooksByAuthor(String authorName) {Author author = authorService.findByName(authorName);return bookRepository.findByAuthor(author);}
}@Repository
public class BookRepository {@Autowiredprivate JdbcTemplate jdbcTemplate;public List<Book> findByAuthor(Author author) {// 数据库查询逻辑return jdbcTemplate.query("SELECT * FROM books WHERE author_id = ?",new Object[]{author.getId()},new BookRowMapper());}
}
使用配置类
@Configuration
public class AppConfig {@Beanpublic UserService userService(UserRepository userRepository) {return new UserService(userRepository);}@Beanpublic UserRepository userRepository() {return new JpaUserRepository();}
}
依赖注入的优势
1. 松耦合
- 对象不需要知道依赖对象的具体实现
- 便于替换不同的实现
2. 可测试性
// 单元测试中可以轻松mock依赖
@Test
public void testUserService() {UserRepository mockRepository = Mockito.mock(UserRepository.class);UserService userService = new UserService(mockRepository);// 测试逻辑
}
3. 配置集中化
- 所有依赖关系在配置文件或注解中统一管理
- 便于维护和修改
4. 重用性
- 同一个类可以在不同场景下使用不同的依赖实现
实际应用场景
多数据源切换
@Service
public class DataService {private final DataRepository repository;public DataService(@Qualifier("primaryDataRepository") DataRepository repository) {this.repository = repository;}
}@Configuration
public class DataConfig {@Bean@Primarypublic DataRepository primaryDataRepository() {return new MySQLDataRepository();}@Beanpublic DataRepository secondaryDataRepository() {return new PostgreSQLDataRepository();}
}
条件注入
@Service
@ConditionalOnProperty(name = "payment.provider", havingValue = "stripe")
public class StripePaymentService implements PaymentService {// Stripe支付实现
}@Service
@ConditionalOnProperty(name = "payment.provider", havingValue = "paypal")
public class PayPalPaymentService implements PaymentService {// PayPal支付实现
}
最佳实践
- 优先使用构造函数注入,因为它保证了依赖的不可变性
- 避免循环依赖
- 使用接口而不是具体类作为依赖类型
- 合理使用@Qualifier注解来解决多个同类型Bean的冲突
依赖注入是现代Java开发中的核心概念,特别是在Spring框架中,它大大简化了对象管理和提高了代码的可维护性。