SpringBoot 最常用的50個注解,都是干貨!
兄弟們!今天咱不整那些虛頭巴腦的概念,直接上硬菜 ——SpringBoot 最常用的 50 個注解,全是干活,看完保準(zhǔn)你開發(fā)效率能提一大截,再也不用對著代碼撓頭想 “這個場景該用啥注解來著”。
咱都知道,SpringBoot 的核心就是 “簡化配置”,而注解就是實現(xiàn)這事兒的 “大功臣”。以前用 Spring 的時候,寫 XML 配置能寫到手軟,現(xiàn)在一個注解就能搞定,簡直是開發(fā)者的 “救星”。但注解多了也容易懵,比如 @Controller 和 @RestController 到底啥區(qū)別?@Autowired 和 @Resource 該咋選?別慌,今天我就用最接地氣的話,把這些注解一個個掰扯明白,連新手都能看得明明白白。
一、SpringBoot 核心注解(3 個)—— 啟動項目全靠它們
這仨注解就像項目的 “發(fā)動機”,沒有它們,SpringBoot 項目都沒法啟動,屬于 “必背必用” 級別的。
1. @SpringBootApplication
作用:這是個 “大雜燴” 注解,把三個關(guān)鍵注解打包了 ——@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan。加在啟動類上,SpringBoot 就知道 “哦,這是入口,我要從這開始加載配置、掃描組件”。
使用場景:唯一的使用地方就是項目的啟動類,沒啥可挑的,寫啟動類就必須加它。
代碼示例:
// 這就是咱項目的啟動類,@SpringBootApplication一貼,萬事俱備
@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        // 啟動SpringBoot項目的固定寫法,記不住就復(fù)制粘貼
        SpringApplication.run(DemoApplication.class, args);
    }
}小提醒:別瞎折騰,啟動類最好放在項目包的最外層,比如你的項目包是 com.demo,啟動類就放這下面,這樣 @ComponentScan 才能掃到里面所有的組件,不然還得手動配置掃描路徑,多此一舉。
2. @SpringBootConfiguration
作用:其實就是個 “偽裝版” 的 @Configuration,告訴 Spring“這個類是配置類,里面可能有 @Bean 定義的 bean”。因為 @SpringBootApplication 已經(jīng)包含它了,所以平時很少單獨寫,但得知道它的存在。
使用場景:一般不單獨用,除非你想自定義一個額外的配置類,并且不想用 @Configuration(不過沒必要,直接用 @Configuration 更直觀)。
代碼示例:
// 單獨用的情況很少見,一般這么寫
@SpringBootConfiguration
public class CustomConfig {
    // 里面可以定義@Bean
    @Bean
    public UserService userService() {
        return new UserService();
    }
}3. @EnableAutoConfiguration
作用:SpringBoot 的 “自動配置” 核心就在這!它會根據(jù)你項目里引入的依賴,自動幫你配置一些 bean。比如你引入了 spring-boot-starter-web 依賴,它就自動配置 DispatcherServlet、Tomcat 這些 Web 相關(guān)的東西,不用你手動寫配置。
使用場景:同樣被 @SpringBootApplication 包含了,不用單獨加。但如果想排除某個自動配置(比如不想用 SpringBoot 自帶的數(shù)據(jù)源配置),可以用它的 exclude 屬性。
代碼示例:
// 比如不想用默認(rèn)的數(shù)據(jù)源自動配置,就這么排除
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}小提醒:自動配置雖然方便,但有時候會 “幫倒忙”,比如你自己配置了數(shù)據(jù)源,它還瞎自動配置,這時候排除就很有用。
二、配置相關(guān)注解(7 個)—— 管理配置不頭疼
項目里肯定有各種配置,比如數(shù)據(jù)庫地址、端口號、自定義參數(shù),這些注解能幫你輕松搞定配置注入,不用再寫死在代碼里。
4. @Configuration
作用:標(biāo)記一個類是 “配置類”,相當(dāng)于以前的 XML 配置文件。里面可以用 @Bean 注解定義 bean,讓 Spring 管理這些 bean 的創(chuàng)建和生命周期。
使用場景:需要自定義 bean 的時候就用它,比如配置 RedisTemplate、RestTemplate 這些第三方組件的 bean。
代碼示例:
// 配置RestTemplate的例子,這是咱開發(fā)中經(jīng)常寫的
@Configuration
public class RestTemplateConfig {
    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder builder) {
        // 可以在這里配置超時時間、攔截器等
        return builder
                .setConnectTimeout(Duration.ofSeconds(5))
                .setReadTimeout(Duration.ofSeconds(5))
                .build();
    }
}小提醒:配置類里的 @Bean 方法,參數(shù)如果是 Spring 管理的 bean,Spring 會自動注入,比如上面的 RestTemplateBuilder,不用你手動 new。
5. @Bean
作用:放在配置類的方法上,告訴 Spring“這個方法返回的對象,你幫我管理起來,以后要用的時候直接拿”。相當(dāng)于以前 XML 里的標(biāo)簽。
使用場景:自定義 bean 的時候,比如上面配置 RestTemplate,還有配置線程池、數(shù)據(jù)源這些。
代碼示例:
@Configuration
public class ThreadPoolConfig {
    // 定義一個線程池bean,名字就是方法名threadPoolTaskExecutor
    @Bean
    public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5); // 核心線程數(shù)
        executor.setMaxPoolSize(10); // 最大線程數(shù)
        executor.setQueueCapacity(20); // 隊列容量
        executor.initialize();
        return executor;
    }
}6. @Value
作用:從配置文件(比如 application.yml 或 application.properties)里讀取單個配置值,注入到變量里。支持字符串、數(shù)字、布爾值這些類型,還能寫點簡單的表達(dá)式。
使用場景:需要單個配置值的時候,比如讀取端口號、數(shù)據(jù)庫用戶名。
代碼示例:
# application.yml里的配置
server:
  port: 8080
custom:
  name: 張三
  age: 25
  isVip: true
@RestController
public class ConfigController {
    // 讀取server.port
    @Value("${server.port}")
    private Integer port;
    // 讀取custom.name,還能加默認(rèn)值,要是配置里沒這個key,就用默認(rèn)值“李四”
    @Value("${custom.name:李四}")
    private String name;
    // 讀取布爾值
    @Value("${custom.isVip}")
    private Boolean isVip;
    @GetMapping("/config")
    public String getConfig() {
        return "端口:" + port + ",姓名:" + name + ",是否VIP:" + isVip;
    }
}小提醒:@Value 只能讀單個值,要是配置項多了,一個個寫 @Value 就太麻煩了,這時候就該下面的 @ConfigurationProperties 出場了。
7. @ConfigurationProperties
作用:批量讀取配置文件里的屬性,綁定到一個實體類上。比 @Value 方便多了,支持嵌套屬性,還能做數(shù)據(jù)校驗。
使用場景:配置項比較多的時候,比如數(shù)據(jù)庫配置(url、username、password)、第三方接口配置(url、appKey、appSecret)。
代碼示例:
# application.yml里的數(shù)據(jù)庫配置
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/demo?useSSL=false
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver
# 自定義的第三方接口配置
third:
  api:
    url: https://api.xxx.com
    appKey: abc123
    appSecret: xyz789
    timeout: 5000
