首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Spring 註解配置全解析:@Autowired、@Resource、@Component 掃描與生命週期

     編輯:Java 相關知識

啟用註解支持:必要前置配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="https://www.springframework.org/schema/beans"
       xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="https://www.springframework.org/schema/context"
       xsi:schemaLocation="
           https://www.springframework.org/schema/beans
           https://www.springframework.org/schema/beans/spring-beans.xsd
           https://www.springframework.org/schema/context
           https://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 核心:啟用註解處理器 -->
    <context:annotation-config/>

    <!-- 掃描組件 (替代 XML 定義 bean) -->
    <context:component-scan base-package="com.example.service, com.example.dao"/>

</beans>

關鍵區別:annotation-config 僅註冊後置處理器 (處理 @Autowired 等);component-scan 包含前者並額外掃描 @Component 類自動註冊 Bean。

核心依賴注入註解對比

1. @Autowired (Spring 專有,按類型裝配)

@Service
public class UserService {
    // 構造器注入 (推薦,不可變、可測試)
    private final UserRepository userRepository;
    @Autowired // 單構造器可省略
    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    // Setter 注入 (可選依賴)
    private CacheManager cacheManager;
    @Autowired(required = false)
    public void setCacheManager(CacheManager cacheManager) {
        this.cacheManager = cacheManager;
    }

    // 字段注入 (不推薦,難測試、循環依賴隱患)
    @Autowired
    private EmailService emailService;
}
  • 默認 required=true,找不到 Bean 拋異常
  • 多個同類型候選時拋 NoUniqueBeanDefinitionException,需配合 @Qualifier

2. @Qualifier (消除歧義)

@Autowired
@Qualifier("redisCacheManager") // 指定 Bean 名稱
private CacheManager cacheManager;

// 或在目標 Bean 上標識
@Primary // 優先選擇
@Bean
public CacheManager redisCacheManager() { ... }

@Bean
public CacheManager ehCacheManager() { ... }

3. @Resource (JSR-250 標準,按名稱裝配)

@Resource(name = "userRepository") // 指定名稱
private UserRepository userRepository;

// 未指定 name 時:優先按字段名匹配 Bean 名稱,退回到類型匹配
@Resource
private UserRepository userRepository; // 查找名為 "userRepository" 的 Bean
特性@Autowired@Resource
來源Spring 專有JSR-250 (Java EE 標準)
匹配策略按類型 → @Qualifier 按名按名稱 (@Resource.name/字段名) → 類型
構造器注入支援不支援 (僅字段/Setter)
可選依賴@Autowired(required=false)無直接對應

4. @Inject (JSR-330,類似 @Autowired)

@Inject
private UserRepository userRepository; // 需引入 javax.inject:javax.inject:1

行為與 @Autowired 一致,但無 required 屬性,配合 @Named 指定名稱。

組件掃描與 Bean 定義註解

註解用途層級約定
@Component通用組件無特定層
@RepositoryDAO 層自動轉換數據訪問異常 (PersistenceExceptionTranslationPostProcessor)
@Service業務邏輯層語義標識,可切面增強事務
@ControllerWeb 控制器Spring MVC 識別,請求映射
@Configuration配置類替代 XML,定義 @Bean 方法
@Bean方法級 Bean 定義方法名 = Bean 名,返回值 = Bean 實例
@Configuration
@ComponentScan(basePackages = "com.example", 
               excludeFilters = @Filter(type = FilterType.ANNOTATION, classes = Controller.class))
public class AppConfig {
    @Bean
    @Primary
    public DataSource dataSource() { ... }
    
    @Bean
    @Scope("prototype")
    public MyPrototypeBean prototypeBean() { return new MyPrototypeBean(); }
}

Spring Bean 生命週期與回調機制

四種生命週期管理方式

@Component
public class LifecycleBean implements InitializingBean, DisposableBean {

    @PostConstruct // JSR-250,初始化後調用 (推薦)
    public void init() { System.out.println("@PostConstruct init"); }

    @PreDestroy // JSR-250,銷毀前調用 (推薦)
    public void destroy() { System.out.println("@PreDestroy destroy"); }

    // InitializingBean 接口方法
    @Override
    public void afterPropertiesSet() { System.out.println("afterPropertiesSet"); }

    // DisposableBean 接口方法
    @Override
    public void destroy() { System.out.println("DisposableBean.destroy"); }
}

// XML 配置方式 (無侵入代碼)
<bean id="xmlBean" class="com.example.XmlBean" 
      init-method="customInit" destroy-method="customDestroy"/>

生命週期執行順序

  1. 構造器實例化
  2. 依賴注入 (Setter/字段/構造器)
  3. @PostConstruct / afterPropertiesSet() / init-method
  4. Bean 就緒,可被使用
  5. 容器關閉觸發銷毀
  6. @PreDestroy / destroy() / destroy-method

進階場景:條件裝配與動態註冊

@Conditional 系列

@Bean
@ConditionalOnProperty(name = "app.cache.enabled", havingValue = "true")
public CacheManager cacheManager() { ... }

@Bean
@ConditionalOnMissingBean(RedisTemplate.class)
public RedisTemplate fallbackRedisTemplate() { ... }

@Bean
@ConditionalOnClass(name = "org.springframework.data.redis.core.RedisTemplate")
public RedisCacheManager redisCacheManager() { ... }

@Import 動態註冊

@Configuration
@Import({MyImportSelector.class, MyImportBeanDefinitionRegistrar.class})
public class DynamicConfig { }

// 實現 ImportSelector:根據條件返回配置類名數組
// 實現 ImportBeanDefinitionRegistrar:程序化註冊 BeanDefinition

最佳實踐總結

  1. 優先構造器注入:final 字段、不可變、易測試、避免循環依賴
  2. @Autowired + @Qualifier/@Primary 解決多實現歧義
  3. @ComponentScan 精確控制掃描範圍:排除測試類、配置類衝突
  4. 生命週期用 @PostConstruct/@PreDestroy:標準、無侵入、異常安全
  5. 避免循環依賴:重構設計、@Lazy 延迟注入、Setter 注入打破循環
  6. 配置類集中管理第三方 Bean:DataSource、RedisTemplate、ThreadPool 等

註解配置讓 Spring 從「XML 地獄」解脫,但濫用會導致隱式依賴難追踪。原則:業務代碼用註解,基礎設施用配置類,測試用 XML/動態註冊覆蓋。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved