?? 目錄
?? Spring框架簡介
??? IoC容器詳解
?? 依賴注入(DI)深入理解
?? Bean配置與管理
?? Bean的作用域
?? Bean生命周期
?? 面向切面編程(AOP)
?? Spring注解詳解
?? 資源管理
?? 事件機制
?? SpEL表達式語言
?? 實戰案例
?? 總結
?? Spring框架簡介
什么是Spring?
Spring就像是Java開發的"超級管家",它幫我們管理對象的創建、依賴關系,讓我們專注于業務邏輯。
生活中的類比:
- 沒有Spring = 自己管理家務(買菜、做飯、打掃、洗衣服...)
- 有了Spring = 請了專業管家(告訴需求,管家安排一切)
Spring的核心優勢
// 傳統Java開發的痛點
public class TraditionalCode {public void businessLogic() {// 手動創建對象DatabaseConnection db = new DatabaseConnection();db.connect("localhost", "user", "password");UserDao userDao = new UserDao();userDao.setConnection(db); // 手動設置依賴EmailService emailService = new EmailService();emailService.setSmtpServer("smtp.gmail.com");UserService userService = new UserService();userService.setUserDao(userDao); // 手動裝配userService.setEmailService(emailService);// 業務邏輯userService.registerUser("張三");// 手動清理資源db.close();}
}// Spring幫我們解決的問題
@Service
public class SpringCode {@Autowiredprivate UserService userService; // Spring自動注入public void businessLogic() {// 直接使用,專注業務邏輯userService.registerUser("張三");// Spring自動管理資源}
}
Spring的兩大核心特性
- IoC(控制反轉) - 對象的創建和管理交給Spring
- AOP(面向切面編程) - 橫切關注點的統一處理
??? IoC容器詳解
什么是IoC(控制反轉)?
控制反轉就是把對象的控制權從程序員手中轉移給Spring容器。
形象比喻:
- 傳統方式 = 自己開車(需要關注啟動、換擋、剎車等細節)
- IoC方式 = 坐出租車(告訴目的地,司機負責駕駛)
IoC容器的類型
// 1. BeanFactory - 基礎容器(懶加載)
public class BeanFactoryExample {public static void main(String[] args) {// 創建資源對象Resource resource = new ClassPathResource("applicationContext.xml");// 創建BeanFactoryBeanFactory factory = new XmlBeanFactory(resource);// 只有在獲取Bean時才創建對象UserService userService = (UserService) factory.getBean("userService");}
}// 2. ApplicationContext - 高級容器(立即加載)
public class ApplicationContextExample {public static void main(String[] args) {// 啟動時就創建所有單例BeanApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");UserService userService = context.getBean("userService", UserService.class);}
}
ApplicationContext的實現類
// 1. 從類路徑加載XML配置
ApplicationContext context1 = new ClassPathXmlApplicationContext("applicationContext.xml");// 2. 從文件系統加載XML配置
ApplicationContext context2 = new FileSystemXmlApplicationContext("/path/to/applicationContext.xml");// 3. 基于注解的配置
ApplicationContext context3 = new AnnotationConfigApplicationContext(AppConfig.class);// 4. Web應用上下文
// 在web.xml中配置,由Spring自動創建
?? 依賴注入(DI)深入理解
什么是依賴注入?
依賴注入是IoC的具體實現方式,就是Spring容器自動為對象提供它所需要的依賴對象。
生活類比:
- 手動依賴 = 自己買零件組裝電腦
- 依賴注入 = 買品牌機(廠商已配好兼容硬件)
依賴注入的三種方式
1. 構造器注入(最推薦)
@Component
public class OrderService {// 使用final確保依賴不可變private final PaymentService paymentService;private final InventoryService inventoryService;private final NotificationService notificationService;// Spring會自動調用這個構造器public OrderService(PaymentService paymentService, InventoryService inventoryService,NotificationService notificationService) {this.paymentService = paymentService;this.inventoryService = inventoryService;this.notificationService = notificationService;}public void processOrder(Order order) {// 檢查庫存if (inventoryService.checkStock(order.getProductId(), order.getQuantity())) {// 處理支付Payment payment = paymentService.processPayment(order);if (payment.isSuccessful()) {// 發送通知notificationService.sendOrderConfirmation(order);}}}
}// 構造器注入的優點:
// 1. 確保依賴不為null(構造時必須提供)
// 2. 支持final字段(不可變性)
// 3. 便于單元測試
// 4. 避免循環依賴問題
2. Setter注入
@Component
public class UserService {private EmailService emailService;private SmsService smsService;private AuditService auditService;// Setter注入 - 可選依賴@Autowired(required = false) // 可選依賴public void setEmailService(EmailService emailService) {this.emailService = emailService;}@Autowiredpublic void setSmsService(SmsService smsService) {this.smsService = smsService;}@Autowiredpublic void setAuditService(AuditService auditService) {this.auditService = auditService;}public void registerUser(User user) {// 保存用戶saveUser(user);// 發送郵件(如果可用)if (emailService != null) {emailService.sendWelcomeEmail(user.getEmail());}// 發送短信smsService.sendWelcomeSms(user.getPhone());// 記錄審計日志auditService.logUserRegistration(user.getId());}
}// Setter注入的優點:
// 1. 支持可選依賴
// 2. 可以重新配置依賴
// 3. 適合有很多可選依賴的場景
3. 字段注入(簡單但不推薦)
@Component
public class ProductService {@Autowiredprivate ProductRepository productRepository;@Autowiredprivate PriceCalculator priceCalculator;@Autowiredprivate InventoryChecker inventoryChecker;public Product getProduct(Long id) {Product product = productRepository.findById(id);product.setPrice(priceCalculator.calculatePrice(product));product.setInStock(inventoryChecker.isInStock(product.getId()));return product;}
}// 字段注入的缺點:
// 1. 難以進行單元測試
// 2. 不支持final字段
// 3. 隱藏了依賴關系
// 4. 可能導致空指針異常
依賴注入的高級特性
1. 按類型注入 vs 按名稱注入
// 按類型注入(默認)
@Component
public class OrderService {@Autowiredprivate PaymentService paymentService; // 按PaymentService類型注入
}// 按名稱注入
@Component
public class OrderService {@Autowired@Qualifier("creditCardPaymentService") // 指定Bean名稱private PaymentService paymentService;
}// 或者使用@Resource
@Component
public class OrderService {@Resource(name = "creditCardPaymentService")private PaymentService paymentService;
}
2. 集合注入
@Component
public class NotificationService {// 注入所有MessageSender實現@Autowiredprivate List<MessageSender> messageSenders;// 注入所有MessageSender的Map,key為Bean名稱@Autowiredprivate Map<String, MessageSender> messageSenderMap;public void sendNotification(String message) {// 使用所有可用的發送器for (MessageSender sender : messageSenders) {sender.send(message);}}
}// 實現類
@Component("emailSender")
public class EmailSender implements MessageSender {public void send(String message) {System.out.println("通過郵件發送: " + message);}
}@Component("smsSender")
public class SmsSender implements MessageSender {public void send(String message) {System.out.println("通過短信發送: " + message);}
}
3. 條件注入
@Component
@ConditionalOnProperty(name = "app.feature.email", havingValue = "true")
public class EmailService {public void sendEmail(String message) {System.out.println("發送郵件: " + message);}
}@Component
@Profile("dev") // 只在dev環境生效
public class MockPaymentService implements PaymentService {public Payment processPayment(Order order) {System.out.println("模擬支付處理");return new Payment(order.getAmount(), true);}
}@Component
@Profile("prod") // 只在生產環境生效
public class RealPaymentService implements PaymentService {public Payment processPayment(Order order) {// 真實的支付處理邏輯return processRealPayment(order);}
}
?? Bean配置與管理
Bean的定義方式
1. XML配置方式
<!-- applicationContext.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"><!-- 基本Bean定義 --><bean id="userService" class="com.example.UserService"><!-- 屬性注入 --><property name="emailService" ref="emailService"/><property name="maxRetryCount" value="3"/></bean><!-- 構造器注入 --><bean id="orderService" class="com.example.OrderService"><constructor-arg ref="paymentService"/><constructor-arg ref="inventoryService"/><constructor-arg value="100"/></bean><!-- 集合屬性注入 --><bean id="notificationService" class="com.example.NotificationService"><property name="senders"><list><ref bean="emailSender"/><ref bean="smsSender"/></list></property><property name="config"><map><entry key="retryCount" value="3"/><entry key="timeout" value="5000"/></map></property></bean><!-- 內部Bean --><bean id="userController" class="com.example.UserController"><property name="userService"><bean class="com.example.UserService"><property name="emailService" ref="emailService"/></bean></property></bean><!-- Bean別名 --><alias name="userService" alias="userManager"/><!-- 啟用組件掃描 --><context:component-scan base-package="com.example"/></beans>
2. 注解配置方式
// 配置類
@Configuration
@ComponentScan(basePackages = "com.example")
@PropertySource("classpath:application.properties")
public class AppConfig {// 讀取配置文件中的值@Value("${database.url}")private String databaseUrl;@Value("${database.username}")private String username;@Value("${database.password}")private String password;// 手動定義Bean@Beanpublic DataSource dataSource() {HikariDataSource dataSource = new HikariDataSource();dataSource.setJdbcUrl(databaseUrl);dataSource.setUsername(username);dataSource.setPassword(password);return dataSource;}// Bean之間的依賴@Beanpublic UserRepository userRepository() {return new UserRepository(dataSource());}// 條件Bean@Bean@ConditionalOnMissingBean(EmailService.class)public EmailService defaultEmailService() {return new DefaultEmailService();}// 主要Bean(當有多個同類型Bean時的默認選擇)@Bean@Primarypublic PaymentService primaryPaymentService() {return new CreditCardPaymentService();}
}
3. 組件注解
// 基礎組件
@Component
public class FileProcessor {public void processFile(String filename) {System.out.println("處理文件: " + filename);}
}// 服務層組件
@Service
public class UserService {@Autowiredprivate UserRepository userRepository;public void saveUser(User user) {userRepository.save(user);}
}// 數據訪問層組件
@Repository
public class UserRepository {@Autowiredprivate DataSource dataSource;public void save(User user) {// 數據庫保存邏輯}
}// 控制層組件(雖然這里不講SpringMVC,但展示注解)
@Controller
public class UserController {@Autowiredprivate UserService userService;
}
Bean的初始化和銷毀
1. 注解方式
@Component
public class DatabaseConnection {private Connection connection;// 初始化方法@PostConstructpublic void init() {System.out.println("初始化數據庫連接");// 建立數據庫連接this.connection = DriverManager.getConnection("...");}// 銷毀方法@PreDestroypublic void cleanup() {System.out.println("關閉數據庫連接");try {if (connection != null && !connection.isClosed()) {connection.close();}} catch (SQLException e) {e.printStackTrace();}}
}
2. 接口方式
@Component
public class CacheManager implements InitializingBean, DisposableBean {private Map<String, Obje