// 數(shù)據(jù)庫配置實體類
@ConfigurationProperties(prefix = "spring.datasource") // prefix指定配置的前綴
@Component // 要讓Spring掃描到這個類,不然沒法綁定
public class DataSourceProperties {
    private String url;
    private String username;
    private String password;
    private String driverClassName; // 注意:配置里是driver-class-name,這里用駝峰命名也能對應(yīng)上
    // getters和setters必須有,不然沒法注入值
    public String getUrl() { return url; }
    public void setUrl(String url) { this.url = url; }
    // 其他getter和setter省略...
}
// 第三方接口配置實體類,還能加數(shù)據(jù)校驗
@ConfigurationProperties(prefix = "third.api")
@Component
@Validated // 開啟數(shù)據(jù)校驗
public class ThirdApiProperties {
    @NotBlank(message = "接口URL不能為空") // 校驗url不能為null或空字符串
    private String url;
    @NotBlank(message = "appKey不能為空")
    private String appKey;
    @NotBlank(message = "appSecret不能為空")
    private String appSecret;
    @Min(value = 1000, message = "超時時間不能小于1000毫秒") // 校驗timeout至少1000
    private Integer timeout;
    // getters和setters省略...
}小提醒:用 @ConfigurationProperties 記得加 @Component(或者在配置類里用 @EnableConfigurationProperties 注解),不然 Spring 找不到這個類,沒法綁定配置。另外,getter 和 setter 必須寫,不然值注入不進去。
8. @PropertySource
作用:指定讀取自定義的配置文件,比如不想把所有配置都放 application.yml 里,想單獨放一個 custom.properties,就用它。
使用場景:配置文件拆分的時候,比如把自定義配置放 custom.properties,把日志配置放 log.properties。
代碼示例:
# 自定義的custom.properties文件,放在resources目錄下
custom.phone=13800138000
custom.email=zhangsan@xxx.com
@Component
@PropertySource(value = "classpath:custom.properties", encoding = "UTF-8") // 指定文件路徑和編碼
@ConfigurationProperties(prefix = "custom")
public class CustomProperties {
    private String phone;
    private String email;
    // getters和setters省略...
}小提醒:如果是.yml 格式的自定義配置文件,@PropertySource 默認(rèn)不支持,得額外加依賴,所以一般自定義配置用.properties 更方便,或者直接把.yml 配置文件放 application.yml 里用 profiles 拆分。
9. @Profile
作用:指定配置類或 bean 在哪個環(huán)境下生效。比如開發(fā)環(huán)境用 dev,測試環(huán)境用 test,生產(chǎn)環(huán)境用 prod,用 @Profile 就能區(qū)分。
使用場景:多環(huán)境配置的時候,比如開發(fā)環(huán)境用本地數(shù)據(jù)庫,生產(chǎn)環(huán)境用線上數(shù)據(jù)庫。
代碼示例:
// 開發(fā)環(huán)境的數(shù)據(jù)源配置
@Configuration
@Profile("dev") // 只有當(dāng)激活dev環(huán)境時,這個配置才生效
public class DevDataSourceConfig {
    @Bean
    public DataSource dataSource() {
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl("jdbc:mysql://localhost:3306/dev_db?useSSL=false");
        config.setUsername("dev_root");
        config.setPassword("dev_123456");
        return new HikariDataSource(config);
    }
}// 生產(chǎn)環(huán)境的數(shù)據(jù)源配置
@Configuration
@Profile("prod") // 激活prod環(huán)境時生效
public class ProdDataSourceConfig {
    @Bean
    public DataSource dataSource() {
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl("jdbc:mysql://192.168.1.100:3306/prod_db?useSSL=true");
        config.setUsername("prod_root");
        config.setPassword("prod_xxxxxx");
        return new HikariDataSource(config);
    }
}激活環(huán)境的方式:在 application.yml 里加spring.profiles.active=dev,或者啟動項目時加參數(shù)--spring.profiles.active=prod。
10. @Conditional
作用:根據(jù)條件判斷配置類或 bean 是否生效。比如 “只有當(dāng)某個類存在時,這個 bean 才創(chuàng)建”“只有當(dāng)某個配置項為 true 時,這個配置類才生效”。它是個父注解,SpringBoot 提供了很多子注解,比直接用 @Conditional 方便。
常用子注解:
- @ConditionalOnClass:某個類存在時生效
 - @ConditionalOnMissingClass:某個類不存在時生效
 - @ConditionalOnBean:某個 bean 存在時生效
 - @ConditionalOnMissingBean:某個 bean 不存在時生效
 - @ConditionalOnProperty:某個配置項滿足條件時生效
 
