17.Spring Boot的Bean詳解(新手版)

文章目錄

    • 1. 什么是Bean?從零開始理解
      • 1.1 Bean的定義
      • 1.2 為什么需要Bean?
      • 1.3 Bean vs 普通對象的區別
    • 2. Spring容器:Bean的家
      • 2.1 什么是Spring容器?
      • 2.2 容器的工作流程
    • 3. Bean的聲明方式詳解
      • 3.1 使用@Component及其專門化注解
        • 3.1.1 @Component - 通用組件
        • 3.1.2 @Service - 業務邏輯層
        • 3.1.3 @Repository - 數據訪問層
        • 3.1.4 @Controller和@RestController - 控制層
        • 3.1.5 用戶實體類
      • 3.2 Bean名稱自定義
    • 4. 使用@Bean注解創建Bean
      • 4.1 什么時候使用@Bean?
      • 4.2 基礎@Bean使用
      • 4.3 Bean之間的依賴
      • 4.4 條件化Bean創建
    • 5. 依賴注入詳解
      • 5.1 什么是依賴注入?
      • 5.2 依賴注入的三種方式
        • 5.2.1 構造器注入(推薦)
        • 5.2.2 Setter注入
        • 5.2.3 字段注入(不推薦,但常見)
      • 5.3 解決多個實現的問題
        • 5.3.1 使用@Qualifier
        • 5.3.2 使用@Primary
        • 5.3.3 注入所有實現
    • 6. Bean的作用域(Scope)
      • 6.1 什么是Bean作用域?
      • 6.2 Singleton作用域(默認)
      • 6.3 Prototype作用域
      • 6.4 Web作用域
        • 6.4.1 Request作用域
        • 6.4.2 Session作用域
    • 7. Bean的生命周期詳解
      • 7.1 Bean生命周期概述
      • 7.2 生命周期回調方法
        • 7.2.1 使用@PostConstruct和@PreDestroy
        • 7.2.2 實現InitializingBean和DisposableBean接口
        • 7.2.3 使用@Bean的initMethod和destroyMethod
      • 7.3 Bean后置處理器
    • 8. 高級Bean特性
      • 8.1 懶加載(Lazy Loading)
      • 8.2 條件化Bean創建
        • 8.2.1 基于配置屬性的條件
        • 8.2.2 基于類存在的條件
      • 8.3 FactoryBean
    • 9. 實際應用案例
      • 9.1 構建完整的用戶管理系統
      • 9.2 增強的用戶服務
      • 9.3 完整的控制器
    • 10. 常見問題與最佳實踐
      • 10.1 避免循環依賴
      • 10.2 合理使用Bean作用域
      • 10.3 優先使用構造器注入
      • 10.4 Bean命名規范
    • 11. 總結
      • 11.1 Bean的核心概念回顧
      • 11.2 最佳實踐總結
      • 11.3 學習建議

1. 什么是Bean?從零開始理解

1.1 Bean的定義

Bean是Spring框架中的核心概念。簡單來說,Bean就是一個由Spring容器創建、管理和維護的Java對象。

舉個生活化的例子:
想象你住在一個高級公寓(Spring容器),公寓管理員(Spring容器)負責:

  • 為你準備房間(創建Bean對象)
  • 提供水電服務(注入依賴)
  • 維護房間設施(管理Bean生命周期)
  • 處理房間之間的關系(Bean之間的依賴)

1.2 為什么需要Bean?

在傳統Java開發中,我們需要手動創建和管理對象:

// 傳統方式 - 手動管理對象
public class TraditionalExample {public static void main(String[] args) {// 手動創建數據庫連接DatabaseConnection dbConnection = new DatabaseConnection("localhost", 3306, "user", "password");// 手動創建數據訪問對象UserDao userDao = new UserDao(dbConnection);// 手動創建服務對象UserService userService = new UserService(userDao);// 手動創建控制器UserController userController = new UserController(userService);// 如果有很多對象,管理起來會很復雜!}
}

使用Spring Bean后:

// Spring方式 - 自動管理對象
@RestController
public class UserController {@Autowired  // Spring自動注入private UserService userService;// 不需要手動創建UserService,Spring會自動處理
}@Service
public class UserService {@Autowired  // Spring自動注入private UserDao userDao;// 不需要手動創建UserDao,Spring會自動處理
}

1.3 Bean vs 普通對象的區別

特性普通Java對象Spring Bean
創建方式new關鍵字手動創建Spring容器自動創建
生命周期管理開發者手動管理Spring容器自動管理
依賴注入手動傳遞參數Spring自動注入
單例管理需要手動實現Spring提供多種作用域
配置管理硬編碼或手動讀取配置Spring自動讀取配置

2. Spring容器:Bean的家

2.1 什么是Spring容器?

Spring容器就像一個智能的對象工廠,它負責:

  1. 創建對象:根據配置創建Bean實例
  2. 管理依賴:自動注入Bean之間的依賴關系
  3. 控制生命周期:管理Bean的創建、初始化、使用和銷毀
  4. 提供服務:為應用程序提供所需的Bean

2.2 容器的工作流程

// 1. Spring Boot啟動時掃描注解
@SpringBootApplication  // 這個注解告訴Spring開始掃描
public class MyApplication {public static void main(String[] args) {// 2. 啟動Spring容器SpringApplication.run(MyApplication.class, args);// 3. 容器開始創建和管理Bean}
}// 4. Spring發現這個類有@Service注解,創建Bean
@Service
public class UserService {// 5. Spring創建UserService的實例并放入容器中
}// 6. Spring發現需要注入UserService的地方,自動注入
@RestController
public class UserController {@Autowiredprivate UserService userService;  // 7. Spring自動注入
}

3. Bean的聲明方式詳解

3.1 使用@Component及其專門化注解

3.1.1 @Component - 通用組件
// 最基礎的Bean聲明方式
@Component
public class EmailSender {public void sendEmail(String to, String subject, String body) {System.out.println("發送郵件到: " + to);System.out.println("主題: " + subject);System.out.println("內容: " + body);}
}// 使用這個Bean
@Service
public class NotificationService {@Autowiredprivate EmailSender emailSender;  // Spring會自動注入EmailSenderpublic void sendWelcomeEmail(String userEmail) {emailSender.sendEmail(userEmail, "歡迎", "歡迎注冊我們的網站!");}
}
3.1.2 @Service - 業務邏輯層
// @Service表示這是一個服務層的Bean
@Service
public class UserService {@Autowiredprivate UserRepository userRepository;// 注冊新用戶public User registerUser(String username, String email, String password) {// 1. 檢查用戶是否已存在if (userRepository.existsByUsername(username)) {throw new RuntimeException("用戶名已存在");}// 2. 創建新用戶User user = new User();user.setUsername(username);user.setEmail(email);user.setPassword(encryptPassword(password));// 3. 保存用戶return userRepository.save(user);}// 獲取用戶信息public User getUserById(Long id) {return userRepository.findById(id).orElseThrow(() -> new RuntimeException("用戶不存在"));}// 密碼加密(簡化示例)private String encryptPassword(String password) {return "encrypted_" + password;}
}
3.1.3 @Repository - 數據訪問層
// @Repository表示這是一個數據訪問層的Bean
@Repository
public class UserRepository {// 模擬數據庫存儲private List<User> users = new ArrayList<>();private Long nextId = 1L;// 保存用戶public User save(User user) {if (user.getId() == null) {user.setId(nextId++);}// 如果是更新操作,先刪除舊的users.removeIf(u -> u.getId().equals(user.getId()));users.add(user);System.out.println("用戶已保存: " + user.getUsername());return user;}// 根據ID查找用戶public Optional<User> findById(Long id) {return users.stream().filter(user -> user.getId().equals(id)).findFirst();}// 檢查用戶名是否存在public boolean existsByUsername(String username) {return users.stream().anyMatch(user -> user.getUsername().equals(username));}// 查找所有用戶public List<User> findAll() {return new ArrayList<>(users);}// 根據用戶名查找public Optional<User> findByUsername(String username) {return users.stream().filter(user -> user.getUsername().equals(username)).findFirst();}
}
3.1.4 @Controller和@RestController - 控制層
// @RestController = @Controller + @ResponseBody
// 表示這是一個RESTful API控制器
@RestController
@RequestMapping("/api/users")  // 基礎路徑
public class UserController {@Autowiredprivate UserService userService;@Autowiredprivate NotificationService notificationService;// 注冊新用戶@PostMapping("/register")public ResponseEntity<String> registerUser(@RequestBody UserRegistrationRequest request) {try {// 1. 調用服務層注冊用戶User user = userService.registerUser(request.getUsername(), request.getEmail(), request.getPassword());// 2. 發送歡迎郵件notificationService.sendWelcomeEmail(user.getEmail());// 3. 返回成功響應return ResponseEntity.ok("用戶注冊成功: " + user.getUsername());} catch (Exception e) {// 4. 處理異常return ResponseEntity.badRequest().body("注冊失敗: " + e.getMessage());}}// 獲取用戶信息@GetMapping("/{id}")public ResponseEntity<User> getUser(@PathVariable Long id) {try {User user = userService.getUserById(id);return ResponseEntity.ok(user);} catch (Exception e) {return ResponseEntity.notFound().build();}}// 獲取所有用戶@GetMappingpublic ResponseEntity<List<User>> getAllUsers() {// 這里為了演示,直接調用Repository// 實際項目中應該通過Service層return ResponseEntity.ok(userService.getAllUsers());}
}// 用戶注冊請求的數據模型
public class UserRegistrationRequest {private String username;private String email;private String password;// 構造函數public UserRegistrationRequest() {}// Getter和Setter方法public String getUsername() { return username; }public void setUsername(String username) { this.username = username; }public String getEmail() { return email; }public void setEmail(String email) { this.email = email; }public String getPassword() { return password; }public void setPassword(String password) { this.password = password; }
}
3.1.5 用戶實體類
// 用戶實體類
public class User {private Long id;private String username;private String email;private String password;private LocalDateTime createdAt;// 構造函數public User() {this.createdAt = LocalDateTime.now();}public User(String username, String email, String password) {this();this.username = username;this.email = email;this.password = password;}// Getter和Setter方法public Long getId() { return id; }public void setId(Long id) { this.id = id; }public String getUsername() { return username; }public void setUsername(String username) { this.username = username; }public String getEmail() { return email; }public void setEmail(String email) { this.email = email; }public String getPassword() { return password; }public void setPassword(String password) { this.password = password; }public LocalDateTime getCreatedAt() { return createdAt; }public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }@Overridepublic String toString() {return "User{" +"id=" + id +", username='" + username + '\'' +", email='" + email + '\'' +", createdAt=" + createdAt +'}';}
}

3.2 Bean名稱自定義

// 默認Bean名稱是類名首字母小寫
@Service  // Bean名稱: userService
public class UserService {
}// 自定義Bean名稱
@Service("myUserService")  // Bean名稱: myUserService
public class UserService {
}@Component("emailSender")  // Bean名稱: emailSender
public class EmailSender {
}// 在其他地方通過名稱注入
@RestController
public class UserController {@Autowired@Qualifier("myUserService")  // 通過名稱指定要注入的Beanprivate UserService userService;
}

4. 使用@Bean注解創建Bean

4.1 什么時候使用@Bean?

當你需要:

  1. 配置第三方庫的對象
  2. 需要復雜的創建邏輯
  3. 根據條件創建不同的Bean
  4. 配置系統組件

4.2 基礎@Bean使用

@Configuration  // 表示這是一個配置類
public class AppConfig {// 創建數據庫連接Bean@Beanpublic DataSource dataSource() {DriverManagerDataSource dataSource = new DriverManagerDataSource();dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");dataSource.setUrl("jdbc:mysql://localhost:3306/mydb?useSSL=false&serverTimezone=UTC");dataSource.setUsername("root");dataSource.setPassword("password");System.out.println("數據源Bean已創建");return dataSource;}// 創建Redis連接Bean@Beanpublic JedisPool jedisPool() {JedisPoolConfig config = new JedisPoolConfig();config.setMaxTotal(100);  // 最大連接數config.setMaxIdle(20);    // 最大空閑連接數config.setMinIdle(5);     // 最小空閑連接數return new JedisPool(config, "localhost", 6379);}// 創建郵件發送器Bean@Beanpublic JavaMailSender mailSender() {JavaMailSenderImpl mailSender = new JavaMailSenderImpl();mailSender.setHost("smtp.qq.com");mailSender.setPort(587);mailSender.setUsername("your-email@qq.com");mailSender.setPassword("your-password");Properties props = mailSender.getJavaMailProperties();props.put("mail.transport.protocol", "smtp");props.put("mail.smtp.auth", "true");props.put("mail.smtp.starttls.enable", "true");return mailSender;}
}

4.3 Bean之間的依賴

@Configuration
public class ServiceConfig {// 創建數據庫服務Bean@Beanpublic DatabaseService databaseService(DataSource dataSource) {// Spring會自動注入dataSource參數return new DatabaseService(dataSource);}// 創建緩存服務Bean@Beanpublic CacheService cacheService(JedisPool jedisPool) {return new CacheService(jedisPool);}// 創建用戶服務Bean,依賴于數據庫服務和緩存服務@Beanpublic UserService userService(DatabaseService databaseService, CacheService cacheService) {UserService userService = new UserService();userService.setDatabaseService(databaseService);userService.setCacheService(cacheService);return userService;}
}// 數據庫服務類
public class DatabaseService {private DataSource dataSource;public DatabaseService(DataSource dataSource) {this.dataSource = dataSource;System.out.println("DatabaseService初始化完成");}public void saveUser(User user) {System.out.println("保存用戶到數據庫: " + user.getUsername());// 實際的數據庫操作}
}// 緩存服務類
public class CacheService {private JedisPool jedisPool;public CacheService(JedisPool jedisPool) {this.jedisPool = jedisPool;System.out.println("CacheService初始化完成");}public void cacheUser(User user) {System.out.println("緩存用戶信息: " + user.getUsername());// 實際的緩存操作}
}

4.4 條件化Bean創建

@Configuration
public class ConditionalConfig {// 只在開發環境創建的Bean@Bean@Profile("dev")  // 只在dev配置文件激活時創建public DataSource devDataSource() {System.out.println("創建開發環境數據源");DriverManagerDataSource dataSource = new DriverManagerDataSource();dataSource.setUrl("jdbc:h2:mem:devdb");  // 內存數據庫return dataSource;}// 只在生產環境創建的Bean@Bean@Profile("prod")  // 只在prod配置文件激活時創建public DataSource prodDataSource() {System.out.println("創建生產環境數據源");DriverManagerDataSource dataSource = new DriverManagerDataSource();dataSource.setUrl("jdbc:mysql://prod-server:3306/proddb");return dataSource;}// 根據配置屬性創建Bean@Bean@ConditionalOnProperty(name = "app.cache.enabled", havingValue = "true")public CacheManager cacheManager() {System.out.println("緩存已啟用,創建緩存管理器");return new ConcurrentMapCacheManager("users", "products");}
}

5. 依賴注入詳解

5.1 什么是依賴注入?

依賴注入(Dependency Injection,DI)是一種設計模式,它允許我們在對象外部創建對象的依賴關系,然后將這些依賴關系"注入"到對象中。

生活化例子:
想象你要做一頓飯:

  • 傳統方式:你親自去買菜、洗菜、切菜,然后做飯
  • 依賴注入方式:有人把洗好切好的菜直接送到你廚房,你只需要專心做飯

5.2 依賴注入的三種方式

5.2.1 構造器注入(推薦)
@Service
public class OrderService {private final UserService userService;private final ProductService productService;private final PaymentService paymentService;// 構造器注入 - 推薦方式public OrderService(UserService userService, ProductService productService, PaymentService paymentService) {this.userService = userService;this.productService = productService;this.paymentService = paymentService;System.out.println("OrderService通過構造器注入創建完成");}public Order createOrder(Long userId, Long productId, BigDecimal amount) {// 1. 驗證用戶User user = userService.getUserById(userId);if (user == null) {throw new RuntimeException("用戶不存在");}// 2. 驗證產品Product product = productService.getProductById(productId);if (product == null) {throw new RuntimeException("產品不存在");}// 3. 創建訂單Order order = new Order();order.setUserId(userId);order.setProductId(productId);order.setAmount(amount);order.setStatus("CREATED");// 4. 處理支付boolean paymentSuccess = paymentService.processPayment(order);if (paymentSuccess) {order.setStatus("PAID");} else {order.setStatus("PAYMENT_FAILED");}return order;}
}// 產品服務
@Service
public class ProductService {public Product getProductById(Long id) {// 模擬查找產品Product product = new Product();product.setId(id);product.setName("示例產品 " + id);product.setPrice(new BigDecimal("99.99"));return product;}
}// 支付服務
@Service
public class PaymentService {public boolean processPayment(Order order) {System.out.println("處理訂單支付: " + order.getId() + ", 金額: " + order.getAmount());// 模擬支付處理try {Thread.sleep(1000);  // 模擬網絡延遲return Math.random() > 0.1;  // 90%成功率} catch (InterruptedException e) {return false;}}
}

構造器注入的優點:

  1. 依賴不可變:可以使用final關鍵字
  2. 保證完整性:對象創建時就有了所有依賴
  3. 便于測試:容易進行單元測試
  4. 避免循環依賴:編譯時就能發現問題
5.2.2 Setter注入
@Service
public class NotificationService {private EmailService emailService;private SmsService smsService;private PushService pushService;// Setter注入@Autowiredpublic void setEmailService(EmailService emailService) {this.emailService = emailService;System.out.println("EmailService已注入");}@Autowiredpublic void setSmsService(SmsService smsService) {this.smsService = smsService;System.out.println("SmsService已注入");}@Autowired(required = false)  // 可選依賴public void setPushService(PushService pushService) {this.pushService = pushService;System.out.println("PushService已注入");}public void sendNotification(String userId, String message) {// 發送郵件通知if (emailService != null) {emailService.sendEmail(userId, "通知", message);}// 發送短信通知if (smsService != null) {smsService.sendSms(userId, message);}// 發送推送通知(可選)if (pushService != null) {pushService.sendPush(userId, message);}}
}@Service
public class EmailService {public void sendEmail(String to, String subject, String body) {System.out.println("發送郵件 - 收件人: " + to + ", 主題: " + subject);}
}@Service
public class SmsService {public void sendSms(String phone, String message) {System.out.println("發送短信 - 手機號: " + phone + ", 內容: " + message);}
}// 推送服務可能不總是可用
@Service
@ConditionalOnProperty(name = "app.push.enabled", havingValue = "true")
public class PushService {public void sendPush(String userId, String message) {System.out.println("發送推送 - 用戶: " + userId + ", 內容: " + message);}
}
5.2.3 字段注入(不推薦,但常見)
@RestController
@RequestMapping("/api/orders")
public class OrderController {// 字段注入 - 簡單但不推薦@Autowiredprivate OrderService orderService;@Autowiredprivate NotificationService notificationService;@PostMappingpublic ResponseEntity<String> createOrder(@RequestBody OrderRequest request) {try {Order order = orderService.createOrder(request.getUserId(), request.getProductId(), request.getAmount());// 發送通知notificationService.sendNotification(request.getUserId().toString(), "訂單創建成功: " + order.getId());return ResponseEntity.ok("訂單創建成功: " + order.getId());} catch (Exception e) {return ResponseEntity.badRequest().body("訂單創建失敗: " + e.getMessage());}}
}// 訂單請求DTO
public class OrderRequest {private Long userId;private Long productId;private BigDecimal amount;// Getter和Setterpublic Long getUserId() { return userId; }public void setUserId(Long userId) { this.userId = userId; }public Long getProductId() { return productId; }public void setProductId(Long productId) { this.productId = productId; }public BigDecimal getAmount() { return amount; }public void setAmount(BigDecimal amount) { this.amount = amount; }
}

5.3 解決多個實現的問題

當一個接口有多個實現時,Spring需要知道注入哪一個。

5.3.1 使用@Qualifier
// 支付接口
public interface PaymentProcessor {boolean processPayment(BigDecimal amount);
}// 支付寶實現
@Service("alipayProcessor")
public class AlipayProcessor implements PaymentProcessor {@Overridepublic boolean processPayment(BigDecimal amount) {System.out.println("使用支付寶支付: " + amount);return true;}
}// 微信支付實現
@Service("wechatProcessor")
public class WechatPayProcessor implements PaymentProcessor {@Overridepublic boolean processPayment(BigDecimal amount) {System.out.println("使用微信支付: " + amount);return true;}
}// 銀行卡支付實現
@Service("bankCardProcessor")
public class BankCardProcessor implements PaymentProcessor {@Overridepublic boolean processPayment(BigDecimal amount) {System.out.println("使用銀行卡支付: " + amount);return true;}
}// 使用特定的支付處理器
@Service
public class PaymentService {private final PaymentProcessor alipayProcessor;private final PaymentProcessor wechatProcessor;private final PaymentProcessor bankCardProcessor;public PaymentService(@Qualifier("alipayProcessor") PaymentProcessor alipayProcessor,@Qualifier("wechatProcessor") PaymentProcessor wechatProcessor,@Qualifier("bankCardProcessor") PaymentProcessor bankCardProcessor) {this.alipayProcessor = alipayProcessor;this.wechatProcessor = wechatProcessor;this.bankCardProcessor = bankCardProcessor;}public boolean processPayment(String paymentType, BigDecimal amount) {switch (paymentType.toLowerCase()) {case "alipay":return alipayProcessor.processPayment(amount);case "wechat":return wechatProcessor.processPayment(amount);case "bank":return bankCardProcessor.processPayment(amount);default:throw new IllegalArgumentException("不支持的支付方式: " + paymentType);}}
}
5.3.2 使用@Primary
// 設置默認的支付處理器
@Service
@Primary  // 默認使用這個實現
public class DefaultPaymentProcessor implements PaymentProcessor {@Overridepublic boolean processPayment(BigDecimal amount) {System.out.println("使用默認支付方式: " + amount);return true;}
}@Service
public class SimplePaymentService {private final PaymentProcessor paymentProcessor;// 會自動注入@Primary標記的實現public SimplePaymentService(PaymentProcessor paymentProcessor) {this.paymentProcessor = paymentProcessor;}public boolean pay(BigDecimal amount) {return paymentProcessor.processPayment(amount);}
}
5.3.3 注入所有實現
@Service
public class PaymentServiceManager {private final List<PaymentProcessor> paymentProcessors;private final Map<String, PaymentProcessor> processorMap;// 注入所有PaymentProcessor實現public PaymentServiceManager(List<PaymentProcessor> paymentProcessors) {this.paymentProcessors = paymentProcessors;this.processorMap = new HashMap<>();// 根據類名建立映射for (PaymentProcessor processor : paymentProcessors) {String name = processor.getClass().getSimpleName().toLowerCase();processorMap.put(name, processor);}System.out.println("發現 " + paymentProcessors.size() + " 個支付處理器");}public List<String> getAvailablePaymentMethods() {return new ArrayList<>(processorMap.keySet());}public boolean processPayment(String method, BigDecimal amount) {PaymentProcessor processor = processorMap.get(method.toLowerCase());if (processor != null) {return processor.processPayment(amount);} else {throw new IllegalArgumentException("不支持的支付方式: " + method);}}
}

6. Bean的作用域(Scope)

6.1 什么是Bean作用域?

Bean作用域定義了Bean實例的生命周期和可見性。Spring提供了多種作用域來滿足不同的需求。

6.2 Singleton作用域(默認)

// 默認就是單例作用域
@Service
public class UserService {private int counter = 0;public String getServiceInfo() {counter++;return "UserService實例: " + this.hashCode() + ", 調用次數: " + counter;}
}// 測試單例特性
@RestController
public class TestController {@Autowiredprivate UserService userService1;@Autowiredprivate UserService userService2;@GetMapping("/test-singleton")public Map<String, String> testSingleton() {Map<String, String> result = new HashMap<>();result.put("service1", userService1.getServiceInfo());result.put("service2", userService2.getServiceInfo());result.put("same_instance", String.valueOf(userService1 == userService2));return result;// 結果會顯示兩個服務是同一個實例,counter會持續增加}
}

6.3 Prototype作用域

// 每次請求都創建新實例
@Service
@Scope("prototype")  // 或者 @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class TokenGenerator {private final String token;private final LocalDateTime createdAt;public TokenGenerator() {this.token = UUID.randomUUID().toString();this.createdAt = LocalDateTime.now();System.out.println("創建新的TokenGenerator: " + token);}public String getToken() {return token;}public LocalDateTime getCreatedAt() {return createdAt;}
}// 使用Prototype Bean
@Service
public class AuthService {private final ApplicationContext applicationContext;public AuthService(ApplicationContext applicationContext) {this.applicationContext = applicationContext;}public String generateNewToken() {// 每次調用都會創建新的TokenGenerator實例TokenGenerator generator = applicationContext.getBean(TokenGenerator.class);return generator.getToken();}
}

6.4 Web作用域

6.4.1 Request作用域
// 每個HTTP請求創建一個實例
@Component
@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class RequestInfo {private final String requestId;private final LocalDateTime requestTime;private final Map<String, Object> attributes;public RequestInfo() {this.requestId = UUID.randomUUID().toString();this.requestTime = LocalDateTime.now();this.attributes = new HashMap<>();System.out.println("創建新的RequestInfo: " + requestId);}public String getRequestId() {return requestId;}public LocalDateTime getRequestTime() {return requestTime;}public void setAttribute(String key, Object value) {attributes.put(key, value);}public Object getAttribute(String key) {return attributes.get(key);}public Map<String, Object> getAllAttributes() {return new HashMap<>(attributes);}
}// 使用Request作用域Bean
@RestController
public class RequestController {@Autowiredprivate RequestInfo requestInfo;@GetMapping("/request-info")public Map<String, Object> getRequestInfo() {requestInfo.setAttribute("endpoint", "/request-info");requestInfo.setAttribute("timestamp", LocalDateTime.now().toString());Map<String, Object> result = new HashMap<>();result.put("requestId", requestInfo.getRequestId());result.put("requestTime", requestInfo.getRequestTime());result.put("attributes", requestInfo.getAllAttributes());return result;}@GetMapping("/another-endpoint")public Map<String, Object> anotherEndpoint() {// 同一個請求中,requestInfo是同一個實例requestInfo.setAttribute("endpoint", "/another-endpoint");Map<String, Object> result = new HashMap<>();result.put("requestId", requestInfo.getRequestId());result.put("message", "這是同一個請求中的另一個端點");return result;}
}
6.4.2 Session作用域
// 每個HTTP會話創建一個實例
@Component
@Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class UserSession {private final String sessionId;private final LocalDateTime sessionStart;private String username;private final Map<String, Object> sessionData;public UserSession() {this.sessionId = UUID.randomUUID().toString();this.sessionStart = LocalDateTime.now();this.sessionData = new HashMap<>();System.out.println("創建新的UserSession: " + sessionId);}public String getSessionId() {return sessionId;}public LocalDateTime getSessionStart() {return sessionStart;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public void putData(String key, Object value) {sessionData.put(key, value);}public Object getData(String key) {return sessionData.get(key);}public boolean isLoggedIn() {return username != null;}
}// 使用Session作用域Bean
@RestController
@RequestMapping("/session")
public class SessionController {@Autowiredprivate UserSession userSession;@PostMapping("/login")public Map<String, Object> login(@RequestBody LoginRequest request) {// 模擬登錄驗證if ("admin".equals(request.getUsername()) && "password".equals(request.getPassword())) {userSession.setUsername(request.getUsername());userSession.putData("loginTime", LocalDateTime.now());Map<String, Object> result = new HashMap<>();result.put("success", true);result.put("sessionId", userSession.getSessionId());result.put("message", "登錄成功");return result;} else {Map<String, Object> result = new HashMap<>();result.put("success", false);result.put("message", "用戶名或密碼錯誤");return result;}}@GetMapping("/info")public Map<String, Object> getSessionInfo() {Map<String, Object> result = new HashMap<>();result.put("sessionId", userSession.getSessionId());result.put("sessionStart", userSession.getSessionStart());result.put("username", userSession.getUsername());result.put("isLoggedIn", userSession.isLoggedIn());result.put("loginTime", userSession.getData("loginTime"));return result;}@PostMapping("/logout")public Map<String, Object> logout() {userSession.setUsername(null);userSession.putData("loginTime", null);Map<String, Object> result = new HashMap<>();result.put("success", true);result.put("message", "已退出登錄");return result;}
}// 登錄請求DTO
public class LoginRequest {private String username;private String password;// Getter和Setterpublic String getUsername() { return username; }public void setUsername(String username) { this.username = username; }public String getPassword() { return password; }public void setPassword(String password) { this.password = password; }
}

7. Bean的生命周期詳解

7.1 Bean生命周期概述

Bean的生命周期包括以下階段:

  1. 實例化:創建Bean實例
  2. 屬性賦值:設置Bean的屬性
  3. 初始化:執行初始化方法
  4. 使用:Bean可以被應用程序使用
  5. 銷毀:應用關閉時銷毀Bean

7.2 生命周期回調方法

7.2.1 使用@PostConstruct和@PreDestroy
@Service
public class DatabaseConnectionService {private Connection connection;private boolean isConnected = false;// Bean創建后自動調用@PostConstructpublic void initialize() {System.out.println("=== Bean初始化開始 ===");try {// 模擬建立數據庫連接System.out.println("正在連接到數據庫...");Thread.sleep(1000); // 模擬連接耗時// 實際項目中這里會是真實的數據庫連接this.connection = createConnection();this.isConnected = true;System.out.println("數據庫連接已建立");System.out.println("=== Bean初始化完成 ===");} catch (Exception e) {System.err.println("數據庫連接失敗: " + e.getMessage());}}// Bean銷毀前自動調用@PreDestroypublic void cleanup() {System.out.println("=== Bean銷毀開始 ===");try {if (connection != null && isConnected) {// 關閉數據庫連接connection.close();System.out.println("數據庫連接已關閉");}// 清理其他資源System.out.println("清理完成");System.out.println("=== Bean銷毀完成 ===");} catch (Exception e) {System.err.println("資源清理失敗: " + e.getMessage());}}public boolean executeQuery(String sql) {if (!isConnected) {throw new RuntimeException("數據庫未連接");}System.out.println("執行SQL: " + sql);return true;}// 模擬創建連接private Connection createConnection() {return new Connection() {private boolean closed = false;@Overridepublic void close() {this.closed = true;isConnected = false;}@Overridepublic boolean isClosed() {return closed;}// 其他Connection方法的簡單實現...};}
}
7.2.2 實現InitializingBean和DisposableBean接口
@Service
public class CacheService implements InitializingBean, DisposableBean {private Map<String, Object> cache;private boolean cacheEnabled = false;@Overridepublic void afterPropertiesSet() throws Exception {System.out.println("=== CacheService初始化 ===");// 初始化緩存this.cache = new ConcurrentHashMap<>();// 預加載一些數據preloadCache();this.cacheEnabled = true;System.out.println("緩存服務已啟動,預加載了 " + cache.size() + " 條數據");}@Overridepublic void destroy() throws Exception {System.out.println("=== CacheService銷毀 ===");if (cache != null) {System.out.println("清理緩存數據,共 " + cache.size() + " 條");cache.clear();cache = null;}this.cacheEnabled = false;System.out.println("緩存服務已關閉");}private void preloadCache() {// 預加載一些常用數據cache.put("app.name", "Spring Boot Demo");cache.put("app.version", "1.0.0");cache.put("app.author", "Developer");System.out.println("預加載緩存數據完成");}public void put(String key, Object value) {if (!cacheEnabled) {throw new RuntimeException("緩存服務未啟用");}cache.put(key, value);System.out.println("緩存數據: " + key);}public Object get(String key) {if (!cacheEnabled) {throw new RuntimeException("緩存服務未啟用");}return cache.get(key);}public boolean containsKey(String key) {return cacheEnabled && cache.containsKey(key);}public int size() {return cacheEnabled ? cache.size() : 0;}
}
7.2.3 使用@Bean的initMethod和destroyMethod
@Configuration
public class ThirdPartyConfig {@Bean(initMethod = "start", destroyMethod = "stop")public ExternalService externalService() {ExternalService service = new ExternalService();service.setServiceUrl("http://api.example.com");service.setApiKey("your-api-key");service.setTimeout(5000);return service;}
}// 第三方服務類(模擬)
public class ExternalService {private String serviceUrl;private String apiKey;private int timeout;private boolean isRunning = false;// 初始化方法public void start() {System.out.println("=== 啟動外部服務 ===");System.out.println("服務URL: " + serviceUrl);System.out.println("API密鑰: " + apiKey);System.out.println("超時時間: " + timeout + "ms");// 模擬啟動過程try {Thread.sleep(500);this.isRunning = true;System.out.println("外部服務啟動成功");} catch (InterruptedException e) {System.err.println("服務啟動失敗: " + e.getMessage());}}// 銷毀方法public void stop() {System.out.println("=== 關閉外部服務 ===");this.isRunning = false;System.out.println("外部服務已關閉");}public String callApi(String endpoint, String data) {if (!isRunning) {throw new RuntimeException("服務未運行");}System.out.println("調用API: " + serviceUrl + endpoint + " 數據: " + data);return "API調用成功";}// Getter和Setter方法public void setServiceUrl(String serviceUrl) { this.serviceUrl = serviceUrl; }public void setApiKey(String apiKey) { this.apiKey = apiKey; }public void setTimeout(int timeout) { this.timeout = timeout; }
}

7.3 Bean后置處理器

@Component
public class CustomBeanPostProcessor implements BeanPostProcessor {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {if (bean instanceof UserService) {System.out.println("準備初始化UserService: " + beanName);// 可以在這里修改bean的屬性}return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {if (bean instanceof UserService) {System.out.println("UserService初始化完成: " + beanName);// 可以在這里返回代理對象}return bean;}
}

8. 高級Bean特性

8.1 懶加載(Lazy Loading)

// 懶加載Bean - 只有在被使用時才創建
@Service
@Lazy
public class HeavyService {public HeavyService() {System.out.println("=== 創建HeavyService ===");System.out.println("這是一個重量級服務,初始化需要很長時間...");// 模擬耗時的初始化過程try {Thread.sleep(3000);System.out.println("HeavyService初始化完成!");} catch (InterruptedException e) {Thread.currentThread().interrupt();}}public String doHeavyWork() {return "執行重量級任務完成";}
}// 使用懶加載Bean
@RestController
public class LazyController {@Autowired@Lazy  // 這里也需要加@Lazy,否則會立即初始化private HeavyService heavyService;@GetMapping("/heavy-work")public String doHeavyWork() {// 只有當這個方法被調用時,HeavyService才會被創建return heavyService.doHeavyWork();}
}

8.2 條件化Bean創建

8.2.1 基于配置屬性的條件
@Configuration
public class ConditionalBeanConfig {// 只有當配置文件中cache.enabled=true時才創建@Bean@ConditionalOnProperty(name = "cache.enabled", havingValue = "true", matchIfMissing = false)public CacheManager redisCacheManager() {System.out.println("創建Redis緩存管理器");// 實際項目中這里會配置Redisreturn new ConcurrentMapCacheManager("users", "products");}// 如果沒有配置緩存,則使用內存緩存@Bean@ConditionalOnProperty(name = "cache.enabled", havingValue = "false", matchIfMissing = true)public CacheManager memoryCacheManager() {System.out.println("創建內存緩存管理器");return new ConcurrentMapCacheManager();}// 基于表達式的條件@Bean@ConditionalOnExpression("${cache.enabled:false} and '${cache.type}'.equals('redis')")public RedisTemplate<String, Object> redisTemplate() {System.out.println("創建Redis模板");return new RedisTemplate<>();}
}
8.2.2 基于類存在的條件
@Configuration
public class ClassBasedConditionalConfig {// 只有當類路徑中存在Redis類時才創建@Bean@ConditionalOnClass(name = "org.springframework.data.redis.core.RedisTemplate")public RedisConnectionFactory redisConnectionFactory() {System.out.println("Redis庫存在,創建Redis連接工廠");// 這里會返回實際的Redis連接工廠return new MockRedisConnectionFactory();}// 當某個Bean不存在時才創建@Bean@ConditionalOnMissingBean(DataSource.class)public DataSource defaultDataSource() {System.out.println("沒有配置數據源,使用默認數據源");DriverManagerDataSource dataSource = new DriverManagerDataSource();dataSource.setUrl("jdbc:h2:mem:testdb");return dataSource;}
}// 模擬Redis連接工廠
class MockRedisConnectionFactory implements RedisConnectionFactory {// 簡化實現
}

8.3 FactoryBean

// 使用FactoryBean創建復雜對象
@Component
public class DatabaseConnectionFactoryBean implements FactoryBean<DatabaseConnection> {@Value("${database.url:jdbc:h2:mem:testdb}")private String url;@Value("${database.username:sa}")private String username;@Value("${database.password:}")private String password;@Overridepublic DatabaseConnection getObject() throws Exception {System.out.println("通過FactoryBean創建數據庫連接");// 復雜的對象創建邏輯DatabaseConnection connection = new DatabaseConnection();connection.setUrl(url);connection.setUsername(username);connection.setPassword(password);// 執行連接測試if (connection.testConnection()) {System.out.println("數據庫連接測試成功");} else {throw new RuntimeException("數據庫連接測試失敗");}return connection;}@Overridepublic Class<?> getObjectType() {return DatabaseConnection.class;}@Overridepublic boolean isSingleton() {return true;  // 返回單例}
}// 數據庫連接類
public class DatabaseConnection {private String url;private String username;private String password;public boolean testConnection() {System.out.println("測試數據庫連接: " + url);// 模擬連接測試return true;}public void executeQuery(String sql) {System.out.println("執行SQL: " + sql);}// Getter和Setter方法public void setUrl(String url) { this.url = url; }public void setUsername(String username) { this.username = username; }public void setPassword(String password) { this.password = password; }
}

9. 實際應用案例

9.1 構建完整的用戶管理系統

// 配置類
@Configuration
@EnableConfigurationProperties(AppProperties.class)
public class UserManagementConfig {@Bean@ConditionalOnProperty(name = "app.security.enabled", havingValue = "true")public PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}@Bean@ConditionalOnProperty(name = "app.security.enabled", havingValue = "false", matchIfMissing = true)public PasswordEncoder simplePasswordEncoder() {return new SimplePasswordEncoder();}@Beanpublic UserValidator userValidator(AppProperties properties) {UserValidator validator = new UserValidator();validator.setMinPasswordLength(properties.getMinPasswordLength());validator.setRequireEmail(properties.isRequireEmail());return validator;}
}// 配置屬性類
@ConfigurationProperties(prefix = "app")
@Data
public class AppProperties {private Security security = new Security();private int minPasswordLength = 6;private boolean requireEmail = true;@Datapublic static class Security {private boolean enabled = true;private int maxLoginAttempts = 3;}// Getter和Setter方法省略
}// 簡單密碼編碼器
public class SimplePasswordEncoder implements PasswordEncoder {@Overridepublic String encode(CharSequence rawPassword) {return "simple_" + rawPassword.toString();}@Overridepublic boolean matches(CharSequence rawPassword, String encodedPassword) {return encodedPassword.equals(encode(rawPassword));}
}// 用戶驗證器
public class UserValidator {private int minPasswordLength = 6;private boolean requireEmail = true;public void validateUser(User user) {if (user.getUsername() == null || user.getUsername().trim().isEmpty()) {throw new IllegalArgumentException("用戶名不能為空");}if (user.getPassword() == null || user.getPassword().length() < minPasswordLength) {throw new IllegalArgumentException("密碼長度至少" + minPasswordLength + "位");}if (requireEmail && (user.getEmail() == null || user.getEmail().trim().isEmpty())) {throw new IllegalArgumentException("郵箱不能為空");}if (user.getEmail() != null && !isValidEmail(user.getEmail())) {throw new IllegalArgumentException("郵箱格式不正確");}}private boolean isValidEmail(String email) {return email.contains("@") && email.contains(".");}// Setter方法public void setMinPasswordLength(int minPasswordLength) { this.minPasswordLength = minPasswordLength; }public void setRequireEmail(boolean requireEmail) { this.requireEmail = requireEmail; }
}

9.2 增強的用戶服務

@Service
@Transactional
public class EnhancedUserService {private final UserRepository userRepository;private final PasswordEncoder passwordEncoder;private final UserValidator userValidator;private final NotificationService notificationService;private final CacheService cacheService;public EnhancedUserService(UserRepository userRepository,PasswordEncoder passwordEncoder,UserValidator userValidator,NotificationService notificationService,CacheService cacheService) {this.userRepository = userRepository;this.passwordEncoder = passwordEncoder;this.userValidator = userValidator;this.notificationService = notificationService;this.cacheService = cacheService;System.out.println("EnhancedUserService創建完成,使用的密碼編碼器: " + passwordEncoder.getClass().getSimpleName());}public User registerUser(UserRegistrationRequest request) {System.out.println("開始注冊用戶: " + request.getUsername());// 1. 創建用戶對象User user = new User();user.setUsername(request.getUsername());user.setEmail(request.getEmail());user.setPassword(request.getPassword());// 2. 驗證用戶信息userValidator.validateUser(user);// 3. 檢查用戶名是否已存在if (userRepository.existsByUsername(request.getUsername())) {throw new RuntimeException("用戶名已存在: " + request.getUsername());}// 4. 加密密碼String encodedPassword = passwordEncoder.encode(request.getPassword());user.setPassword(encodedPassword);// 5. 保存用戶User savedUser = userRepository.save(user);// 6. 緩存用戶信息cacheUserInfo(savedUser);// 7. 發送歡迎通知try {notificationService.sendWelcomeEmail(savedUser.getEmail());} catch (Exception e) {System.err.println("發送歡迎郵件失敗: " + e.getMessage());// 不影響用戶注冊流程}System.out.println("用戶注冊成功: " + savedUser.getUsername());return savedUser;}public User getUserById(Long id) {// 1. 先從緩存查找String cacheKey = "user:" + id;if (cacheService.containsKey(cacheKey)) {System.out.println("從緩存獲取用戶: " + id);return (User) cacheService.get(cacheKey);}// 2. 從數據庫查找User user = userRepository.findById(id).orElseThrow(() -> new RuntimeException("用戶不存在: " + id));// 3. 放入緩存cacheUserInfo(user);return user;}public boolean authenticateUser(String username, String password) {Optional<User> userOpt = userRepository.findByUsername(username);if (!userOpt.isPresent()) {return false;}User user = userOpt.get();return passwordEncoder.matches(password, user.getPassword());}public List<User> getAllUsers() {return userRepository.findAll();}public User updateUser(Long id, UserUpdateRequest request) {User user = getUserById(id);if (request.getEmail() != null) {user.setEmail(request.getEmail());}if (request.getPassword() != null) {userValidator.validateUser(user);  // 驗證新信息String encodedPassword = passwordEncoder.encode(request.getPassword());user.setPassword(encodedPassword);}User updatedUser = userRepository.save(user);// 更新緩存cacheUserInfo(updatedUser);return updatedUser;}private void cacheUserInfo(User user) {String cacheKey = "user:" + user.getId();cacheService.put(cacheKey, user);}
}// 用戶更新請求DTO
public class UserUpdateRequest {private String email;private String password;// Getter和Setterpublic String getEmail() { return email; }public void setEmail(String email) { this.email = email; }public String getPassword() { return password; }public void setPassword(String password) { this.password = password; }
}

9.3 完整的控制器

@RestController
@RequestMapping("/api/v1/users")
@Validated
public class EnhancedUserController {private final EnhancedUserService userService;public EnhancedUserController(EnhancedUserService userService) {this.userService = userService;}@PostMapping("/register")public ResponseEntity<ApiResponse<User>> registerUser(@Valid @RequestBody UserRegistrationRequest request) {try {User user = userService.registerUser(request);ApiResponse<User> response = new ApiResponse<>();response.setSuccess(true);response.setMessage("用戶注冊成功");response.setData(user);return ResponseEntity.ok(response);} catch (Exception e) {ApiResponse<User> response = new ApiResponse<>();response.setSuccess(false);response.setMessage("注冊失敗: " + e.getMessage());return ResponseEntity.badRequest().body(response);}}@PostMapping("/login")public ResponseEntity<ApiResponse<String>> login(@RequestBody LoginRequest request) {boolean authenticated = userService.authenticateUser(request.getUsername(), request.getPassword());ApiResponse<String> response = new ApiResponse<>();if (authenticated) {response.setSuccess(true);response.setMessage("登錄成功");response.setData("authentication-token-here");return ResponseEntity.ok(response);} else {response.setSuccess(false);response.setMessage("用戶名或密碼錯誤");return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(response);}}@GetMapping("/{id}")public ResponseEntity<ApiResponse<User>> getUser(@PathVariable Long id) {try {User user = userService.getUserById(id);ApiResponse<User> response = new ApiResponse<>();response.setSuccess(true);response.setData(user);return ResponseEntity.ok(response);} catch (Exception e) {ApiResponse<User> response = new ApiResponse<>();response.setSuccess(false);response.setMessage(e.getMessage());return ResponseEntity.notFound().build();}}@GetMappingpublic ResponseEntity<ApiResponse<List<User>>> getAllUsers() {List<User> users = userService.getAllUsers();ApiResponse<List<User>> response = new ApiResponse<>();response.setSuccess(true);response.setMessage("獲取用戶列表成功");response.setData(users);return ResponseEntity.ok(response);}@PutMapping("/{id}")public ResponseEntity<ApiResponse<User>> updateUser(@PathVariable Long id,@RequestBody UserUpdateRequest request) {try {User user = userService.updateUser(id, request);ApiResponse<User> response = new ApiResponse<>();response.setSuccess(true);response.setMessage("用戶信息更新成功");response.setData(user);return ResponseEntity.ok(response);} catch (Exception e) {ApiResponse<User> response = new ApiResponse<>();response.setSuccess(false);response.setMessage("更新失敗: " + e.getMessage());return ResponseEntity.badRequest().body(response);}}
}// 通用API響應類
public class ApiResponse<T> {private boolean success;private String message;private T data;private LocalDateTime timestamp;public ApiResponse() {this.timestamp = LocalDateTime.now();}// Getter和Setter方法public boolean isSuccess() { return success; }public void setSuccess(boolean success) { this.success = success; }public String getMessage() { return message; }public void setMessage(String message) { this.message = message; }public T getData() { return data; }public void setData(T data) { this.data = data; }public LocalDateTime getTimestamp() { return timestamp; }public void setTimestamp(LocalDateTime timestamp) { this.timestamp = timestamp; }
}

10. 常見問題與最佳實踐

10.1 避免循環依賴

// ? 錯誤示例:循環依賴
@Service
public class ServiceA {@Autowiredprivate ServiceB serviceB;  // ServiceA依賴ServiceB
}@Service
public class ServiceB {@Autowiredprivate ServiceA serviceA;  // ServiceB依賴ServiceA,形成循環
}// ? 解決方案1:使用@Lazy
@Service
public class ServiceA {private final ServiceB serviceB;public ServiceA(@Lazy ServiceB serviceB) {  // 懶加載打破循環this.serviceB = serviceB;}
}// ? 解決方案2:重新設計,引入第三個服務
@Service
public class SharedService {// 共同需要的功能
}@Service
public class ServiceA {@Autowiredprivate SharedService sharedService;
}@Service
public class ServiceB {@Autowiredprivate SharedService sharedService;
}

10.2 合理使用Bean作用域

// ? 正確:無狀態的服務使用單例
@Service  // 默認單例,適合無狀態的服務
public class UserService {// 無實例變量,線程安全public User findById(Long id) {// 查找邏輯}
}// ? 錯誤:有狀態的Bean使用單例會有線程安全問題
@Service  // 單例,但有狀態,不線程安全
public class StatefulService {private int counter = 0;  // 實例變量,多線程訪問會有問題public int increment() {return ++counter;  // 線程不安全}
}// ? 正確:有狀態的Bean使用原型作用域
@Service
@Scope("prototype")  // 每次使用都創建新實例
public class StatefulService {private int counter = 0;  // 每個實例都有自己的counterpublic int increment() {return ++counter;  // 線程安全}
}

10.3 優先使用構造器注入

// ? 推薦:構造器注入
@Service
public class UserService {private final UserRepository userRepository;private final EmailService emailService;// 構造器注入,依賴明確,便于測試public UserService(UserRepository userRepository, EmailService emailService) {this.userRepository = userRepository;this.emailService = emailService;}
}// ? 不推薦:字段注入
@Service
public class UserService {@Autowiredprivate UserRepository userRepository;  // 字段注入,難以測試@Autowiredprivate EmailService emailService;
}

10.4 Bean命名規范

// ? 好的Bean命名
@Service("userService")           // 清晰的服務名稱
@Repository("userRepository")     // 清晰的倉庫名稱
@Component("emailSender")         // 清晰的組件名稱// ? 不好的Bean命名
@Service("us")                    // 太簡短,不清晰
@Repository("repo1")              // 沒有意義的名稱
@Component("component")           // 通用名稱,不具體

11. 總結

11.1 Bean的核心概念回顧

  1. Bean是什么:Spring容器管理的Java對象
  2. 為什么使用Bean:自動化對象管理,降低耦合度
  3. 如何聲明Bean:@Component系列注解、@Bean方法
  4. 依賴注入:自動裝配Bean之間的依賴關系
  5. 作用域:控制Bean的生命周期和實例化策略
  6. 生命周期:從創建到銷毀的完整過程

11.2 最佳實踐總結

  1. 優先使用構造器注入,保證依賴的不可變性
  2. 合理選擇Bean作用域,無狀態用單例,有狀態用原型
  3. 避免循環依賴,通過重新設計或使用@Lazy解決
  4. 使用有意義的Bean名稱,提高代碼可讀性
  5. 合理使用生命周期回調,管理資源的創建和釋放
  6. 條件化創建Bean,根據環境和配置靈活選擇

11.3 學習建議

  1. 從簡單開始:先掌握@Service、@Repository、@Controller
  2. 理解依賴注入:搞清楚構造器注入、Setter注入的區別
  3. 實踐作用域:創建不同作用域的Bean,觀察行為差異
  4. 學習生命周期:使用@PostConstruct和@PreDestroy管理資源
  5. 探索高級特性:條件化Bean、FactoryBean、懶加載等
  6. 項目實踐:在實際項目中應用這些概念

通過深入理解和實踐Spring Boot的Bean機制,您將能夠構建出結構清晰、易于維護的應用程序!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/88179.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/88179.shtml
英文地址,請注明出處:http://en.pswp.cn/web/88179.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

cherryStudio electron因為環境問題無法安裝解決方法或打包失敗解決方法

$env:ELECTRON_MIRROR"https://npmmirror.com/mirrors/electron/"; $env:ELECTRON_CUSTOM_DIR"{{ version }}"; yarn install1. 上面是關于electron安裝失敗的解決方法. 也可以通過到git上下面包,解壓后,放到對應的目錄下面,并把里面的build文件夾刪除, b…

微服務架構中數據一致性保證機制深度解析

在微服務架構中&#xff0c;數據一致性是分布式系統設計的核心挑戰。由于服務拆分后數據自治&#xff08;每個服務獨立數據庫&#xff09;&#xff0c;跨服務操作的一致性保障需突破傳統單體事務的局限。本文從一致性模型、核心解決方案、技術實現及面試高頻問題四個維度&#…

【Gin】HTTP 請求調試器

文章目錄 項目概述代碼功能詳解1. 導入必要的包2. 主函數和路由設置3. 請求信息捕獲4. 請求參數和頭信息5. 請求體處理5.1 JSON 數據處理5.2 表單數據處理5.3 Multipart 表單數據處理5.4 其他類型數據處理6. 構造響應對象7. 返回 JSON 響應功能特點使用場景完整代碼項目概述 這…

物聯網(IoT)領域的協議

物聯網&#xff08;IoT&#xff09;領域的通信協議種類繁多&#xff0c;不同協議適用于不同的應用場景&#xff08;如低功耗設備、工業自動化、家庭智能設備等&#xff09;。以下是主要物聯網協議的分類及詳細解釋&#xff1a;一、物聯網協議分類物聯網協議通常分為兩大類&…

專題一_雙指針_四數之和

一&#xff1a;題目解析 題目鏈接&#xff1a;18. 四數之和 - 力扣&#xff08;LeetCode&#xff09; 注&#xff1a;本題是在上題的基礎上講解的&#xff1a;專題一_雙指針_三數之和-CSDN博客 解析&#xff1a;和三數之區別在于找四元組和為targe的數字 而不是0 二&#xff1a…

Spring Boot多數據源配置詳解

Spring Boot多數據源配置詳解 在實際企業開發中&#xff0c;隨著業務復雜度提升&#xff0c;單一數據源已無法滿足所有場景需求。比如&#xff1a;讀寫分離、分庫分表、數據遷移、微服務整合等&#xff0c;這時就需要用到多數據源配置。本文將從原理、配置、常見問題和最佳實踐…

項目進度嚴重依賴關鍵人,如何分散風險

項目進度嚴重依賴關鍵人的風險&#xff0c;可以通過建立知識共享機制、強化團隊協作模式、實施交叉培訓和培養后備人才、優化流程標準化等措施有效分散。其中&#xff0c;實施交叉培訓和培養后備人才尤為重要&#xff0c;通過培養多個成員具備相似的關鍵技能&#xff0c;能夠迅…

【RK3568+PG2L50H開發板實驗例程】FPGA部分 | 以太網傳輸實驗例程

本原創文章由深圳市小眼睛科技有限公司創作&#xff0c;版權歸本公司所有&#xff0c;如需轉載&#xff0c;需授權并注明出處&#xff08;www.meyesemi.com)1.實驗簡介實驗目的&#xff1a;完成 DDR3 的讀寫測試。實驗環境&#xff1a;Window11 PDS2022.2-SP6.4芯片型號&#x…

《每日AI-人工智能-編程日報》--2025年7月9日

介紹:AI 方面1. Manus 通用智能體初成型&#xff0c;開啟 AIAgent 新時代?中泰證券發布研報稱&#xff0c;首款通用型 AI 智能體 Manus 已問世&#xff0c;能夠將復雜任務拆解為可執行的步驟鏈&#xff0c;并在虛擬環境中靈活調用工具&#xff0c;標志著 AI 從 “Reasoner” 走…

MyBatis之數據操作增刪改查基礎全解

目錄 1. ?MyBatis添加數據 1.1. 持久層接口添加方法 1.2. 映射文件添加標簽 1.3. 編寫測試方法 2. ??MyBatis修改數據 2.1. 代碼的優化 2.2. 持久層接口添加方法 2.3. 映射文件添加標簽 2.4. 編寫測試方法 3. &#x1f5d1;?MyBatis刪除數據與根據Id查詢 3.1. 刪…

kbmMemTable Pro 7.82 Delphi 11 源代碼

kbmMemTable Pro 7.82 Delphi 11 源代碼KbmMemTable 是一個用于在 Win 32/64、Mac OS、Android 和 iOS 32/64 應用程序中存儲臨時數據的組件&#xff0c;這些應用程序可以使用 RAD Studio、Delphi、C Builder 或 FPC 等編程語言創建&#xff0c;同時您還可以高速訪問存儲在數據…

LeetCode Hot 100 除自身以外數組的乘積

給你一個整數數組 nums&#xff0c;返回 數組 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘積 。題目數據 保證 數組 nums之中任意元素的全部前綴元素和后綴的乘積都在 32 位 整數范圍內。請 不要使用除法&#xff0c;且在 O(n) 時間復雜度內…

VC Code--常用的配置

原文網址&#xff1a;VC Code--常用的配置-CSDN博客 簡介 本文介紹VC Cod常用的配置。 1.字體大小 整體字體大小 左下角齒輪> Settings> Windows> Window: Zoom Level> 改為&#xff1a;2 編輯器字體大小&#xff08;如果調整了整體字體大小&#xff0c;此處…

大模型驅動的智能體:從GPT-4到o1的能力躍升

大模型驅動的智能體&#xff1a;從GPT-4到o1的能力躍升 &#x1f31f; 嗨&#xff0c;我是IRpickstars&#xff01; &#x1f30c; 總有一行代碼&#xff0c;能點亮萬千星辰。 &#x1f50d; 在技術的宇宙中&#xff0c;我愿做永不停歇的探索者。 ? 用代碼丈量世界&#xf…

200nl2sql

‘train_runtime’: 1375.1089, ‘train_samples_per_second’: 0.025, ‘train_steps_per_second’: 0.007, ‘train_loss’: 0.0, ‘num_tokens’: 115914.0, ‘completions/mean_length’: 76.4125, ‘completions/min_length’: 27.8, ‘completions/max_length’: 151.2, …

Transformer、BERT、GPT以及Embedding之間的關系

1. Transformer架構的兩大方向 Transformer分為兩大類應用&#xff0c;但劃分標準不是"分類vs生成"&#xff0c;而是編碼方式&#xff1a; Encoder架構&#xff08;代表&#xff1a;BERT&#xff09;&#xff1a; 使用Transformer的??編碼器??&#xff08;Encode…

ARM匯編編程(AArch64架構)課程 - 第7章:SIMD與浮點運算

目錄1. NEON寄存器關鍵特性數據排列示例2. 浮點指令2.1 FMUL指令2.2 FADD指令2.3 FCMP指令1. NEON寄存器 AArch64架構提供32個128位NEON向量寄存器&#xff08;V0-V31&#xff09;&#xff0c;支持SIMD并行計算 關鍵特性 寄存器類型數量位寬數據視圖Q寄存器32128bQ0-Q31D寄存…

Word2Vec模型詳解:CBOW與Skip-gram

Word2Vec模型詳解&#xff1a;CBOW與Skip-gram 目錄 模型概述理論基礎CBOW模型詳解Skip-gram模型詳解模型對比代碼實現詳解訓練過程分析應用場景實驗結果總結 模型概述 Word2Vec是一種用于生成詞向量的神經網絡模型&#xff0c;由Google在2013年提出。它包含兩種主要架構&am…

跨服務sqlplus連接oracle數據庫

背景&#xff1a;ogg程序同步數據。 目標庫&#xff1a;客戶oracle數據庫11.0.2.4.0&#xff0c;也就是11g的數據庫。源庫&#xff1a;業務組搭建的19c數據庫&#xff0c;剛安裝的oracle數據庫。ogg在源庫和目標庫系統都部署好了并且也可以通信。在目標庫系統使用sqlplus測試連…

虛擬機安裝與使用vim編輯器簡單使用

文章目錄1.VMware17許可證2.ubuntu虛擬機的顯示屏幕太小3.vmware 17 無法安裝 vmware tools4.buntu常用快捷鍵與命令5.vim文本編輯器參考資料&#xff1a;1.VMware17許可證 JU090-6039P-08409-8J0QH-2YR7F&#xff08;親測2025/7/8有效&#xff09; 2.ubuntu虛擬機的顯示屏幕…