使用場景:按需創(chuàng)建 bean,比如 “如果項目里引入了 Redis 依賴,就配置 RedisTemplate;如果沒引入,就不配置”。
代碼示例:
@Configuration
publicclass RedisConfig {
    // 只有當(dāng)RedisTemplate這個類不存在時,才創(chuàng)建這個自定義的RedisTemplate bean
    @Bean
    @ConditionalOnMissingBean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);
        // 配置序列化方式
        Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class);
        template.setValueSerializer(serializer);
        template.setKeySerializer(new StringRedisSerializer());
        return template;
    }
}三、Web 開發(fā)相關(guān)注解(12 個)—— 寫接口全靠它們
Web 開發(fā)是 SpringBoot 最常用的場景,這些注解幫你快速寫 Controller、接收參數(shù)、處理響應(yīng),不用再像以前那樣配置 Servlet 了。
11. @Controller
作用:標(biāo)記一個類是 “控制器”,處理用戶的 HTTP 請求。一般和 @ResponseBody 一起用,返回 JSON 數(shù)據(jù);如果是返回頁面(比如 Thymeleaf),就不用加 @ResponseBody。
使用場景:所有處理 HTTP 請求的類都要加,比如用戶管理 Controller、訂單 Controller。
12. @RestController
作用:@Controller + @ResponseBody 的組合體!加了這個注解,類里所有方法返回的都是 JSON 數(shù)據(jù),不用再每個方法都加 @ResponseBody,省事兒。
使用場景:寫 API 接口的時候(比如前后端分離項目),幾乎全用這個,不用考慮返回頁面。
代碼示例:
// 前后端分離項目的Controller,直接用@RestController
@RestController
@RequestMapping("/user") // 類上的請求路徑前綴,所有方法都帶/user
publicclass UserController {
    // 處理GET請求,路徑是/user/{id},{id}是路徑參數(shù)
    @GetMapping("/{id}")
    public ResponseEntity<User> getUserById(@PathVariable Long id) {
        // 模擬從數(shù)據(jù)庫查數(shù)據(jù)
        User user = new User(id, "張三", 25);
        return ResponseEntity.ok(user); // 返回200狀態(tài)碼和用戶數(shù)據(jù)
    }
    // 處理POST請求,路徑是/user,請求體是JSON格式的User對象
    @PostMapping
    public ResponseEntity<String> addUser(@RequestBody User user) {
        // 模擬保存用戶
        return ResponseEntity.status(HttpStatus.CREATED).body("用戶添加成功:" + user.getName());
    }
}小提醒:如果你的項目是傳統(tǒng)的 JSP/Thymeleaf 項目,需要返回頁面,就用 @Controller,然后在方法上用 @ResponseBody 返回 JSON,不用 @ResponseBody 的方法返回頁面路徑。
13. @RequestMapping
作用:指定 Controller 類或方法處理的 HTTP 請求路徑和請求方式(GET、POST、PUT、DELETE 等)??梢约釉陬惿希ㄖ付ㄇ熬Y),也可以加在方法上(指定具體路徑)。
使用場景:所有需要指定請求路徑的方法都要加,不過現(xiàn)在更多用下面的 @GetMapping、@PostMapping 這些更具體的注解。
代碼示例:
@RestController
@RequestMapping("/order") // 類上的前綴,所有方法路徑都帶/order
publicclass OrderController {
    // 處理GET請求,路徑是/order,相當(dāng)于@RequestMapping(value = "/", method = RequestMethod.GET)
    @RequestMapping(value = "/", method = RequestMethod.GET)
    public List<Order> getOrderList() {
        // 模擬查訂單列表
        List<Order> orders = Arrays.asList(
                new Order(1L, "訂單1", 100.0),
                new Order(2L, "訂單2", 200.0)
        );
        return orders;
    }
    // 處理POST請求,路徑是/order,相當(dāng)于@RequestMapping(value = "/", method = RequestMethod.POST)
    @RequestMapping(value = "/", method = RequestMethod.POST)
    public String createOrder() {
        return"訂單創(chuàng)建成功";
    }
}14. @GetMapping
作用:專門處理 GET 請求的注解,相當(dāng)于 @RequestMapping (method = RequestMethod.GET)。比 @RequestMapping 更簡潔,一看就知道是處理 GET 請求的。
使用場景:查詢數(shù)據(jù)的時候,比如查用戶、查訂單、查列表。
15. @PostMapping
作用:專門處理 POST 請求的注解,相當(dāng)于 @RequestMapping (method = RequestMethod.POST)。
使用場景:創(chuàng)建數(shù)據(jù)的時候,比如添加用戶、創(chuàng)建訂單、提交表單。
16. @PutMapping
作用:專門處理 PUT 請求的注解,相當(dāng)于 @RequestMapping (method = RequestMethod.PUT)。
使用場景:更新數(shù)據(jù)的時候,比如全量更新用戶信息(修改姓名、年齡、手機號等所有字段)。
17. @DeleteMapping
作用:專門處理 DELETE 請求的注解,相當(dāng)于 @RequestMapping (method = RequestMethod.DELETE)。
使用場景:刪除數(shù)據(jù)的時候,比如刪除用戶、刪除訂單。
代碼示例(@PutMapping 和 @DeleteMapping):
@RestController
@RequestMapping("/user")
publicclass UserController {
    // 處理PUT請求,路徑是/user/{id},全量更新用戶
    @PutMapping("/{id}")
    publicString updateUser(@PathVariable Long id, @RequestBody User user) {
        // 模擬更新,id是路徑參數(shù),user是請求體里的更新數(shù)據(jù)
        return"用戶" + id + "更新成功,新信息:" + user.getName();
    }
    // 處理DELETE請求,路徑是/user/{id},刪除用戶
    @DeleteMapping("/{id}")
    publicString deleteUser(@PathVariable Long id) {
        // 模擬刪除
        return"用戶" + id + "刪除成功";
    }
}18. @PathVariable
作用:獲取 URL 路徑里的參數(shù),比如路徑是 /user/{id},{id} 就是路徑參數(shù),用 @PathVariable 就能拿到這個 id 的值。
使用場景:路徑里帶參數(shù)的時候,比如根據(jù) id 查數(shù)據(jù)、根據(jù) id 更新 / 刪除數(shù)據(jù)。
代碼示例:
@GetMapping("/user/{id}/{name}") // 路徑里有兩個參數(shù):id和name
public String getUserInfo(
        @PathVariable Long id, // 直接拿id,參數(shù)名和路徑里的{id}一致
        @PathVariable("name") String userName // 路徑里是{name},變量名是userName,用value指定對應(yīng)關(guān)系
) {
    return "id:" + id + ",姓名:" + userName;
}小提醒:如果路徑參數(shù)是可選的,可以加 required = false,比如@PathVariable(required = false) Long id,但路徑里要寫成 /user/{id:.*}(適配空值),不然會報 404。
19. @RequestParam
作用:獲取 URL 查詢參數(shù)(就是?后面的參數(shù)),比如請求是 /user?page=1&size=10,page 和 size 就是查詢參數(shù),用 @RequestParam 就能拿到。
使用場景:分頁查詢、條件查詢的時候,比如查用戶列表,帶 page(頁碼)、size(每頁條數(shù))、keyword(關(guān)鍵詞)這些參數(shù)。
代碼示例:
// 請求路徑:/user/list?page=1&size=10&keyword=張
@GetMapping("/user/list")
public String getUserList(
        @RequestParam(defaultValue = "1") Integer page, // 默認(rèn)值1,沒傳page就用1
        @RequestParam(defaultValue = "10") Integer size, // 默認(rèn)值10
        @RequestParam(required = false) String keyword // 可選參數(shù),沒傳就是null
) {
    return "當(dāng)前頁碼:" + page + ",每頁條數(shù):" + size + ",查詢關(guān)鍵詞:" + keyword;
}小提醒:@RequestParam 的 required 默認(rèn)是 true,也就是說如果沒傳這個參數(shù),會報 400 錯誤;如果參數(shù)是可選的,一定要設(shè) required = false,或者給個默認(rèn)值(給了默認(rèn)值,required 會自動變成 false)。
20. @RequestBody
作用:獲取 HTTP 請求體里的 JSON 數(shù)據(jù),把它轉(zhuǎn)換成 Java 對象。一般和 POST、PUT 請求一起用,因為 GET 請求沒有請求體。
使用場景:提交復(fù)雜數(shù)據(jù)的時候,比如創(chuàng)建用戶需要傳姓名、年齡、手機號等多個字段,就把這些字段封裝成 JSON,放在請求體里,用 @RequestBody 接收。
代碼示例:
// 請求體是JSON:{"name":"李四","age":30,"phone":"13900139000"}
@PostMapping("/user")
publicString addUser(@RequestBody@Valid User user) { // @Valid開啟數(shù)據(jù)校驗
    return"添加用戶成功:" + user.getName() + ",手機號:" + user.getPhone();
}
// User類,加了數(shù)據(jù)校驗注解
publicclass User {
    private Long id;
    @NotBlank(message = "姓名不能為空") // 姓名不能為null或空字符串
    privateString name;
    @Min(value = 18, message = "年齡不能小于18歲") // 年齡至少18
    private Integer age;
    @Pattern(regexp = "^1[3-9]\\d{9}$", message = "手機號格式不正確") // 手機號正則校驗
    privateString phone;
    // getters和setters省略...
}小提醒:用 @RequestBody 的時候,前端傳的 JSON 字段名要和 Java 對象的屬性名一致(或者用 @JsonProperty 指定對應(yīng)關(guān)系),不然值注入不進去。另外,加上 @Valid 可以做數(shù)據(jù)校驗,不符合規(guī)則會報 400 錯誤。
21. @ResponseBody
作用:把方法的返回值轉(zhuǎn)換成 JSON(或其他格式),寫入 HTTP 響應(yīng)體里。以前用 @Controller 的時候,每個要返回 JSON 的方法都要加這個注解,現(xiàn)在用 @RestController 就不用了。
使用場景:用 @Controller 返回 JSON 數(shù)據(jù)的時候,比如傳統(tǒng)項目里既有頁面又有 API 接口的情況。
代碼示例:
// 傳統(tǒng)項目,用@Controller,有的方法返回頁面,有的方法返回JSON
@Controller
@RequestMapping("/test")
publicclass TestController {
    // 返回頁面,不用@ResponseBody,返回的是Thymeleaf模板名
    @GetMapping("/page")
    publicString getPage() {
        return"index"; // 對應(yīng)resources/templates/index.html
    }
    // 返回JSON,需要加@ResponseBody
    @GetMapping("/json")
    @ResponseBody
    public Map<String, String> getJson() {
        Map<String, String> map = new HashMap<>();
        map.put("key1", "value1");
        map.put("key2", "value2");
        return map;
    }
}22. @RequestHeader
作用:獲取 HTTP 請求頭里的信息,比如 User-Agent、Token、Content-Type 這些。
使用場景:需要驗證 Token、獲取客戶端信息的時候,比如接口鑒權(quán),前端把 Token 放在請求頭里,后端用 @RequestHeader 拿出來驗證。
代碼示例:
@GetMapping("/header")
public String getHeader(
        @RequestHeader("User-Agent") String userAgent, // 獲取User-Agent(客戶端信息)
        @RequestHeader(value = "Token", required = false) String token // 獲取Token,可選
) {
    String result = "客戶端信息:" + userAgent;
    if (token != null) {
        result += ",Token:" + token;
    }
    return result;
}23. @CookieValue
作用:獲取 HTTP 請求里的 Cookie 值,比如前端設(shè)置的用戶登錄 Cookie。
使用場景:需要從 Cookie 里獲取信息的時候,比如記住登錄狀態(tài)。
代碼示例:
@GetMapping("/cookie")
public String getCookie(
        @CookieValue(value = "username", required = false) String username, // 獲取username Cookie
        @CookieValue(value = "sessionId", defaultValue = "unknown") String sessionId // 默認(rèn)值
) {
    return "Cookie中的用戶名:" + username + ",SessionId:" + sessionId;
}四、組件掃描與注入相關(guān)注解(8 個)——Spring 管理 Bean 的核心
Spring 的核心是 IOC(控制反轉(zhuǎn)),就是讓 Spring 幫你創(chuàng)建和管理 Bean,這些注解幫你把 Bean 交給 Spring 管理,以及從 Spring 里拿 Bean 來用。
24. @Component
作用:標(biāo)記一個類是 “Spring 組件”,讓 Spring 在掃描的時候把它當(dāng)成 Bean 來管理。這是個通用注解,下面的 @Service、@Repository、@Controller 都是它的 “子類”,只是語義不同。
使用場景:不確定這個類屬于哪個層(服務(wù)層、數(shù)據(jù)層、控制層)的時候,就用 @Component。
代碼示例:
// 通用組件,用@Component
@Component
public class CommonUtils {
    // 比如一個工具方法
    public String formatDate(Date date) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return sdf.format(date);
    }
}25. @Service
作用:@Component 的 “子類”,專門標(biāo)記 “服務(wù)層” 的類(比如處理業(yè)務(wù)邏輯的類)。和 @Component 功能一樣,只是語義更清晰,一看就知道這個類是服務(wù)層的。
使用場景:所有業(yè)務(wù)邏輯類都用這個,比如 UserService、OrderService、PayService。
代碼示例:
// 服務(wù)層類,用@Service
@Service
publicclass UserService {
    // 業(yè)務(wù)邏輯方法:根據(jù)id查用戶
    public User getUserById(Long id) {
        // 這里實際會調(diào)用DAO層查數(shù)據(jù)庫,現(xiàn)在模擬一下
        if (id == 1L) {
            returnnew User(1L, "張三", 25);
        } else {
            returnnull;
        }
    }
    // 業(yè)務(wù)邏輯方法:添加用戶
    public boolean addUser(User user) {
        // 模擬保存邏輯
        return user != null && user.getName() != null;
    }
}26. @Repository
作用:@Component 的 “子類”,專門標(biāo)記 “數(shù)據(jù)訪問層” 的類(比如 DAO 層、Mapper 層)。除了語義清晰,它還能讓 Spring 自動轉(zhuǎn)換數(shù)據(jù)庫相關(guān)的異常(比如把 JDBC 的異常轉(zhuǎn)換成 Spring 的 DataAccessException)。
使用場景:DAO 層類,比如 UserDao、OrderDao,不過現(xiàn)在用 MyBatis 的話,更多用 @Mapper,@Repository 用得少了。
代碼示例:
// 數(shù)據(jù)訪問層類,用@Repository
@Repository
public class UserDao {
    // 模擬數(shù)據(jù)庫查詢
    public User findById(Long id) {
        return new User(id, "李四", 30);
    }
}27. @Autowired
作用:從 Spring 容器里 “自動注入” Bean,不用你手動 new 對象。默認(rèn)按 “類型” 注入,如果同一個類型有多個 Bean,就按 “名稱” 匹配(或者用 @Qualifier 指定名稱)。
使用場景:需要使用其他 Bean 的時候,比如 Controller 里用 Service,Service 里用 DAO/Mapper。
代碼示例:
@RestController
@RequestMapping("/user")
public class UserController {
    // 自動注入UserService,不用new UserService()
    @Autowired
    private UserService userService;
    @GetMapping("/{id}")
    public User getUserById(@PathVariable Long id) {
        // 直接用注入的userService調(diào)用方法
        return userService.getUserById(id);
    }
}@Service
publicclass UserService {
    // 同一個類型有多個Bean的情況,用@Qualifier指定Bean名稱
    @Autowired
    @Qualifier("userDaoImpl1") // 指定注入名稱為userDaoImpl1的Bean
    private UserDao userDao;
    public User getUserById(Long id) {
        return userDao.findById(id);
    }
}
// UserDao的實現(xiàn)類1
@Repository("userDaoImpl1")
publicclass UserDaoImpl1 implements UserDao {
    @Override
    public User findById(Long id) {
        returnnew User(id, "張三(來自Impl1)", 25);
    }
}
// UserDao的實現(xiàn)類2
@Repository("userDaoImpl2")
publicclass UserDaoImpl2 implements UserDao {
    @Override
    public User findById(Long id) {
        returnnew User(id, "李四(來自Impl2)", 30);
    }
}小提醒:@Autowired 默認(rèn)要求注入的 Bean 必須存在,不然會報錯。如果允許 Bean 不存在,可以加 required = false,比如@Autowired(required = false) private UserService userService。
28. @Resource
作用:和 @Autowired 類似,也是自動注入 Bean,但它是 JDK 自帶的注解(javax.annotation.Resource),不是 Spring 的。默認(rèn)按 “名稱” 注入,如果名稱找不到,再按 “類型” 注入。
使用場景:和 @Autowired 一樣,需要注入 Bean 的時候,有人習(xí)慣用 @Resource,有人習(xí)慣用 @Autowired,看個人喜好。
代碼示例:
@Service
public class OrderService {
    // 按名稱注入,name指定Bean名稱
    @Resource(name = "orderDao")
    private OrderDao orderDao;
    // 不指定name,默認(rèn)按變量名“userService”匹配Bean名稱
    @Resource
    private UserService userService;
    public Order getOrderById(Long id) {
        return orderDao.findById(id);
    }
}小提醒:@Resource 沒有 required 屬性,所以如果注入的 Bean 不存在,會直接報錯;而 @Autowired 有 required = false,可以避免這種情況。另外,@Resource 不能和 @Qualifier 一起用,要指定名稱就用它自己的 name 屬性。
29. @Qualifier
作用:和 @Autowired 一起用,指定要注入的 Bean 的 “名稱”。當(dāng)同一個類型有多個 Bean 的時候,@Autowired 按類型找不到唯一的 Bean,就需要 @Qualifier 指定名稱。
使用場景:同一個接口有多個實現(xiàn)類的時候,比如 UserDao 有 UserDaoImpl1 和 UserDaoImpl2,就用 @Qualifier 指定注入哪個。
代碼示例:前面 @Autowired 的例子里已經(jīng)用過了,這里再簡單來一個:
@Service
publicclass PayService {
    // 同一個PayDao有多個實現(xiàn)類,用@Qualifier指定注入alipayDao
    @Autowired
    @Qualifier("alipayDao")
    private PayDao payDao;
    public String pay(Double amount) {
        return payDao.pay(amount);
    }
}
@Repository("alipayDao")
publicclass AlipayDao implements PayDao {
    @Override
    public String pay(Double amount) {
        return"支付寶支付:" + amount + "元";
    }
}
@Repository("wechatPayDao")
publicclass WechatPayDao implements PayDao {
    @Override
    public String pay(Double amount) {
        return"微信支付:" + amount + "元";
    }
}30. @Primary
作用:當(dāng)同一個類型有多個 Bean 的時候,標(biāo)記哪個 Bean 是 “首選” 的。如果用 @Autowired 注入,沒指定 @Qualifier,就會優(yōu)先注入加了 @Primary 的 Bean。
使用場景:同一個類型有多個 Bean,且有一個是默認(rèn)常用的,就用 @Primary 標(biāo)記它。
代碼示例:
@Service
publicclass UserService {
    // 沒加@Qualifier,會優(yōu)先注入加了@Primary的UserDao
    @Autowired
    private UserDao userDao;
    public User getUserById(Long id) {
        return userDao.findById(id);
    }
}
// 加了@Primary,是首選Bean
@Repository
@Primary
publicclass UserDaoImpl1 implements UserDao {
    @Override
    public User findById(Long id) {
        returnnew User(id, "張三(首選Impl1)", 25);
    }
}
// 沒加@Primary,不是首選
@Repository
publicclass UserDaoImpl2 implements UserDao {
    @Override
    public User findById(Long id) {
        returnnew User(id, "李四(Impl2)", 30);
    }
}31. @Lazy
作用:讓 Bean “延遲初始化”,也就是 Spring 啟動的時候不創(chuàng)建這個 Bean,等到第一次使用的時候再創(chuàng)建。默認(rèn)情況下,Spring 啟動時會創(chuàng)建所有單例 Bean(餓漢式),加了 @Lazy 就是懶漢式。
使用場景:Bean 創(chuàng)建比較耗時,或者啟動時用不到的 Bean,比如某些定時任務(wù)的 Bean、某些只在特定條件下用的 Bean,用 @Lazy 可以加快項目啟動速度。
代碼示例:
// 加了@Lazy,Spring啟動時不創(chuàng)建這個Bean,第一次用的時候才創(chuàng)建
@Service
@Lazy
publicclass LazyService {
    public LazyService() {
        // 構(gòu)造方法,啟動時如果沒創(chuàng)建,這個日志不會打印
        System.out.println("LazyService被創(chuàng)建了");
    }
    public String doSomething() {
        return"LazyService做事了";
    }
}
@RestController
publicclass LazyController {
    @Autowired
    private LazyService lazyService;
    // 第一次訪問這個接口的時候,才會創(chuàng)建LazyService,打印構(gòu)造方法的日志
    @GetMapping("/lazy")
    public String testLazy() {
        return lazyService.doSomething();
    }
}五、AOP 相關(guān)注解(5 個)—— 切面編程不用愁
AOP(面向切面編程)是 Spring 的核心特性之一,用來做日志記錄、性能監(jiān)控、權(quán)限校驗、事務(wù)管理這些 “橫切關(guān)注點” 的功能。這些注解幫你快速實現(xiàn) AOP。
32. @Aspect
作用:標(biāo)記一個類是 “切面類”,里面定義了切入點(Pointcut)和通知(Advice)。
使用場景:所有需要實現(xiàn) AOP 的類都要加這個注解,比如日志切面、權(quán)限切面、性能監(jiān)控切面。
小提醒:光加 @Aspect 還不夠,還得讓 Spring 掃描到這個類(加 @Component),或者在配置類里用 @EnableAspectJAutoProxy 開啟 AOP 支持(不過 SpringBoot 默認(rèn)已經(jīng)開啟了,不用手動加)。
33. @Pointcut
作用:定義 “切入點”,也就是指定 AOP 要作用在哪些方法上。用表達(dá)式來描述切入點,比如 “所有 Service 層的方法”“某個包下的所有方法”“加了某個注解的方法”。
常用切入點表達(dá)式:
- execution:按方法簽名匹配,比如execution(* com.demo.service..(..))(com.demo.service 包下所有類的所有方法)
 - @annotation:按注解匹配,比如@annotation(com.demo.annotation.Log)(加了 @Log 注解的方法)
 - within:按類匹配,比如within(com.demo.service.*)(com.demo.service 包下所有類)
 - this:按接口匹配,比如this(com.demo.service.UserService)(實現(xiàn)了 UserService 接口的類)
 
使用場景:定義 AOP 作用的范圍,比如想給所有 Service 方法加日志,就用 execution 表達(dá)式;想給特定方法加日志,就自定義一個注解,用 @annotation 匹配。
34. @Before
作用:“前置通知”,在切入點方法執(zhí)行之前執(zhí)行。比如在方法執(zhí)行前記錄日志、校驗權(quán)限。
35. @After
作用:“后置通知”,在切入點方法執(zhí)行之后執(zhí)行(不管方法有沒有拋出異常,都會執(zhí)行)。比如在方法執(zhí)行后清理資源。
36. @AfterReturning
作用:“返回后通知”,在切入點方法正常返回之后執(zhí)行(如果方法拋出異常,就不會執(zhí)行)。比如在方法返回后記錄返回值。
37. @AfterThrowing
作用:“異常通知”,在切入點方法拋出異常之后執(zhí)行。比如在方法拋異常時記錄異常信息、發(fā)送告警。
38. @Around
作用:“環(huán)繞通知”,包裹住切入點方法,可以在方法執(zhí)行前、執(zhí)行后、返回后、拋異常后都做處理,功能最強大。比如做性能監(jiān)控(記錄方法執(zhí)行時間)。
代碼示例(完整 AOP 日志切面):
首先自定義一個 @Log 注解,用來標(biāo)記需要記錄日志的方法:
// 自定義@Log注解
@Target(ElementType.METHOD) // 注解作用在方法上
@Retention(RetentionPolicy.RUNTIME) // 注解在運行時生效
public @interface Log {
    String value() default ""; // 注解的屬性,用來描述日志內(nèi)容
}然后寫切面類:
@Component // 讓Spring掃描到
@Aspect// 標(biāo)記為切面類
publicclass LogAspect {
    privatestaticfinal Logger log = LoggerFactory.getLogger(LogAspect.class);
    // 定義切入點:加了@Log注解的方法
    @Pointcut("@annotation(com.demo.annotation.Log)")
    public void logPointcut() {}
    // 前置通知:方法執(zhí)行前記錄請求信息
    @Before("logPointcut() && @annotation(logAnnotation)") // 拿到@Log注解的屬性
    public void beforeLog(JoinPoint joinPoint, Log logAnnotation) {
        // 獲取請求信息
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        // 記錄日志
        log.info("【前置通知】請求URL:{},請求方法:{},日志描述:{}",
                request.getRequestURL(),
                request.getMethod(),
                logAnnotation.value());
    }
    // 返回后通知:方法正常返回后記錄返回值
    @AfterReturning(pointcut = "logPointcut()", returning = "result") // returning指定返回值變量名
    public void afterReturningLog(JoinPoint joinPoint, Object result) {
        log.info("【返回后通知】方法返回值:{}", result);
    }
    // 異常通知:方法拋異常后記錄異常信息
    @AfterThrowing(pointcut = "logPointcut()", throwing = "e") // throwing指定異常變量名
    public void afterThrowingLog(JoinPoint joinPoint, Exception e) {
        log.error("【異常通知】方法拋出異常:{},異常信息:{}",
                e.getClass().getName(),
                e.getMessage(),
                e); // 打印異常棧
    }
    // 環(huán)繞通知:記錄方法執(zhí)行時間
    @Around("logPointcut()")
    public Object aroundLog(ProceedingJoinPoint joinPoint) throws Throwable {
        long startTime = System.currentTimeMillis(); // 開始時間
        // 執(zhí)行切入點方法(也就是目標(biāo)方法)
        Object result = joinPoint.proceed();
        long endTime = System.currentTimeMillis(); // 結(jié)束時間
        long costTime = endTime - startTime; // 執(zhí)行時間
        log.info("【環(huán)繞通知】方法執(zhí)行時間:{}毫秒", costTime);
        return result; // 返回目標(biāo)方法的返回值
    }
}最后在需要記錄日志的方法上加 @Log 注解:
@RestController
@RequestMapping("/user")
publicclass UserController {
    @Autowired
    private UserService userService;
    // 加@Log注解,描述日志內(nèi)容
    @Log("根據(jù)ID查詢用戶")
    @GetMapping("/{id}")
    public User getUserById(@PathVariable Long id) {
        return userService.getUserById(id);
    }
    @Log("添加用戶")
    @PostMapping
    publicString addUser(@RequestBody User user) {
        boolean success = userService.addUser(user);
        return success ? "添加成功" : "添加失敗";
    }
}小提醒:環(huán)繞通知里一定要調(diào)用proceed()方法,不然目標(biāo)方法不會執(zhí)行;另外,proceed()方法可能會拋出異常,要處理或拋出。
六、事務(wù)管理相關(guān)注解(2 個)—— 數(shù)據(jù)一致性有保障
事務(wù)管理是數(shù)據(jù)庫操作的核心,比如轉(zhuǎn)賬的時候,扣錢和加錢必須同時成功或同時失敗,不然就會出問題。SpringBoot 用這些注解幫你輕松實現(xiàn)事務(wù)。
39. @Transactional
作用:標(biāo)記方法或類需要 “事務(wù)支持”,Spring 會自動管理事務(wù)的提交和回滾。如果方法里拋出未捕獲的異常(默認(rèn)是 RuntimeException 及其子類),事務(wù)會回滾;如果方法正常執(zhí)行,事務(wù)會提交。
使用場景:所有涉及多步數(shù)據(jù)庫操作的方法,比如轉(zhuǎn)賬、下單(創(chuàng)建訂單 + 扣庫存)、批量修改數(shù)據(jù)。
常用屬性:
- propagation:事務(wù)傳播行為,比如 REQUIRED(默認(rèn),沒有事務(wù)就新建,有就加入)、REQUIRES_NEW(不管有沒有事務(wù),都新建一個)
 - isolation:事務(wù)隔離級別,比如 DEFAULT(默認(rèn),用數(shù)據(jù)庫的隔離級別)、READ_COMMITTED(讀已提交,避免臟讀)
 - timeout:事務(wù)超時時間,單位秒,超過時間沒執(zhí)行完就回滾
 - rollbackFor:指定哪些異常會觸發(fā)回滾,默認(rèn)是 RuntimeException
 - noRollbackFor:指定哪些異常不會觸發(fā)回滾
 
代碼示例:
@Service
publicclass OrderService {
    @Autowired
    private OrderDao orderDao;
    @Autowired
    private StockDao stockDao;
    // 下單方法,需要事務(wù)支持:創(chuàng)建訂單和扣庫存必須同時成功或失敗
    @Transactional(
            propagation = Propagation.REQUIRED, // 事務(wù)傳播行為:默認(rèn)
            isolation = Isolation.READ_COMMITTED, // 隔離級別:讀已提交
            timeout = 5, // 超時時間5秒
            rollbackFor = Exception.class // 所有Exception都回滾(默認(rèn)只回滾RuntimeException)
    )
    public String createOrder(Long productId, Integer count) {
        try {
            // 1. 創(chuàng)建訂單
            Order order = new Order();
            order.setProductId(productId);
            order.setCount(count);
            order.setStatus(0); // 0:未支付
            orderDao.insert(order);
            log.info("創(chuàng)建訂單成功:{}", order.getId());
            // 2. 扣庫存
            int rows = stockDao.decreaseStock(productId, count);
            if (rows == 0) {
                // 庫存不足,拋出異常,觸發(fā)事務(wù)回滾
                thrownew RuntimeException("商品" + productId + "庫存不足");
            }
            log.info("扣庫存成功:商品{},數(shù)量{}", productId, count);
            return"下單成功,訂單ID:" + order.getId();
        } catch (Exception e) {
            log.error("下單失敗", e);
            // 拋出異常,觸發(fā)回滾(如果是checked異常,要手動拋,或者rollbackFor指定)
            thrownew RuntimeException("下單失?。? + e.getMessage());
        }
    }
}小提醒:
- @Transactional 只能用在 public 方法上,非 public 方法(private、protected)加了也沒用,事務(wù)不生效。
 - 方法內(nèi)部調(diào)用帶 @Transactional 的方法,事務(wù)也不生效,比如:
 
@Service
public class TestService {
    public void methodA() {
        // 內(nèi)部調(diào)用methodB,methodB的事務(wù)不生效
        methodB();
    }
    @Transactional
    public void methodB() {
        // 數(shù)據(jù)庫操作
    }
}解決辦法:把 methodB 放到另一個 Service 里,或者用 AOP 代理調(diào)用(比如自己注入自己)。
- 事務(wù)回滾只對數(shù)據(jù)庫操作有效,對非數(shù)據(jù)庫操作(比如修改緩存、發(fā)送消息)無效,需要自己處理。
 
40. @EnableTransactionManagement
作用:開啟 Spring 的事務(wù)管理支持。不過在 SpringBoot 里,只要引入了 spring-boot-starter-jdbc 或 spring-boot-starter-data-jpa 這些依賴,SpringBoot 會自動開啟事務(wù)管理,所以不用手動加這個注解。
使用場景:非 SpringBoot 項目(比如純 Spring 項目),需要手動加這個注解開啟事務(wù)管理。
代碼示例:
// 純Spring項目的配置類,需要加@EnableTransactionManagement
@Configuration
@EnableTransactionManagement
public class SpringConfig {
    // 配置數(shù)據(jù)源、事務(wù)管理器等
    @Bean
    public DataSource dataSource() {
        // 數(shù)據(jù)源配置
    }
    @Bean
    public PlatformTransactionManager transactionManager(DataSource dataSource) {
        returnnewDataSourceTransactionManager(dataSource);
    }
}七、異常處理相關(guān)注解(3 個)—— 全局異常不用慌
項目里肯定會有各種異常,比如用戶輸入錯誤、數(shù)據(jù)庫異常、接口調(diào)用異常,如果每個方法都寫 try-catch,太麻煩了。用這些注解可以實現(xiàn)全局異常處理,統(tǒng)一捕獲和處理異常。
41. @ControllerAdvice
作用:“控制器增強”,用來定義全局的異常處理、數(shù)據(jù)綁定、模型屬性等。和 @ExceptionHandler 一起用,就能實現(xiàn)全局異常處理。
使用場景:所有需要全局處理的情況,比如全局異常處理、全局?jǐn)?shù)據(jù)綁定。
42. @RestControllerAdvice
作用:@ControllerAdvice + @ResponseBody 的組合體!用來處理 REST 接口的全局異常,返回 JSON 格式的異常信息,不用再每個異常處理方法加 @ResponseBody。
使用場景:前后端分離項目的全局異常處理,幾乎全用這個。
43. @ExceptionHandler
作用:定義 “異常處理方法”,指定捕獲哪種異常。加在 @ControllerAdvice 或 @RestControllerAdvice 類里,就能全局捕獲指定的異常。
使用場景:捕獲特定異常,比如自定義異常、參數(shù)校驗異常、數(shù)據(jù)庫異常。
代碼示例(全局異常處理):
首先自定義一個業(yè)務(wù)異常類:
// 自定義業(yè)務(wù)異常
public class BusinessException extends RuntimeException {
    private Integer code; // 錯誤碼
    // 構(gòu)造方法
    public BusinessException(Integer code, String message) {
        super(message);
        this.code = code;
    }
    // getter
    public Integer getCode() {
        return code;
    }
}然后寫全局異常處理類:
// 全局異常處理,返回JSON
@RestControllerAdvice
publicclass GlobalExceptionHandler {
    // 捕獲自定義的BusinessException
    @ExceptionHandler(BusinessException.class)
    public ResponseEntity<ErrorResult> handleBusinessException(BusinessException e) {
        ErrorResult result = new ErrorResult(e.getCode(), e.getMessage());
        // 返回400狀態(tài)碼和錯誤信息
        return ResponseEntity.badRequest().body(result);
    }
    // 捕獲參數(shù)校驗異常(MethodArgumentNotValidException)
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<ErrorResult> handleValidException(MethodArgumentNotValidException e) {
        // 獲取校驗失敗的信息
        String message = e.getBindingResult().getFieldErrors().stream()
                .map(FieldError::getDefaultMessage)
                .collect(Collectors.joining(","));
        ErrorResult result = new ErrorResult(400, message);
        return ResponseEntity.badRequest().body(result);
    }
    // 捕獲其他所有未處理的異常(兜底)
    @ExceptionHandler(Exception.class)
    public ResponseEntity<ErrorResult> handleException(Exception e) {
        log.error("系統(tǒng)異常", e); // 記錄異常棧
        ErrorResult result = new ErrorResult(500, "系統(tǒng)繁忙,請稍后再試");
        // 返回500狀態(tài)碼
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(result);
    }
    // 錯誤結(jié)果實體類
    @Data
    staticclass ErrorResult {
        private Integer code; // 錯誤碼
        private String message; // 錯誤信息
        public ErrorResult(Integer code, String message) {
            this.code = code;
            this.message = message;
        }
    }
}然后在業(yè)務(wù)代碼里拋自定義異常:
@Service
publicclass UserService {
    public User getUserById(Long id) {
        if (id == null || id <= 0) {
            // 拋自定義異常,錯誤碼400,提示信息
            thrownew BusinessException(400, "用戶ID不能為空且必須大于0");
        }
        // 模擬查數(shù)據(jù)庫
        if (id == 1L) {
            returnnew User(1L, "張三", 25);
        } else {
            thrownew BusinessException(404, "用戶不存在");
        }
    }
}當(dāng)請求 /user/0 的時候,會拋 BusinessException,全局異常處理類會捕獲它,返回 JSON:
{
  "code": 400,
  "message": "用戶ID不能為空且必須大于0"
}小提醒:@RestControllerAdvice 默認(rèn)會處理所有 Controller 的異常,如果想只處理某個包下的 Controller,可以加 basePackages 屬性,比如@RestControllerAdvice(basePackages = "com.demo.controller")。
八、其他常用注解(7 個)—— 小注解大用處
這些注解雖然不是核心,但在開發(fā)中經(jīng)常用到,能解決很多實際問題。
44. @Scope
作用:指定 Bean 的 “作用域”,也就是 Bean 的創(chuàng)建方式和生命周期。
常用作用域:
- singleton:單例(默認(rèn)),Spring 啟動時創(chuàng)建,整個應(yīng)用只有一個實例,所有地方用的都是同一個。
 - prototype:多例,每次獲取 Bean 的時候(比如 @Autowired 注入、getBean ())都會創(chuàng)建一個新的實例。
 - request:請求作用域,每個 HTTP 請求創(chuàng)建一個新的 Bean,請求結(jié)束后銷毀,只在 Web 項目里有用。
 - session:會話作用域,每個 HTTP Session 創(chuàng)建一個新的 Bean,會話結(jié)束后銷毀,只在 Web 項目里有用。
 
使用場景:
- 一般情況下用 singleton(默認(rèn)),因為單例性能好。
 - 如果 Bean 里有狀態(tài)(比如有成員變量會被修改),就用 prototype,避免多線程安全問題。
 - Web 項目里,需要保存請求或會話相關(guān)數(shù)據(jù)的時候,用 request 或 session。
 
代碼示例:
// 多例Bean,每次注入或獲取都是新實例
@Component
@Scope("prototype")
publicclass PrototypeBean {
    private Integer count = 0;
    public void increment() {
        count++;
    }
    public Integer getCount() {
        return count;
    }
}
// 測試多例Bean
@RestController
publicclass ScopeController {
    @Autowired
    private PrototypeBean prototypeBean1;
    @Autowired
    private PrototypeBean prototypeBean2;
    @GetMapping("/prototype")
    public String testPrototype() {
        prototypeBean1.increment();
        prototypeBean2.increment();
        // 兩個Bean的count都是1,因為是不同的實例
        return"prototypeBean1 count:" + prototypeBean1.getCount() + 
               ",prototypeBean2 count:" + prototypeBean2.getCount();
    }
}45. @RequiredArgsConstructor
作用:Lombok 提供的注解,自動生成 “帶所有 final 字段的構(gòu)造方法”。配合 @NonNull 注解,可以生成帶非空字段的構(gòu)造方法。用它可以替代 @Autowired 注入 Bean,讓代碼更簡潔。
使用場景:需要注入多個 Bean 的時候,不用寫多個 @Autowired,加個 @RequiredArgsConstructor 就行。
代碼示例:
首先要引入 Lombok 依賴(SpringBoot 項目一般都會加):
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>然后用 @RequiredArgsConstructor 注入 Bean:
@RestController
@RequestMapping("/user")
@RequiredArgsConstructor// 自動生成帶final字段的構(gòu)造方法
publicclass UserController {
    // 用final修飾,@RequiredArgsConstructor會生成帶這個字段的構(gòu)造方法
    privatefinal UserService userService;
    // 不用加@Autowired,Spring會通過構(gòu)造方法注入
    privatefinal OrderService orderService;
    @GetMapping("/{id}")
    public User getUserById(@PathVariable Long id) {
        return userService.getUserById(id);
    }
    @GetMapping("/order/{userId}")
    public List<Order> getOrderByUserId(@PathVariable Long userId) {
        return orderService.getOrderByUserId(userId);
    }
}小提醒:@RequiredArgsConstructor 生成的是帶 final 字段的構(gòu)造方法,所以注入的 Bean 必須用 final 修飾;如果想注入非 final 的 Bean,可以用 @AllArgsConstructor(生成帶所有字段的構(gòu)造方法),但一般推薦用 final 修飾注入的 Bean,避免被修改。
46. @Slf4j
作用:Lombok 提供的注解,自動生成日志對象(private static final Logger log = LoggerFactory.getLogger (當(dāng)前類.class)),不用再手動寫日志對象了。
使用場景:所有需要打日志的類,比如 Controller、Service、Dao,用 @Slf4j 能省不少代碼。
代碼示例:
@Service
@Slf4j // 自動生成log對象
publicclass UserService {
    public User getUserById(Long id) {
        log.info("開始查詢用戶,用戶ID:{}", id); // 用log.info打日志
        try {
            // 模擬查數(shù)據(jù)庫
            if (id == 1L) {
                User user = new User(1L, "張三", 25);
                log.debug("查詢到用戶信息:{}", user); // debug日志,一般開發(fā)環(huán)境開啟
                return user;
            } else {
                log.warn("用戶不存在,用戶ID:{}", id); // warn日志,警告信息
                return null;
            }
        } catch (Exception e) {
            log.error("查詢用戶失敗,用戶ID:{}", id, e); // error日志,異常信息
            throw e;
        }
    }
}小提醒:日志級別從低到高是 trace < debug < info < warn < error,生產(chǎn)環(huán)境一般只開啟 info 及以上級別,避免 debug 日志太多影響性能。
47. @NonNull
作用:Lombok 提供的注解,加在方法參數(shù)或字段上,會自動生成非空校驗。如果參數(shù)或字段為 null,會拋出 NullPointerException。
使用場景:需要校驗參數(shù)或字段非空的時候,比如方法參數(shù)不能為 null,字段不能為 null,用 @NonNull 能省掉手動寫的 if (param == null) throw new NullPointerException () 代碼。
代碼示例:
@Service
publicclass UserService {
    // 方法參數(shù)加@NonNull,自動校驗非空
    public boolean addUser(@NonNull User user) {
        if (user.getName() == null) {
            returnfalse;
        }
        // 模擬保存
        returntrue;
    }
    // 字段加@NonNull,Lombok會在構(gòu)造方法和setter里加非空校驗
    @Data
    @AllArgsConstructor
    publicstaticclass User {
        private Long id;
        @NonNull// 姓名非空
        private String name;
        private Integer age;
    }
}
// 測試
@RestController
publicclass UserController {
    @Autowired
    private UserService userService;
    @PostMapping("/user")
    public String addUser(@RequestBody UserService.User user) {
        // 如果user是null,調(diào)用addUser的時候會拋NullPointerException
        boolean success = userService.addUser(user);
        return success ? "添加成功" : "添加失敗";
    }
}48. @Data
作用:Lombok 提供的注解,自動生成類的 getter、setter、toString、equals、hashCode 方法,不用再手動寫這些模板代碼了,能極大減少代碼量。
使用場景:所有實體類(比如 User、Order、Product),用 @Data 能省掉大量的 getter 和 setter 代碼。
代碼示例:
// 用@Data,自動生成getter、setter、toString、equals、hashCode
@Data
publicclassUser {
    private Long id;
    private String name;
    private Integer age;
    private String phone;
    private Date createTime;
}
// 測試
publicclassTest {
    public static void main(String[] args) {
        User user = new User();
        user.setId(1L); // 自動生成的setter
        user.setName("張三");
        System.out.println(user.getName()); // 自動生成的getter
        System.out.println(user); // 自動生成的toString
    }
}小提醒:@Data 包含了 @Getter、@Setter、@ToString、@EqualsAndHashCode、@RequiredArgsConstructor,如果不想生成其中某個方法,可以單獨用對應(yīng)的注解,比如 @Getter、@Setter。
49. @NoArgsConstructor
作用:Lombok 提供的注解,自動生成 “無參構(gòu)造方法”。
使用場景:實體類需要無參構(gòu)造方法的時候,比如 Jackson 反序列化 JSON 的時候需要無參構(gòu)造,JPA 實體類也需要無參構(gòu)造。
50. @AllArgsConstructor
作用:Lombok 提供的注解,自動生成 “帶所有字段的構(gòu)造方法”。
使用場景:需要創(chuàng)建包含所有字段的對象的時候,比如用構(gòu)造方法注入 Bean(配合 @RequiredArgsConstructor),或者快速創(chuàng)建實體類對象。
代碼示例(@NoArgsConstructor 和 @AllArgsConstructor):
@Data
@NoArgsConstructor// 無參構(gòu)造
@AllArgsConstructor// 全參構(gòu)造
publicclass Order {
    private Long id;
    private Long userId;
    private Double amount;
    private Integer status;
    privateDate createTime;
}
// 測試
publicclass Test {
    publicstaticvoid main(String[] args) {
        // 無參構(gòu)造
        Order order1 = new Order();
        order1.setId(1L);
        order1.setUserId(100L);
        // 全參構(gòu)造
        Order order2 = new Order(2L, 101L, 200.0, 0, newDate());
        System.out.println(order2);
    }
}總結(jié)
好了,以上就是 SpringBoot 最常用的 50 個注解,從核心啟動、配置管理、Web 開發(fā),到 Bean 注入、AOP、事務(wù)、異常處理,再到 Lombok 的實用注解,基本覆蓋了日常開發(fā)的所有場景。
這些注解不是孤立的,比如寫一個接口,會用到 @RestController、@GetMapping,注入 Service 會用到 @Autowired 或 @RequiredArgsConstructor,處理業(yè)務(wù)邏輯會用到 @Service,涉及數(shù)據(jù)庫操作會用到 @Transactional,打日志會用到 @Slf4j。把這些注解融會貫通,你的 SpringBoot 開發(fā)效率會提升一大截,代碼也會更簡潔、更規(guī)范。















 
 
 












 
 
 
 