国产无遮挡裸体免费直播视频,久久精品国产蜜臀av,动漫在线视频一区二区,欧亚日韩一区二区三区,久艹在线 免费视频,国产精品美女网站免费,正在播放 97超级视频在线观看,斗破苍穹年番在线观看免费,51最新乱码中文字幕

Spring Boot 常用注解整理(最全收藏版)

 更新時間:2025年05月14日 11:31:13   作者:Gurucyy  
本文系統(tǒng)整理了常用的 Spring/Spring Boot 注解,按照功能分類進行介紹,每個注解都會涵蓋其含義、提供來源、應(yīng)用場景以及代碼示例,幫助開發(fā)者深入理解和快速檢索,感興趣的朋友跟隨小編一起看看吧

Spring & Spring Boot 常用注解整理

現(xiàn)代的 Spring 與 Spring Boot 應(yīng)用大量使用注解來簡化配置、管理組件和實現(xiàn)各種框架功能。本文系統(tǒng)整理了常用的 Spring/Spring Boot 注解,按照功能分類進行介紹。每個注解都會涵蓋其含義、提供來源、應(yīng)用場景以及代碼示例,幫助開發(fā)者深入理解和快速檢索。

一、Spring Boot 核心注解

@SpringBootApplication

簡介: @SpringBootApplication 是 Spring Boot 應(yīng)用的主入口注解。它標(biāo)注在啟動類上,表示這是一個 Spring Boot 應(yīng)用。該注解由 Spring Boot 提供(位于 org.springframework.boot.autoconfigure 包),本質(zhì)上是一個組合注解,包含了 Spring Framework 和 Spring Boot 的關(guān)鍵配置注解。

作用與場景: 使用 @SpringBootApplication 標(biāo)記主類后,Spring Boot 會自動進行以下配置:

  • 配置類聲明: 包含了 @SpringBootConfiguration(其本身是 @Configuration 的特化),因此該類被視為配置類,可定義 Bean。
  • 組件掃描: 內(nèi)含 @ComponentScan,會自動掃描該類所在包及其子包下的組件(被諸如 @Component、@Service、@Controller 等注解標(biāo)記的類),將它們注冊為 Spring 容器中的 Bean。
  • 自動配置: 內(nèi)含 @EnableAutoConfiguration,根據(jù)類路徑下依賴自動配置 Spring Boot 應(yīng)用。例如,若 classpath 中存在 HSQLDB 數(shù)據(jù)庫依賴,則會自動配置內(nèi)存數(shù)據(jù)庫等。開發(fā)者無需手動編寫大量配置即可啟動應(yīng)用。

使用示例: 創(chuàng)建一個 Spring Boot 主啟動類,在類上添加 @SpringBootApplication 注解,并編寫 main 方法啟動應(yīng)用:

@SpringBootApplication
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
}

上述代碼中,MyApplication 類由 @SpringBootApplication 注解標(biāo)記為應(yīng)用入口。運行 SpringApplication.run 后,Spring Boot 將引導(dǎo)啟動內(nèi)嵌服務(wù)器、初始化 Spring 容器,自動掃描組件并完成配置。

注: @SpringBootApplication 提供了屬性用于定制,如 exclude 可排除特定的自動配置類。如果需要禁用某些自動配置,可以使用例如 @SpringBootApplication(exclude = DataSourceAutoConfiguration.class) 來排除。

二、Spring 容器與組件注冊注解

這一類注解用于將類注冊為 Spring 容器管理的組件或定義配置,以取代傳統(tǒng)的 XML 配置文件,實現(xiàn)注解驅(qū)動的裝配。

@Component

簡介: @Component 是一個通用的組件注解,由 Spring Framework 提供(org.springframework.stereotype.Component)。它用于將一個普通的 Java 類標(biāo)識為 Spring 容器中的 Bean。被標(biāo)注的類在組件掃描時會被發(fā)現(xiàn)并實例化,由容器統(tǒng)一管理生命周期。

作用與場景: 當(dāng)某個類不好歸類到特定層時,可以使用 @Component 進行標(biāo)注。典型場景如工具類、通用邏輯處理類等。使用 @Component 后,無需在 XML 中聲明 bean,Spring 會根據(jù)配置的掃描路徑自動將其注冊。提供模塊: Spring Context 模塊提供對組件掃描和 @Component 注解的支持。

使用示例: 定義一個組件類并演示注入:

@Component
public class MessageUtil {
    public String getWelcomeMessage() {
        return "Welcome to Spring!";
    }
}
// 使用組件
@Service
public class GreetingService {
    @Autowired
    private MessageUtil messageUtil;
    public void greet() {
        System.out.println(messageUtil.getWelcomeMessage());
    }
}

上例中,MessageUtil 類通過 @Component 標(biāo)記成為容器 Bean,GreetingService 中使用 @Autowired(詳見后文)將其注入,最后調(diào)用其方法。

@Service

簡介: @Service@Component 的一種特化,用于標(biāo)注業(yè)務(wù)邏輯層的組件(Service層)。它位于 Spring 框架的 org.springframework.stereotype 包。

作用與場景: 在分層架構(gòu)中,服務(wù)層類使用 @Service 注解,使代碼含義更語義化。盡管行為上和 @Component 相同(被掃描注冊為 Bean),@Service 強調(diào)該類承擔(dān)業(yè)務(wù)服務(wù)職責(zé)。提供模塊: Spring Context,同屬于組件模型的一部分。

使用示例:

@Service
public class OrderService {
    public void createOrder(Order order) {
        // 業(yè)務(wù)邏輯:創(chuàng)建訂單
    }
}

通過 @ServiceOrderService 會被自動掃描注冊。在需要使用它的地方,例如控制層或其他服務(wù)層,可以通過依賴注入獲取該 Bean 實例。

@Repository

簡介: @Repository@Component 的特化注解之一,用于標(biāo)注數(shù)據(jù)訪問層組件(DAO層,或倉庫類)。定義在 Spring Framework 的 org.springframework.stereotype.Repository 包中。

作用與場景: DAO 類(例如訪問數(shù)據(jù)庫的類)使用 @Repository 注解不僅可以被掃描為容器 Bean,還能啟用異常轉(zhuǎn)換功能。Spring DAO 層會捕獲底層數(shù)據(jù)訪問異常(如 JDBC 的 SQLException 或 JPA 的異常),將其翻譯為 Spring 統(tǒng)一的DataAccessException體系,從而簡化異常處理。換句話說,如果一個類標(biāo)注為 @Repository,Spring 在為其創(chuàng)建代理時會自動處理持久化異常,將原始異常轉(zhuǎn)為 Spring 的非檢查型數(shù)據(jù)訪問異常,以提高健壯性。另外,標(biāo)注了 @Repository 的類可以被 @Autowired 等注解自動裝配到其他地方。

使用示例:

@Repository
public class UserDao {
    @Autowired
    private JdbcTemplate jdbcTemplate;
    public User findById(Long id) {
        try {
            return jdbcTemplate.queryForObject("SELECT * FROM users WHERE id=?", 
                                               new BeanPropertyRowMapper<>(User.class), id);
        } catch (DataAccessException e) {
            // Spring 已將底層SQLException翻譯為DataAccessException
            throw e;
        }
    }
}

上例中,UserDao 使用 @Repository 注解,使其成為容器管理的DAO組件。Spring 自動為其提供異常轉(zhuǎn)換功能:如果 JDBC 操作拋出 SQLException,會被翻譯為 DataAccessException(RuntimeException),調(diào)用處可以統(tǒng)一處理。標(biāo)注后也允許通過 @Autowired 注入到服務(wù)層使用。

@Controller

簡介: @Controller 是 Spring MVC 的控制層組件注解,同樣派生自 @Component。由 Spring Web MVC 模塊提供(org.springframework.stereotype.Controller),用于標(biāo)識一個類是Web MVC 控制器,負(fù)責(zé)處理 HTTP 請求并返回視圖或響應(yīng)。

作用與場景: 在 Web 應(yīng)用程序中,@Controller 注解的類會被 DispatcherServlet 識別為控制器,用于映射請求URL、封裝模型數(shù)據(jù)并返回視圖名。通常配合視圖模板(如 Thymeleaf、JSP)返回頁面。如果需要直接返回 JSON 數(shù)據(jù),可以配合 @ResponseBody 或直接使用 @RestController(后者見下文)。

使用示例:

@Controller
public class HomeController {
    @RequestMapping("/home")
    public String homePage(Model model) {
        model.addAttribute("msg", "Hello Spring MVC");
        return "home"; // 返回視圖名,由視圖解析器解析為頁面
    }
}

上述 HomeController 使用 @Controller 標(biāo)記,提供一個映射 “/home” 請求的處理方法。返回值 "home" 代表視圖邏輯名,框架會根據(jù)配置解析到具體的頁面(如 home.html)。如果我們在類上使用了 @Controller,框架在啟動時會自動注冊相應(yīng)的映射。

@RestController

簡介: @RestController 是 Spring 提供的組合注解,等價于同時在類上使用 @Controller@ResponseBody。它主要由 Spring Web 模塊提供,用于RESTful Web服務(wù)的控制器。

作用與場景: 標(biāo)注 @RestController 的類會被識別為控制器,并且其每個處理方法的返回值會直接作為 HTTP 響應(yīng)體輸出,而不是作為視圖名稱解析。適用于需要返回 JSON、XML 等數(shù)據(jù)的場景,比如 Web API 接口。模塊提供: Spring Web(Spring MVC)。

使用示例:

@RestController
@RequestMapping("/api")
public class UserApiController {
    @GetMapping("/hello")
    public String hello() {
        return "Hello, RESTful";
    }
    @PostMapping("/users")
    public User createUser(@RequestBody User user) {
        // 直接接收J(rèn)SON反序列化為User對象,處理后返回
        return userService.save(user);
    }
}

UserApiController 使用 @RestController 注解,其方法返回字符串和對象將直接通過消息轉(zhuǎn)換器寫入響應(yīng)(例如字符串作為純文本,User 對象會序列化為 JSON)。不需要再在每個方法上加 @ResponseBody,使代碼更加簡潔。通常在開發(fā) REST API 時,都使用 @RestController 來定義控制器。

@Configuration

簡介: @Configuration 用于聲明一個配置類,由 Spring Framework 提供(org.springframework.context.annotation.Configuration)。配置類可以包含若干個帶有 @Bean 注解的方法,以定義 Bean 并交由 Spring 容器管理。@Configuration 本身也是 @Component,因此配置類也會被組件掃描注冊。

作用與場景: 在 Java Config 風(fēng)格的應(yīng)用中,@Configuration 相當(dāng)于傳統(tǒng) XML 配置文件。用于定義 Beans、設(shè)置依賴注入規(guī)則等。Spring Boot 應(yīng)用的某些自動配置也是以配置類形式存在。提供模塊: Spring Context。

使用示例:

@Configuration
public class AppConfig {
    @Bean
    public DataSource dataSource() {
        // 配置數(shù)據(jù)源 Bean,例如使用 HikariCP 數(shù)據(jù)源
        HikariDataSource ds = new HikariDataSource();
        ds.setJdbcUrl("jdbc:mysql://localhost:3306/test");
        ds.setUsername("root");
        ds.setPassword("123456");
        return ds;
    }
    @Bean
    public UserService userService() {
        // 將 UserService 注冊為 Bean,并注入依賴的數(shù)據(jù)源
        return new UserService(dataSource());
    }
}

上述 AppConfig@Configuration 注解標(biāo)識為配置類。方法 dataSource()userService() 上的 @Bean 注解會使 Spring 將其返回值注冊為容器中的 Bean。其中 userService() 方法調(diào)用了 dataSource(),Spring 會攔截并確保返回的是容器中單例的 DataSource Bean,而非每次調(diào)用重新實例化(即 CGLIB 增強 @Configuration 類確保 Bean 單例行為)。

@Bean

簡介: @Bean 注解用于定義一個 Bean。它標(biāo)注在方法上,表示該方法返回的對象會注冊到 Spring 容器中。@Bean 通常配合 @Configuration 使用,由 Spring Context 模塊提供。

作用與場景: 當(dāng)通過 JavaConfig 定義 Bean 時,用 @Bean 替代傳統(tǒng) XML <bean> 聲明。例如整合第三方庫的 Bean、或需要在創(chuàng)建 Bean 時執(zhí)行一些自定義邏輯等場景。@Bean 方法可以指定名稱(默認(rèn)是方法名),還支持設(shè)置 initMethod(初始化時回調(diào)方法)和 destroyMethod(銷毀時回調(diào)方法)。

使用示例:

@Configuration
public class MyConfig {
    @Bean(name = "customBean", initMethod = "init", destroyMethod = "cleanup")
    public MyComponent customBean() {
        return new MyComponent();
    }
}

在上例中,@Bean 注解聲明了 customBean 這個 Bean。容器啟動時調(diào)用 customBean() 方法創(chuàng)建 MyComponent 實例,并以 "customBean" 名稱注冊。initMethod="init" 表示在 Bean 創(chuàng)建后自動調(diào)用其 init() 方法進行初始化;destroyMethod="cleanup" 表示容器銷毀該 Bean 時調(diào)用其 cleanup() 方法。通過這種方式可以管理 Bean 的生命周期方法(類似于 InitializingBeanDisposableBean 接口或 @PostConstruct/@PreDestroy,見后文)。

@ComponentScan

簡介: @ComponentScan 用于配置組件掃描路徑的注解。由 Spring Context 提供,通常與 @Configuration 一起使用。它的作用是指示 Spring 在指定的包路徑下搜索帶有組件注解的類,并注冊為 Bean。

作用與場景: 默認(rèn)情況下,Spring Boot 的 @SpringBootApplication 已經(jīng)隱含指定掃描其所在包及子包。如果需要自定義掃描范圍(例如掃描其他包的組件),可以使用 @ComponentScan 注解并提供 basePackages 等屬性。普通 Spring 應(yīng)用(非 Boot)則經(jīng)常需要在主配置類上顯式使用 @ComponentScan 指定根包。提供模塊: Spring Context。

使用示例:

@Configuration
@ComponentScan(basePackages = {"com.example.service", "com.example.dao"})
public class AppConfig {
    // ... Bean definitions
}

上述配置類通過 @ComponentScan 指定 Spring 將掃描 com.example.servicecom.example.dao 這兩個包及其子包,搜索所有標(biāo)注了 @Component/@Service/@Controller 等的類并注冊。這樣可以將應(yīng)用的組件按照包組織,而由配置集中管理掃描范圍。

@Import

簡介: @Import 注解用于導(dǎo)入額外的配置類或組件到 Spring 容器。它由 Spring Context 提供,可用在 @Configuration 類上,將一個或多個配置類合并進來。也可以用于引入第三方配置。

作用與場景: 當(dāng)項目拆分成多個配置類時,可以通過 @Import 將它們組合。例如,將公共配置獨立出來,再在主配置中引入。Spring Boot 自動配置內(nèi)部也大量使用了 @Import 來按條件加載配置類。提供模塊: Spring Context。

使用示例:

@Configuration
@Import({SecurityConfig.class, DataConfig.class})
public class MainConfig {
    // 主配置,導(dǎo)入了安全配置和數(shù)據(jù)配置
}

如上,MainConfig 通過 @Import 導(dǎo)入了 SecurityConfigDataConfig 兩個配置類。這樣這兩個配置類中定義的 Bean 同樣會加載到容器中,相當(dāng)于把多個配置模塊拼裝在一起。相比在 XML 里用 <import>,注解方式更加直觀。

注: Spring Boot 提供的許多 @Enable... 注解(例如后文的 @EnableScheduling 等)內(nèi)部也是通過 @Import 導(dǎo)入相應(yīng)的配置實現(xiàn)啟用功能的。

三、依賴注入注解

依賴注入(DI)是 Spring 核心機制之一。以下注解用于在容器中進行 Bean 注入和裝配,解決 Bean 間的依賴關(guān)系。

@Autowired

簡介: @Autowired 是 Spring 提供的自動裝配注解(org.springframework.beans.factory.annotation.Autowired),用于按類型自動注入依賴對象。它可作用于字段、setter方法或者構(gòu)造函數(shù)上。由 Spring Context 模塊支持。

作用與場景: 標(biāo)注了 @Autowired 的屬性或方法,Spring 會在容器啟動時自動尋找匹配的 Bean 注入。其中按類型匹配是默認(rèn)行為。如果匹配到多個同類型 Bean,則需要結(jié)合 @Qualifier@Primary 來消除歧義(見下文)。如果沒有找到匹配 Bean,默認(rèn)會拋出異常??赏ㄟ^設(shè)置 @Autowired(required=false) 來表示找不到 Bean 時跳過注入而不報錯。

使用示例:

@Component
public class UserService {
    @Autowired  // 按類型自動裝配
    private UserRepository userRepository;
    // 或者構(gòu)造函數(shù)注入
    // @Autowired 
    // public UserService(UserRepository userRepository) { ... }
    public User findUser(Long id) {
        return userRepository.findById(id);
    }
}

上例中,UserService 有一個成員 userRepository,使用 @Autowired 標(biāo)注。容器會自動將類型為 UserRepository 的 Bean 注入進來(假設(shè)已有 @Repository@Component 標(biāo)記的 UserRepository 實現(xiàn))。開發(fā)者可以通過構(gòu)造器、setter 或字段注入的方式使用 @Autowired。注意: Spring 4.3+ 如果類中只有一個構(gòu)造器,且需要注入?yún)?shù),可省略構(gòu)造函數(shù)上的 @Autowired,仍會自動注入。

@Qualifier

簡介: @Qualifier 注解與 @Autowired 配合使用,用于按照名稱或限定符進行依賴注入匹配。它由 Spring 提供(org.springframework.beans.factory.annotation.Qualifier),可以解決當(dāng)容器中存在多個同類型 Bean 時的沖突。

作用與場景: 默認(rèn)按類型注入在有多于一個候選 Bean 時會無法確定注入哪個。例如有兩個實現(xiàn)類實現(xiàn)了同一接口,都被注冊為 Bean。這種情況下,可以在注入點使用 @Qualifier("beanName") 指定注入哪一個 Bean,或在 Bean 定義處使用 @Component("name") 為 Bean 命名,然后在注入處引用同名限定符。提供模塊: Spring Context/Beans。

使用示例:

@Component("mysqlRepo")
public class MySqlUserRepository implements UserRepository { ... }
@Component("oracleRepo")
public class OracleUserRepository implements UserRepository { ... }
@Service
public class UserService {
    @Autowired
    @Qualifier("mysqlRepo")  // 指定注入名稱為 mysqlRepo 的實現(xiàn)
    private UserRepository userRepository;
    // ...
}

如上,有兩個 UserRepository 實現(xiàn) Bean,分別命名為 “mysqlRepo” 和 “oracleRepo”。在 UserService 中,通過 @Qualifier("mysqlRepo") 指定注入名為 mysqlRepo 的 Bean。這樣即使存在多個同類型 Bean,Spring 也能準(zhǔn)確地注入所需的依賴。

@Primary

簡介: @Primary 注解用于標(biāo)記一個 Bean 為主要候選者。當(dāng)按類型注入出現(xiàn)多個 Bean 可選時,標(biāo)有 @Primary 的 Bean 將優(yōu)先被注入。它由 Spring 提供(org.springframework.context.annotation.Primary),可作用于類或方法(例如 @Bean 方法)上。

作用與場景: 如果不方便在每個注入點都使用 @Qualifier 指定 Bean,另一種方式是在 Bean 定義處用 @Primary 聲明一個首選 Bean。當(dāng)存在歧義時,容器會選擇標(biāo)記了 @Primary 的 Bean 注入。注意,@Primary 只能有一個,否則仍然無法明確選擇。提供模塊: Spring Context。

使用示例:

@Configuration
public class RepoConfig {
    @Bean
    @Primary  // 將這個Bean標(biāo)記為首選
    public UserRepository mysqlUserRepository() {
        return new MySqlUserRepository();
    }
    @Bean
    public UserRepository oracleUserRepository() {
        return new OracleUserRepository();
    }
}
@Service
public class UserService {
    @Autowired
    private UserRepository userRepository;
    // 將自動注入 mysqlUserRepository,因為它被標(biāo)記為 @Primary
}

在上例的配置中,我們定義了兩個 UserRepository Bean,其中 MySQL 實現(xiàn)被標(biāo)記為 @Primary。因此在 UserService 中按類型注入 UserRepository 時,Spring 會注入標(biāo)記了 @Primary 的 MySQL 實現(xiàn)。@Primary 提供了一個全局默認(rèn)方案,簡化了注入點的選擇。

@Resource

簡介: @Resource 是來自 JSR-250 規(guī)范的注解(Javax/Jakarta Annotation),Spring 對其提供了支持,用于按名稱或按類型注入依賴。它通常位于 jakarta.annotation.Resource(Java EE/Jakarta EE)包下。注意: 盡管不在 Spring 包中,Spring 容器能識別并處理它。

作用與場景: @Resource 可以看作功能類似于 @Autowired + @Qualifier 的組合。默認(rèn)情況下按名稱注入:它首先按照屬性名或指定的名稱在容器中查找 Bean,找不到再按類型匹配。這在某些情況下很有用,例如需要與傳統(tǒng) Java EE 代碼兼容時。在 Spring 應(yīng)用中,也有開發(fā)者偏好使用 @Resource 進行依賴注入。提供模塊: 需要引入相應(yīng)的 Jakarta Annotation API,但 Spring Framework 自身支持處理。

使用示例:

@Component("userRepo")
public class UserRepositoryImpl implements UserRepository { ... }
@Service
public class UserService {
    @Resource(name = "userRepo")  // 按名稱注入名為"userRepo"的Bean
    private UserRepository userRepo;
    // ...
}

這里,UserRepositoryImpl 組件被命名為 "userRepo"。在 UserService 中,通過 @Resource(name = "userRepo") 來注入。如果省略 name 屬性,@Resource 默認(rèn)以屬性名 userRepo 作為 Bean 名稱查找。與 @Autowired 不同,@Resource 不支持 required=false 屬性,但其異常信息可能更直觀(若找不到 Bean 則拋出 NoSuchBeanDefinitionException)。值得一提的是,Spring 也支持 JSR-330 的 @Inject(javax.inject.Inject)注解,其語義與 @Autowired 相同,也可用于構(gòu)造函數(shù)注入等。在實際開發(fā)中,可根據(jù)團隊規(guī)范選擇使用 Spring 原生的 @Autowired 還是標(biāo)準(zhǔn)的 @Resource/@Inject。

@Value

簡介: @Value 注解用于將外部化配置中的屬性值注入到 Bean 的字段或參數(shù)中。它由 Spring 提供(org.springframework.beans.factory.annotation.Value),常用于讀取 application.properties/yaml 配置文件或系統(tǒng)環(huán)境變量、JNDI等屬性。

作用與場景: 當(dāng)需要在 Bean 中使用配置文件里的值時,可以使用 @Value("${property.name}") 注入。例如數(shù)據(jù)庫連接參數(shù)、服務(wù)端口號等。還支持設(shè)置默認(rèn)值和 SpEL 表達式。提供模塊: Spring Context 環(huán)境抽象。

使用示例:
假設(shè) application.properties 有如下內(nèi)容:

app.name=MySpringApp
app.version=1.0.0

Java 類使用 @Value 注入:

@Component
public class AppInfo {
    @Value("${app.name}")
    private String appName;
    @Value("${app.version:0.0.1}")  // 帶默認(rèn)值,若配置缺失則使用0.0.1
    private String appVersion;
    // ...
}

上述 AppInfo 類中,@Value("${app.name}") 將把配置中的 app.name 值注入到 appName 字段。如果對應(yīng)屬性不存在,會啟動失敗。而 appVersion 字段提供了默認(rèn)值 0.0.1,當(dāng)配置文件未設(shè)置 app.version 時就會使用默認(rèn)值。這樣,可以靈活地將外部配置與代碼解耦,使應(yīng)用更易于調(diào)整參數(shù)而無需改動源碼。

@Scope

簡介: @Scope 注解用于指定 Bean 的作用域,由 Spring 提供(org.springframework.context.annotation.Scope)。默認(rèn)情況下,Spring 容器中的 Bean 都是單例(singleton)作用域。通過 @Scope 可以定義其他作用域,例如 prototype、request、session 等。

作用與場景: 常見的作用域:

  • singleton(默認(rèn)):容器中僅保持一個實例。
  • prototype:每次請求 Bean 時都會創(chuàng)建新實例。
  • Web相關(guān)的作用域(需要在 Web 容器環(huán)境下使用):如 request(每個HTTP請求創(chuàng)建)、session(每個會話創(chuàng)建)等。

在需要每次使用新對象的場景(如有狀態(tài) Bean),可將 Bean 定義成 prototype;在 Web 應(yīng)用中某些 Bean 希望隨請求或會話存續(xù),可用相應(yīng)作用域。提供模塊: Spring Context。

使用示例:

@Component
@Scope("prototype")
public class Connection {
    public Connection() {
        System.out.println("New Connection created.");
    }
}

Connection Bean 聲明為 prototype,每次獲取都會創(chuàng)建新的實例:

@Autowired
private Connection conn1;
@Autowired
private Connection conn2;

上面 conn1conn2 將是不同的實例,因為 Connection 定義為 prototype。日志會打印兩次 “New Connection created.”。若作用域是 singleton,則只創(chuàng)建一次實例并復(fù)用。需要注意,prototype Bean 的生命周期由使用方管理,Spring 只負(fù)責(zé)創(chuàng)建,不會自動調(diào)用其銷毀方法。

@Lazy

簡介: @Lazy 注解用于將 Bean 的初始化延遲到首次使用時(懶加載)。由 Spring 提供(org.springframework.context.annotation.Lazy),可用于類級別或 @Bean 方法上。

作用與場景: 默認(rèn)情況下,單例 Bean 在容器啟動時就會初始化。如果某些 Bean 的創(chuàng)建比較耗時或在應(yīng)用運行期間可能不會被用到,可以標(biāo)記為 @Lazy,這樣只有在真正需要時才實例化,減少啟動時間和資源消耗。懶加載常用于:例如調(diào)試或在單元測試中減少不必要 Bean 創(chuàng)建,或避免循環(huán)依賴時暫緩 Bean 的注入初始化。對于 prototype Bean,Spring 始終延遲創(chuàng)建(因為本身就按需創(chuàng)建),@Lazy主要針對單例 Bean。提供模塊: Spring Context。

使用示例:

@Service
@Lazy
public class HeavyService {
    public HeavyService() {
        // 構(gòu)造函數(shù)可能進行大量初始化
        System.out.println("HeavyService initialized");
    }
    // ...
}
@Controller
public class DemoController {
    @Autowired
    private HeavyService heavyService; // 被@Lazy標(biāo)記,不會在容器啟動時實例化
    // ...
}

如上,HeavyService 使用 @Lazy 注解標(biāo)記為懶加載單例。啟動時不會打印 “HeavyService initialized”。當(dāng) DemoController 第一次實際調(diào)用 heavyService 的方法或訪問它時,Spring 才會創(chuàng)建 HeavyService 實例并注入。這對于優(yōu)化啟動性能和按需加載組件很有幫助。但應(yīng)謹(jǐn)慎使用懶加載,如果Bean在啟動后馬上就會用到,則不應(yīng)延遲初始化,以免首次調(diào)用時產(chǎn)生延遲。

四、配置屬性注解

Spring 提供了將配置文件內(nèi)容綁定到對象的機制,這類注解幫助管理應(yīng)用的外部化配置和環(huán)境區(qū)分。

@ConfigurationProperties

簡介: @ConfigurationProperties 用于將一組配置屬性映射到一個 Java 類上。由 Spring Boot 提供(org.springframework.boot.context.properties.ConfigurationProperties),通常配合 Bean 使用。通過前綴(prefix)來批量注入配置項到類的屬性中。

作用與場景: 當(dāng)有多項相關(guān)配置需要使用時,比起逐個使用 @Value,可以定義一個配置屬性類。例如應(yīng)用配置、數(shù)據(jù)源配置等。在類上標(biāo)注 @ConfigurationProperties(prefix="xxx") 后,該類的各屬性會根據(jù)前綴讀取配置文件中的對應(yīng)項賦值。需要將該類注冊為 Bean(可以通過在類上加 @Component 或在配置類中用 @Bean 創(chuàng)建),Spring Boot 會自動將配置綁定到 Bean 實例上。

使用示例:
application.yml:

app:
  name: MyApp
  apiUrl: https://api.example.com
  pool:
    size: 20
    enableLog: true

定義屬性綁定類:

@Component  // 確保被掃描注冊為Bean
@ConfigurationProperties(prefix = "app")
public class AppProperties {
    private String name;
    private String apiUrl;
    private Pool pool;
    // 內(nèi)部靜態(tài)類或普通類用于嵌套屬性
    public static class Pool {
        private int size;
        private boolean enableLog;
        // getters/setters ...
    }
    // getters/setters ...
}

AppProperties 注入使用:

@RestController
public class AppInfoController {
    @Autowired
    private AppProperties appProperties;
    @GetMapping("/appInfo")
    public AppProperties getAppInfo() {
        // 返回整個配置對象,框架會序列化為JSON
        return appProperties;
    }
}

在這個例子中,@ConfigurationProperties(prefix="app") 使得 YAML 中 app 下的配置自動綁定到 AppProperties Bean。nameapiUrl 會對應(yīng)賦值,嵌套的 pool.sizepool.enableLog 也會注入到 Pool 類中。這樣可以方便地管理和校驗成組的配置屬性。需要注意,綁定類必須有無參構(gòu)造器,提供標(biāo)準(zhǔn)的 getter/setter。Spring Boot 還支持JSR-303校驗注解(如 @Validated)配合 @ConfigurationProperties 對配置進行格式校驗。

@EnableConfigurationProperties

簡介: @EnableConfigurationProperties 是 Spring Boot 用于啟用 @ConfigurationProperties 支持的注解。它通常加在主應(yīng)用類或配置類上,用來將帶有 @ConfigurationProperties 注解的配置POJO注入到容器中。

作用與場景: 在 Spring Boot 2.x 以后,如果配置屬性類已經(jīng)被聲明為 Bean(例如加了 @Component),則無需顯式使用這個注解。@EnableConfigurationProperties 常用在需要將未被組件掃描的配置屬性類納入 Spring 管理時。例如定義了一個純 POJO 沒有用@Component,則可以在主類上通過此注解指定要啟用綁定的配置類列表。提供模塊: Spring Boot AutoConfigure。

使用示例:

@SpringBootApplication
@EnableConfigurationProperties(AppProperties.class)
public class MyApplication {
    // ...
}

上述在主啟動類上添加了 @EnableConfigurationProperties(AppProperties.class),顯式指定將 AppProperties 這個被 @ConfigurationProperties 注解的類納入配置屬性綁定并注冊為 Bean。這樣即使未加 @Component,仍可使用 @Autowired 注入 AppProperties 實例。Spring Boot 自動配置模塊會掃描此注解并完成相應(yīng)的綁定工作。

@Profile

簡介: @Profile 注解用于根據(jù)**環(huán)境(Profile)**加載 Bean。由 Spring 提供(org.springframework.context.annotation.Profile)??梢詷?biāo)注在類或方法(Bean 方法)上,只有在激活的環(huán)境與指定 Profile 匹配時,該 Bean 才會注冊到容器。

作用與場景: 常用于區(qū)別開發(fā)、測試、生產(chǎn)環(huán)境的配置。例如開發(fā)環(huán)境使用嵌入式數(shù)據(jù)庫,而生產(chǎn)環(huán)境使用正式數(shù)據(jù)庫連接,就可以用 @Profile("dev")@Profile("prod") 注解分別標(biāo)注不同的配置類或 Bean。在運行應(yīng)用時通過配置 spring.profiles.active 激活某個 Profile,則對應(yīng)的 Bean 生效。提供模塊: Spring Context 環(huán)境管理。

使用示例:

@Configuration
public class DataSourceConfig {
    @Bean
    @Profile("dev")
    public DataSource memoryDataSource() {
        // 開發(fā)環(huán)境使用內(nèi)存數(shù)據(jù)庫
        return new H2DataSource(...);
    }
    @Bean
    @Profile("prod")
    public DataSource mysqlDataSource() {
        // 生產(chǎn)環(huán)境使用MySQL數(shù)據(jù)源
        return new MySQLDataSource(...);
    }
}

當(dāng)設(shè)置 spring.profiles.active=dev 時,應(yīng)用啟動只會創(chuàng)建 memoryDataSource Bean;設(shè)置為 prod 時只創(chuàng)建 mysqlDataSource Bean。如果不激活任何 Profile,上述兩個 Bean 都不會加載(也可以用 @Profile("default") 指定默認(rèn)配置)。使用 @Profile 實現(xiàn)了根據(jù)環(huán)境有條件地注冊 Bean,方便一套代碼多環(huán)境運行。

五、Bean 生命周期與作用域注解

Spring 管理的 Bean 具有完整的生命周期,包括初始化和銷毀過程。以下注解用于在生命周期特定階段執(zhí)行方法,以及控制 Bean 的作用域與加載時機。

@PostConstruct

簡介: @PostConstruct 是一個來自 Java 標(biāo)準(zhǔn)(JSR-250)的注解(位于 jakarta.annotation.PostConstruct)。Spring 容器在Bean初始化完依賴注入后,會調(diào)用被該注解標(biāo)記的方法。常用于初始化邏輯。需要注意在 Spring Boot 3+ 中,@PostConstruct 等由 Jakarta 引入,需要相應(yīng)依賴。

作用與場景: 當(dāng)我們希望在 Bean 完成依賴注入后自動執(zhí)行一些初始化代碼,可以在 Bean 的方法上加 @PostConstruct。例如設(shè)置默認(rèn)值、開啟定時器、檢查配置完整性等。在傳統(tǒng) Spring 中,這相當(dāng)于 <bean init-method="..."> 或?qū)崿F(xiàn) InitializingBean 接口的 afterPropertiesSet。提供模塊: JSR-250(Javax/Jakarta Annotation),由 Spring 容器支持調(diào)用。

使用示例:

@Component
public class CacheManager {
    private Map<String, Object> cache;
    @PostConstruct
    public void init() {
        // 初始化緩存
        cache = new ConcurrentHashMap<>();
        System.out.println("CacheManager initialized");
    }
}

當(dāng) Spring 創(chuàng)建了 CacheManager Bean 并注入完依賴后,會自動調(diào)用其 init() 方法,輸出 “CacheManager initialized” 并完成緩存容器初始化。這樣開發(fā)者無需手動調(diào)用初始化邏輯,容器托管完成。這對于單例Bean非常方便。

@PreDestroy

簡介: @PreDestroy 同樣來自 JSR-250 標(biāo)準(zhǔn)(jakarta.annotation.PreDestroy),Spring 在 Bean 銷毀前(容器關(guān)閉或 Bean 移除前)調(diào)用標(biāo)注該注解的方法。常用于資源釋放、保存狀態(tài)等操作。

作用與場景: 當(dāng)應(yīng)用結(jié)束或容器要銷毀 Bean 時,希望執(zhí)行一些清理工作,例如關(guān)閉文件流、線程池、數(shù)據(jù)庫連接等,可以在方法上加 @PreDestroy 注解。相當(dāng)于 XML 配置中的 <bean destroy-method="..."> 或?qū)崿F(xiàn) DisposableBean 接口的 destroy 方法。提供模塊: JSR-250,由 Spring 容器負(fù)責(zé)調(diào)用。

使用示例:

@Component
public class ConnectionManager {
    private Connection connection;
    @PostConstruct
    public void connect() {
        // 建立數(shù)據(jù)庫連接
        connection = DriverManager.getConnection(...);
    }
    @PreDestroy
    public void disconnect() throws SQLException {
        // 關(guān)閉數(shù)據(jù)庫連接
        if(connection != null && !connection.isClosed()) {
            connection.close();
            System.out.println("Connection closed.");
        }
    }
}

在上例中,ConnectionManager Bean 在初始化時建立數(shù)據(jù)庫連接,在容器銷毀時通過 @PreDestroy 標(biāo)記的 disconnect() 方法關(guān)閉連接。Spring 在應(yīng)用關(guān)閉時會調(diào)用該方法,確保資源釋放。這使得資源管理更加可靠,避免連接泄漏等問題。

@Scope (作用域) – 見上文第三部分

(此處簡要說明:) 使用 @Scope 注解可以改變 Bean 的作用域,比如 "singleton""prototype" 等。已在依賴注入部分詳細介紹其使用。

@Lazy (懶加載) – 見上文第三部分

(此處簡要說明:) 使用 @Lazy 可以延遲 Bean 的初始化直至第一次使用。在某些場景下提高啟動性能或解決循環(huán)依賴。前文已介紹其概念和示例。

六、Web 開發(fā)注解

Spring MVC 框架提供了大量注解來簡化 Web 開發(fā),包括請求映射、參數(shù)綁定、響應(yīng)處理等。這些注解大多位于 org.springframework.web.bind.annotation 包中。

@RequestMapping

簡介: @RequestMapping 是最基本的請求映射注解,用于將 HTTP 請求URL路徑映射到對應(yīng)的控制器類或處理方法上。由 Spring Web MVC 提供??捎糜陬惡头椒墑e。

作用與場景: 在類上標(biāo)注 @RequestMapping("basePath") 可以為該控制器指定一個基礎(chǔ)路徑,方法上的 @RequestMapping("subPath") 則在類路徑基礎(chǔ)上進一步細分。它支持設(shè)置請求方法(GET、POST等)、請求參數(shù)和請求頭等屬性,用于更精確地映射請求。例如只處理 GET 請求,或某個請求參數(shù)存在時才匹配。Spring MVC 啟動時會根據(jù)這些注解建立 URL 到方法的映射關(guān)系。

使用示例:

@Controller
@RequestMapping("/users")
public class UserController {
    @RequestMapping(value = "/{id}", method = RequestMethod.GET)
    public String getUserProfile(@PathVariable Long id, Model model) {
        // 根據(jù)id查詢用戶...
        model.addAttribute("user", userService.findById(id));
        return "profile";
    }
    @RequestMapping(value = "", method = RequestMethod.POST, params = "action=register")
    public String registerUser(UserForm form) {
        // 處理用戶注冊
        userService.register(form);
        return "redirect:/users";
    }
}

UserController 類上的 @RequestMapping("/users") 指定了基礎(chǔ)路徑“/users”。方法級注解:

  • getUserProfile: 映射 GET 請求到 “/users/{id}”。使用 method = RequestMethod.GET 限定請求方法為 GET,@PathVariable 獲取 URL 中的 {id} 部分。返回視圖名 “profile” 供顯示用戶信息。
  • registerUser: 映射 POST 請求到 “/users”,并使用 params="action=register" 進一步限定只有請求參數(shù)包含 action=register 時才調(diào)用此方法。這是區(qū)分同一路徑不同操作的方式。處理完后重定向到用戶列表。

@RequestMapping 非常靈活,其常用屬性:

valuepath:映射的 URL 路徑,可以是 Ant 風(fēng)格模式(如 /users/*)。method:限定 HTTP 方法,如 RequestMethod.GET 等。params:指定必須存在的參數(shù)或參數(shù)值,如 "action=register""!admin"(必須不包含admin參數(shù))。headers:指定必須的請求頭,如 "Content-Type=application/json"@GetMapping / @PostMapping

簡介: @GetMapping@PostMapping@RequestMapping 的派生注解,專門用于簡化映射 GET 和 POST 請求。類似的還有 @PutMapping、@DeleteMapping@PatchMapping,分別對應(yīng) HTTP PUT/DELETE/PATCH 方法。它們由 Spring MVC 提供,從 Spring 4.3 開始引入。

作用與場景: 這些注解相當(dāng)于 @RequestMapping(method = RequestMethod.X) 的快捷方式,使代碼更簡潔。尤其在定義 RESTful API 時,常用不同 HTTP 方法表示不同操作,用這些注解能直觀體現(xiàn)方法用途。例如 @GetMapping 表示獲取資源,@PostMapping 表示創(chuàng)建資源等。

使用示例:

@RestController
@RequestMapping("/items")
public class ItemController {
    @GetMapping("/{id}")
    public Item getItem(@PathVariable Long id) {
        return itemService.findById(id);
    }
    @PostMapping("")
    public Item createItem(@RequestBody Item item) {
        return itemService.save(item);
    }
    @DeleteMapping("/{id}")
    public void deleteItem(@PathVariable Long id) {
        itemService.delete(id);
    }
}

上例中:

  • @GetMapping("/{id}) 等價于 @RequestMapping(value="/{id}", method = RequestMethod.GET),用于獲取指定ID的 Item。
  • @PostMapping("") 等價于類路徑/items下的 POST 請求(創(chuàng)建新的 Item),請求體通過 @RequestBody 解析為 Item 對象。
  • @DeleteMapping("/{id}") 處理刪除操作。

這些組合注解讓控制器方法定義更直觀,更符合 RESTful 風(fēng)格??梢愿鶕?jù)需要使用對應(yīng)的 HTTP方法注解。未提供參數(shù)時,@GetMapping 等注解的路徑可以直接寫在注解括號內(nèi)(如上 @PostMapping("") 指當(dāng)前路徑)。

@PathVariable

簡介: @PathVariable 用于將 URL 路徑中的動態(tài)部分綁定到方法參數(shù)上。由 Spring MVC 提供。常與 @RequestMapping@GetMapping 等一起使用,用于處理RESTful風(fēng)格的URL。

作用與場景: 當(dāng)URL中含有變量占位符(如 /users/{id})時,可通過在方法參數(shù)上加 @PathVariable 來獲取該占位符的值。可以指定名稱匹配占位符,或者不指定名稱則根據(jù)參數(shù)名自動推斷。適用于從路徑獲取資源標(biāo)識(ID、name等)的場景。

使用示例:

@GetMapping("/orders/{orderId}/items/{itemId}")
public OrderItem getOrderItem(
        @PathVariable("orderId") Long orderId, 
        @PathVariable("itemId") Long itemId) {
    return orderService.findItem(orderId, itemId);
}

當(dāng)收到請求 /orders/123/items/456 時:

  • orderId 參數(shù)會被賦值為 123(Long 類型轉(zhuǎn)換),
  • itemId 參數(shù)賦值為 456。

@PathVariable("orderId") 中指定名稱,與 {orderId} 占位符對應(yīng)。如果方法參數(shù)名與占位符名稱相同,可以簡寫為 @PathVariable Long orderId。

通過 @PathVariable,我們無需從 HttpServletRequest 手動解析路徑,Spring MVC 自動完成轉(zhuǎn)換和注入,簡化了代碼。

@RequestParam

簡介: @RequestParam 用于綁定 HTTP 請求的查詢參數(shù)或表單數(shù)據(jù)到方法參數(shù)上。由 Spring MVC 提供。支持為參數(shù)設(shè)置默認(rèn)值、是否必需等屬性。

作用與場景: 處理 GET 請求的查詢字符串參數(shù)(URL ? 后的參數(shù))或 POST 表單提交的字段時,可以使用 @RequestParam 獲取。例如搜索接口的關(guān)鍵詞,分頁的頁碼和大小等。它可以將 String 類型的請求參數(shù)轉(zhuǎn)換為所需的目標(biāo)類型(如 int、boolean),自動完成類型轉(zhuǎn)換和必要的校驗。

使用示例:

@GetMapping("/search")
public List<Product> searchProducts(
        @RequestParam(name="keyword", required=false, defaultValue="") String keyword,
        @RequestParam(defaultValue="0") int pageIndex,
        @RequestParam(defaultValue="10") int pageSize) {
    return productService.search(keyword, pageIndex, pageSize);
}

當(dāng)請求 /search?keyword=phone&pageIndex=1 到達時:

  • keyword 參數(shù)綁定到方法的 keyword 參數(shù)。如果未提供則使用默認(rèn)值空字符串。
  • pageIndex 綁定到整型參數(shù),未提供則為默認(rèn)0。
  • pageSize 在此請求未提供,因此取默認(rèn)值10。

@RequestParam 常用屬性:

  • valuename:參數(shù)名,對應(yīng)URL中的參數(shù)名。
  • required:是否必須提供,默認(rèn) true(不提供會報錯)。上例中我們將 keyword 標(biāo)記為 false 可選。
  • defaultValue:如果請求未包含該參數(shù)則使用默認(rèn)值(注意即使標(biāo)記 required=true,有 defaultValue 也不會報錯)。

通過 @RequestParam,方法可以直接獲得解析后的參數(shù)值,無需自己從 request 獲取和轉(zhuǎn)換,大大簡化控制器代碼。

@RequestBody

簡介: @RequestBody 用于將 HTTP 請求報文體中的內(nèi)容轉(zhuǎn)換為 Java 對象并綁定到方法參數(shù)上。常用于處理 JSON 或 XML 等請求體。由 Spring MVC 提供。

作用與場景: 在 RESTful API 中,POST/PUT 等請求通常會攜帶 JSON 格式的數(shù)據(jù)作為請求體。使用 @RequestBody 注解在方法參數(shù)(通常是自定義的 DTO 類)上,Spring MVC 會利用 HttpMessageConverter 將 JSON/XML 等按需轉(zhuǎn)換為對應(yīng)的對象實例。適用于需要從請求正文獲取復(fù)雜對象的場景。與之對應(yīng),返回值或方法上使用 @ResponseBody(或 @RestController)可將對象序列化為響應(yīng)。

使用示例:

@PostMapping("/users")
public ResponseEntity<String> addUser(@RequestBody UserDTO userDto) {
    // userDto 已自動綁定了請求JSON的數(shù)據(jù)
    userService.save(userDto);
    return ResponseEntity.ok("User added successfully");
}

假設(shè)客戶端發(fā)送 POST 請求至 /users,請求體為:

{ "name": "Tom", "email": "tom@example.com" }

Spring MVC 會根據(jù) @RequestBody UserDTO userDto

  • 讀取請求體 JSON,
  • 將其轉(zhuǎn)換為 UserDTO 對象(要求有適當(dāng)?shù)膶傩院蛃etter)。
  • 然后傳遞給控制器方法使用。

方法處理后返回成功響應(yīng)。使用 @RequestBody,開發(fā)者無需手動解析 JSON,提高了開發(fā)效率并減少出錯。

注意: @RequestBody 默認(rèn)要求請求體存在,否則報錯。如果希望在請求體為空時處理為 null,可以設(shè)置 required=false。對于 GET 請求一般不使用 @RequestBody(GET沒有主體或主體被忽略)。

@ResponseBody

簡介: @ResponseBody 注解用于將控制器方法的返回值直接作為 HTTP 響應(yīng)內(nèi)容輸出,而不是解析為視圖名稱。由 Spring MVC 提供??梢詷?biāo)注在方法上或(較少見)標(biāo)注在類上(類上標(biāo)注相當(dāng)于對該類所有方法應(yīng)用此行為)。

作用與場景: @ResponseBody 常用于 AJAX 接口或 RESTful 方法,需要返回 JSON、XML或純文本等給客戶端,而非頁面。當(dāng)方法標(biāo)注該注解后,Spring 會將返回對象通過合適的 HttpMessageConverter 轉(zhuǎn)換為 JSON/XML 或其他格式寫入響應(yīng)流。例如返回一個對象會自動序列化為 JSON 字符串。@RestController 注解實際上已經(jīng)包含了 @ResponseBody 效果,所以在使用 @RestController 時無需再標(biāo)注此注解在每個方法上。

使用示例:

@Controller
public class StatusController {
    @GetMapping("/ping")
    @ResponseBody
    public String ping() {
        return "OK";
    }
    @GetMapping("/status")
    @ResponseBody
    public Map<String, Object> status() {
        Map<String, Object> info = new HashMap<>();
        info.put("status", "UP");
        info.put("timestamp", System.currentTimeMillis());
        return info;
    }
}

對于上例:

  • /ping 請求返回純文本 “OK” 給客戶端。
  • /status 請求返回一個 Map,Spring 會將其轉(zhuǎn)換為 JSON,如:{"status":"UP","timestamp":1638346953000}

因為使用的是普通的 @Controller 類,所以需要在每個方法上添加 @ResponseBody 來指示直接返回內(nèi)容。如果改用 @RestController 則可以省略這些注解。@ResponseBody 常用于快速測試接口或者在需要精確控制輸出內(nèi)容時使用。

@CrossOrigin

簡介: @CrossOrigin 注解用于配置跨域資源共享 (CORS)。由 Spring Web 提供,可標(biāo)注在類或方法上。它允許來自不同域名的客戶端訪問被標(biāo)注的資源。

作用與場景: 當(dāng)前端和后端分屬不同域(例如前端React開發(fā)服務(wù)器 http://localhost:3000,后端 http://localhost:8080)時,瀏覽器會攔截跨域請求。使用 @CrossOrigin 可以在服務(wù)端指定允許跨域的來源、方法、頭信息等,從而使瀏覽器允許調(diào)用。可以針對整個控制器類統(tǒng)一配置(類上標(biāo)注)或針對特定方法(方法上標(biāo)注)配置不同跨域策略。

使用示例:

@RestController
@RequestMapping("/api")
@CrossOrigin(origins = "http://localhost:3000")
public class ApiController {
    @GetMapping("/data")
    public Data getData() { ... }
    @PostMapping("/submit")
    @CrossOrigin(origins = "http://example.com", methods = RequestMethod.POST)
    public void submitData(@RequestBody Data data) { ... }
}

類上標(biāo)注的 @CrossOrigin(origins = "http://localhost:3000") 表示允許來自 http://localhost:3000 的跨域請求訪問該控制器的所有接口。submitData 方法上單獨標(biāo)注了一個不同的 @CrossOrigin,表示對于 /api/submit 接口,允許來自 http://example.com 的 POST 請求跨域訪問(不受類上通用配置限制)。@CrossOrigin 還可設(shè)置允許的請求頭、是否發(fā)送憑證等,通過參數(shù)如 allowedHeaders, allowCredentials 等配置。使用這個注解,開發(fā)者不必在全局Web配置中配置 CorsRegistry,可以就近管理跨域策略。

@ExceptionHandler

簡介: @ExceptionHandler 用于在控制器中定義異常處理方法的注解。由 Spring MVC 提供。通過指定要處理的異常類型,當(dāng)控制器方法拋出該異常時,轉(zhuǎn)而由標(biāo)注了 @ExceptionHandler 的方法來處理。

作用與場景: 為了避免將異常堆棧暴露給客戶端或者在每個控制器方法中編寫重復(fù)的 try-catch,可以使用 @ExceptionHandler集中處理。例如處理表單校驗異常返回友好錯誤信息、處理全局異常返回統(tǒng)一格式響應(yīng)等。@ExceptionHandler 通常與 @ControllerAdvice(后述)配合,用于全局異常處理;也可以直接在本控制器內(nèi)部定義專門的異常處理方法。

使用示例:

@Controller
@RequestMapping("/orders")
public class OrderController {
    @GetMapping("/{id}")
    public String getOrder(@PathVariable Long id, Model model) {
        Order order = orderService.findById(id);
        if(order == null) {
            throw new OrderNotFoundException(id);
        }
        model.addAttribute("order", order);
        return "orderDetail";
    }
    // 本控制器專門處理 OrderNotFoundException
    @ExceptionHandler(OrderNotFoundException.class)
    public String handleNotFound(OrderNotFoundException ex, Model model) {
        model.addAttribute("error", "訂單不存在,ID=" + ex.getOrderId());
        return "orderError";
    }
}

OrderController 中,getOrder 方法如果找不到訂單,會拋出自定義的 OrderNotFoundException。下方用 @ExceptionHandler(OrderNotFoundException.class) 標(biāo)注了 handleNotFound 方法來處理這種異常:當(dāng)異常拋出后,控制器不會繼續(xù)執(zhí)行原流程,而是進入該方法。方法可以接收異常對象,以及 Model 等參數(shù),處理后返回一個視圖名 "orderError" 顯示錯誤信息。

通過 @ExceptionHandler,控制器內(nèi)部的異常處理邏輯與正常業(yè)務(wù)邏輯解耦,代碼清晰且易于維護。

@ControllerAdvice

簡介: @ControllerAdvice 是全局控制器增強注解。由 Spring MVC 提供,用于定義一個全局異常處理或全局?jǐn)?shù)據(jù)綁定的切面類。標(biāo)注該注解的類可以包含多個 @ExceptionHandler 方法,用于處理應(yīng)用所有控制器拋出的異常;也可以包含 @ModelAttribute@InitBinder 方法對所有控制器生效。

作用與場景: 當(dāng)需要對所有控制器統(tǒng)一處理某些邏輯時,使用 @ControllerAdvice 非常方便。典型用法是結(jié)合 @ExceptionHandler 作為全局異常處理器,比如攔截所有 Exception 返回通用錯誤響應(yīng),或分類處理不同異常類型返回不同狀態(tài)碼。提供模塊: Spring MVC。

使用示例:

@ControllerAdvice
public class GlobalExceptionHandler {
    // 處理所有異常的fallback
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public ResponseEntity<String> handleException(Exception ex) {
        // 記錄日志
        ex.printStackTrace();
        // 返回通用錯誤響應(yīng)
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                             .body("Internal Server Error: " + ex.getMessage());
    }
    // 處理特定異常
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseBody
    public ResponseEntity<List<String>> handleValidationException(MethodArgumentNotValidException ex) {
        List<String> errors = ex.getBindingResult().getAllErrors()
                                .stream()
                                .map(ObjectError::getDefaultMessage)
                                .collect(Collectors.toList());
        return ResponseEntity.badRequest().body(errors);
    }
}

GlobalExceptionHandler 類使用 @ControllerAdvice 聲明后,Spring 會將其中標(biāo)注了 @ExceptionHandler 的方法應(yīng)用到整個應(yīng)用的控制器:

  • 第一個方法捕獲所有未被其它更專門處理的異常,打印棧Trace并返回500錯誤提示。
  • 第二個方法專門處理參數(shù)校驗失敗異常,提取錯誤信息列表并返回400狀態(tài)和錯誤列表。

此外,可以在 @ControllerAdvice 類中定義 @ModelAttribute 方法,為所有控制器請求添加模型數(shù)據(jù)(如公共下拉選項),或定義 @InitBinder 方法,注冊全局屬性編輯器等。@ControllerAdvice 可以通過屬性限制只應(yīng)用于某些包或注解的控制器,但全局異常處理通常都是應(yīng)用全局的。

通過 @ControllerAdvice,我們實現(xiàn)了 AOP 式的全局控制器邏輯抽取,使各控制器關(guān)注自身業(yè)務(wù),將通用邏輯集中處理,保持代碼整潔。

七、數(shù)據(jù)訪問與事務(wù)注解

在使用 Spring 管理數(shù)據(jù)持久化層時,會涉及到 JPA/Hibernate 等注解定義實體,以及 Spring 提供的事務(wù)管理注解等。

@Entity

簡介: @Entity 是 Java Persistence API (JPA) 的注解(jakarta.persistence.Entity),用于將一個類聲明為 JPA 實體。Spring Boot 通常通過 JPA/Hibernate 來操作數(shù)據(jù)庫,因此定義模型時會用到它。@Entity 注解的類對應(yīng)數(shù)據(jù)庫中的一張表。

作用與場景: 標(biāo)記為 @Entity 的類將由 JPA 實現(xiàn)(例如 Hibernate)管理,其實例可映射到數(shù)據(jù)庫記錄。必須提供主鍵(用 @Id 標(biāo)注),可選地用 @Table 指定表名,不指定則默認(rèn)表名為類名。提供模塊: JPA 規(guī)范,由 Hibernate 等實現(xiàn)。在 Spring Boot 中,引入 spring-boot-starter-data-jpa 會自動掃描 @Entity 類并創(chuàng)建表結(jié)構(gòu)(結(jié)合DDL生成策略)。

使用示例:

@Entity
@Table(name = "users")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;              // 主鍵
    @Column(name = "username", length = 50, nullable = false, unique = true)
    private String username;      // 用戶名列
    @Column(nullable = false)
    private String password;      // 密碼列
    // getters & setters ...
}

User 類被 @Entity 注解標(biāo)記為持久化實體,對應(yīng)數(shù)據(jù)庫表users(由@Table指定,若不指定默認(rèn)表名User)。字段上:

  • id@Id 標(biāo)識為主鍵,@GeneratedValue 指定主鍵生成策略(自增)。
  • username@Column 細化映射:列名指定為username,長度50,非空且唯一。
  • password 僅用了 @Column(nullable=false),列名默認(rèn)為屬性名。

定義好實體后,可以使用 Spring Data JPA 的倉庫接口來自動生成常用查詢(見下文 @Repository@Query)。Spring Boot 啟動時若開啟DDL-auto,會根據(jù)實體定義自動在數(shù)據(jù)庫創(chuàng)建或更新表結(jié)構(gòu)。

@Table

簡介: @Table 是 JPA 注解(jakarta.persistence.Table),配合 @Entity 使用,用于指定實體映射的數(shù)據(jù)庫表信息,如表名、schema、catalog等。

作用與場景: 默認(rèn)情況下,實體類名即表名。若數(shù)據(jù)庫表名與類名不同,或者需要定義 schema,使用 @Table 注解非常必要。也能定義唯一約束等。提供模塊: JPA。

使用示例:

@Entity
@Table(name = "T_USER", schema = "public", uniqueConstraints = {
    @UniqueConstraint(columnNames = "email")
})
public class User {
    // ...
}

該實體指定映射到 public 模式下的 T_USER 表,并聲明 email 列上有唯一約束。@Table 的屬性:

  • name:表名。
  • schema/catalog:所屬 schema 或 catalog 名稱。
  • uniqueConstraints:唯一約束定義。

@Id

簡介: @Id 是 JPA 注解(jakarta.persistence.Id),指定實體類的主鍵字段。每個 @Entity 必須有且只有一個屬性使用 @Id 注解??膳浜?@GeneratedValue 一起使用定義主鍵生成策略。

作用與場景: 標(biāo)記主鍵后,JPA 會將該字段作為數(shù)據(jù)庫表的主鍵列。支持基本類型或包裝類型,或 java.util.UUID 等。提供模塊: JPA。

使用示例:

@Entity
public class Product {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    // ... 其他字段
}

如上,id 字段為主鍵,使用自動生成策略。常見的 GenerationType

  • IDENTITY:數(shù)據(jù)庫自增字段(MySQL的AUTO_INCREMENT等)。
  • SEQUENCE:使用數(shù)據(jù)庫序列(需要定義序列,Oracle等DB適用)。
  • AUTO:讓 JPA 自動選擇合適策略。
  • TABLE:使用一個數(shù)據(jù)庫表模擬序列。

@GeneratedValue

簡介: @GeneratedValue 是 JPA 注解(jakarta.persistence.GeneratedValue),與 @Id 聯(lián)用,表示主鍵的生成方式??芍付ú呗?strategy 和生成器 generator。

作用與場景: 根據(jù)數(shù)據(jù)庫和需求選擇主鍵生成策略。比如 MySQL 用 IDENTITY 讓數(shù)據(jù)庫自增,Oracle 用 SEQUENCE 指定序列名稱等。提供模塊: JPA。

使用示例:

@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "user_seq")
@SequenceGenerator(name = "user_seq", sequenceName = "user_sequence", allocationSize = 1)
private Long id;

上例中,使用序列生成器:

  • @SequenceGenerator 定義名為 “user_seq” 的序列生成器,映射數(shù)據(jù)庫序列 “user_sequence”。
  • @GeneratedValue 引用該生成器并使用 SEQUENCE 策略。每次插入User時會從序列獲取下一個值作為ID。

對于常用的 AUTO 或 IDENTITY 策略,在大多數(shù)情況下只需簡單標(biāo)注 @GeneratedValue(strategy = GenerationType.IDENTITY) 等,無需額外生成器配置。

@Column

簡介: @Column 是 JPA 注解(jakarta.persistence.Column),用于定義實體字段與數(shù)據(jù)庫表列的映射細節(jié)??梢圆皇褂茫绻粯?biāo)注,JPA 默認(rèn)按屬性名映射列名(可能做小寫下劃線轉(zhuǎn)換,視實現(xiàn)而定)。

作用與場景: @Column 可指定列名、數(shù)據(jù)類型長度、是否允許NULL、是否唯一等約束。對于日期時間類型,還可指定 columnDefinitionTemporal 等,控制SQL類型。提供模塊: JPA。

使用示例:

@Column(name = "email", length = 100, nullable = false, unique = true)
private String email;

如上,將字段 email 映射為名為 email 的列(其實和默認(rèn)同名,但明確指出),長度100,非空且唯一。使用 @Column 可以清晰地將實體和數(shù)據(jù)庫字段對應(yīng)起來。

@Repository – 見上文第二部分

(此處補充:) 在數(shù)據(jù)訪問層,@Repository 標(biāo)注的接口或類通常與 Spring Data JPA 搭配使用。如一個接口 UserRepository extends JpaRepository<User, Long> 上加 @Repository(實際上 Spring Data JPA 的接口已經(jīng)隱式有這個語義),Spring 會為其生成實現(xiàn)并交由容器管理。@Repository 除了提供組件掃描和異常轉(zhuǎn)換外,本身沒有其他方法屬性。

@Transactional

簡介: @Transactional 是 Spring 提供的聲明式事務(wù)管理注解(org.springframework.transaction.annotation.Transactional)??蓸?biāo)注在類或方法上,表示其中的數(shù)據(jù)庫操作應(yīng)當(dāng)在一個事務(wù)中執(zhí)行。Spring 將在運行時提供事務(wù)支持,如開始、提交或回滾事務(wù)。

作用與場景: 數(shù)據(jù)庫操作需要事務(wù)保障數(shù)據(jù)一致性,例如同時更新多張表,要么全部成功要么全部失敗。使用 @Transactional 可以在不手動編程式管理事務(wù)的情況下,由框架自動處理。典型應(yīng)用:

  • Service 層的方法需要原子性,則加上 @Transactional,Spring會在進入方法時開啟事務(wù),方法成功返回則提交,如有異常則回滾。
  • 也可加在類上,表示類中所有公有方法都事務(wù)管理。

提供模塊: Spring ORM/Transaction 模塊,需要相應(yīng)的事務(wù)管理器(DataSourceTransactionManager 或 JpaTransactionManager 等)配置。Spring Boot 自動根據(jù)數(shù)據(jù)源配置合適的事務(wù)管理器。

使用示例:

@Service
public class AccountService {
    @Autowired
    private AccountRepository accountRepo;
    @Autowired
    private AuditService auditService;
    @Transactional
    public void transfer(Long fromId, Long toId, BigDecimal amount) {
        // 扣減轉(zhuǎn)出賬戶余額
        accountRepo.decreaseBalance(fromId, amount);
        // 增加轉(zhuǎn)入賬戶余額
        accountRepo.increaseBalance(toId, amount);
        // 記錄轉(zhuǎn)賬流水
        auditService.logTransfer(fromId, toId, amount);
        // 方法結(jié)束時,Spring自動提交事務(wù)。如發(fā)生運行時異常則自動回滾。
    }
}

transfer 方法標(biāo)注了 @Transactional,因此上述三個數(shù)據(jù)庫操作將處于同一個事務(wù)中:如果任何一步拋出未經(jīng)捕獲的異常(默認(rèn)僅RuntimeException和Error會導(dǎo)致回滾,可通過 rollbackFor 屬性更改回滾規(guī)則),所有已執(zhí)行的數(shù)據(jù)庫更新都會回滾,保持?jǐn)?shù)據(jù)一致性。如果全部成功,則提交事務(wù),將更新真正持久化。事務(wù)傳播行為隔離級別等也可以通過注解屬性配置,例如 @Transactional(propagation=Propagation.REQUIRES_NEW) 開啟新事務(wù),@Transactional(isolation=Isolation.SERIALIZABLE) 設(shè)置高隔離級別等,視業(yè)務(wù)需求而定。

注意: 使用 @Transactional 時,需要確保啟用了 Spring 的事務(wù)支持(見下文 @EnableTransactionManagement),Spring Boot 會自動在有數(shù)據(jù)源時啟用事務(wù)管理。所以在 Boot 場景下通常不需要額外配置即可使用。

@JsonFormat

簡介: @JsonFormat 是 Jackson 提供的序列化/反序列化格式化注解(com.fasterxml.jackson.annotation.JsonFormat)。可作用在字段、方法(getter / setter)或類型上,用于自定義日期-時間、數(shù)字、布爾等屬性在 JSON ←→ Java 轉(zhuǎn)換時的形態(tài)、時區(qū)與本地化設(shè)置。

作用與場景:

  • 日期時間格式化:將 Date / LocalDateTime 等類型格式化為固定字符串(例如 yyyy-MM-dd HH:mm:ss)并指定時區(qū),避免前后端默認(rèn)時區(qū)不一致導(dǎo)致時間偏移。
  • 數(shù)字 / 布爾形態(tài)控制:可把布爾值序列化成 0/1,或把 Instant、LocalDateTime 轉(zhuǎn)成數(shù)值時間戳(shape = NUMBER)等。
  • 與 Bean Validation 協(xié)同:在 DTO 中同時配合 @DateTimeFormat / 校驗注解,可保持前后端格式完全一致。
  • 優(yōu)先級:字段級 @JsonFormat 會覆蓋 ObjectMapper 的全局日期格式配置,適用于單獨字段需要特殊格式的場景。

使用示例:

@Data
public class OrderDTO {
    private Long id;
    // 1. 指定日期-時間格式 + 時區(qū)
    @JsonFormat(shape = JsonFormat.Shape.STRING,
                pattern = "yyyy-MM-dd HH:mm:ss",
                timezone = "GMT+8")
    private LocalDateTime createdAt;
    // 2. 以秒級時間戳輸出
    @JsonFormat(shape = JsonFormat.Shape.NUMBER)
    private Instant eventTime;
    // 3. 布爾值改為 0 / 1
    @JsonFormat(shape = JsonFormat.Shape.NUMBER)
    private Boolean paid;
}

@Getter

簡介: @Getter 是 Lombok 提供的生成器注解(lombok.Getter)。編譯期自動為被注解的類或字段生成 public getter 方法,省去手寫樣板代碼。

作用與場景:

  • 簡化 POJO / DTO 編寫:一個注解即可為所有字段(或單獨字段)生成讀取方法,保持類體簡潔。
  • 與框架集成:Spring / Jackson / Hibernate 等框架依賴 getter 讀取屬性時可直接使用 Lombok 生成的方法。

使用示例:

@Getter          // 為所有字段生成 getter
public class UserVO {
    private Long id;
    @Getter(AccessLevel.NONE) // 不生成該字段的 getter
    private String password;
    // 也可在字段級別加 @Getter 僅生成單個方法
}

依賴:開發(fā)環(huán)境需引入 lombok 依賴,并在 IDE 中安裝 Lombok 插件或開啟 Annotation Processing。

@Setter

簡介: @Setter 同樣由 Lombok 提供(lombok.Setter),自動為類或字段生成 public setter 方法。

作用與場景:

  • 可變對象賦值:在需要修改字段值、或框架反射注入時使用。
  • 粒度控制:可通過 AccessLevel 設(shè)置方法可見性(如 @Setter(AccessLevel.PROTECTED)),或僅在特定字段上使用,避免暴露全部可寫接口。

使用示例:

@Getter
@Setter               // 為所有字段生成 setter
public class ProductVO {
    private Long id;
    @Setter(AccessLevel.PRIVATE) // 僅類內(nèi)部可修改
    private BigDecimal price;
    // price 的 setter 為 private,其余字段的 setter 為 public
}

@ToString

簡介: @ToString 亦由 Lombok 提供(lombok.ToString)。在編譯期生成 toString() 方法,自動拼接字段名和值,支持包含/排除特定字段、隱藏敏感信息等。

作用與場景:

  • 調(diào)試與日志:快速輸出對象內(nèi)容而不必手寫 toString()。
  • 避免敏感字段泄漏:可用 @ToString.Exclude 排除字段,或在注解上設(shè)置 callSuper = true 包含父類字段。
  • 鏈?zhǔn)阶⒔?/strong>:常與 @Getter/@Setter/@EqualsAndHashCode 等一起使用,快速生成完整數(shù)據(jù)類。

使用示例:

@Getter
@Setter
@ToString(exclude = "password")          // 排除 password
public class AccountVO {
    private String username;
    @ToString.Exclude
    private String password;             // 或者字段級排除
    private LocalDateTime lastLogin;
}
/*
輸出示例:
AccountVO(username=admin, lastLogin=2025-05-10T20:30:00)
*/

在生產(chǎn)日志中輸出對象時務(wù)必排除敏感信息;@ToString 支持 exclude 數(shù)組或字段級 @ToString.Exclude 精細控制。

@EnableTransactionManagement

簡介: @EnableTransactionManagement 注解用于開啟 Spring 對 事務(wù)注解(如 @Transactional)的支持。由 Spring 提供(org.springframework.transaction.annotation.EnableTransactionManagement)。一般加在配置類上。

作用與場景: 在非 Spring Boot 場景下,使用 @Transactional 前通常需要在 Java 配置類上加此注解或在 XML 中配置 <tx:annotation-driven/> 來啟用事務(wù) AOP。它會注冊事務(wù)管理相關(guān)的后置處理器,檢測 @Transactional 并在運行時生成代理。提供模塊: Spring Tx。

使用示例:

@Configuration
@EnableTransactionManagement
public class TxConfig {
    @Bean
    public PlatformTransactionManager txManager(DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource); // 配置事務(wù)管理器
    }
}

上例通過 @EnableTransactionManagement 啟用了注解驅(qū)動的事務(wù)管理,并顯式聲明了數(shù)據(jù)源事務(wù)管理器 Bean。在 Spring Boot 中,如果引入了 spring-boot-starter-jdbc 或 JPA,會自動配置 DataSourceTransactionManagerJpaTransactionManager,且默認(rèn)啟用事務(wù)支持,無需手動添加該注解(Boot 會自動應(yīng)用)。但在需要更細粒度控制事務(wù)行為時,了解此注解的作用仍然重要。

@Query

簡介: @Query 注解由 Spring Data JPA 提供(org.springframework.data.jpa.repository.Query),用于在 Repository 方法上定義自定義的 JPQL或原生SQL 查詢。

作用與場景: 雖然 Spring Data JPA 可以通過解析方法名自動生成查詢,但是復(fù)雜或特殊的查詢可以用 @Query 手工編寫JPQL語句。還可以通過設(shè)置 nativeQuery=true 使用原生SQL。當(dāng)自動生成無法滿足需求,或為了性能使用數(shù)據(jù)庫特定查詢時,用此注解非常有用。提供模塊: Spring Data JPA。

使用示例:

public interface UserRepository extends JpaRepository<User, Long> {
    // 使用JPQL查詢
    @Query("SELECT u FROM User u WHERE u.email = ?1")
    User findByEmail(String email);
    // 使用原生SQL查詢
    @Query(value = "SELECT * FROM users u WHERE u.status = :status LIMIT :limit", nativeQuery = true)
    List<User> findTopByStatus(@Param("status") int status, @Param("limit") int limit);
}

在上面的倉庫接口中:

  • findByEmail 方法使用 JPQL 查詢根據(jù)郵箱獲取用戶。?1 表示第一個參數(shù)。
  • findTopByStatus 方法使用原生SQL查詢指定狀態(tài)的用戶若干條,使用命名參數(shù) :status:limit。需要搭配 @Param 注解綁定參數(shù)值。

Spring Data JPA 在運行時會解析這些注解并生成相應(yīng)實現(xiàn)代碼執(zhí)行查詢。@Query 能大大提升查詢的靈活性,但要注意JPQL語句的正確性以及原生SQL的可移植性。

八、面向切面編程(AOP)注解

Spring AOP 提供了強大的面向切面編程功能,可以通過注解定義橫切關(guān)注點,如日志記錄、性能監(jiān)控、權(quán)限檢查等。主要的 AOP 注解包括:

@Aspect

簡介: @Aspect 注解用于將一個類聲明為切面類。由 AspectJ 提供(Spring AOP 使用 AspectJ 注解風(fēng)格)。標(biāo)記為 @Aspect 的類內(nèi)部可以定義切點和通知,實現(xiàn) AOP 功能。需要配合 Spring AOP 使用。

作用與場景: 切面類匯總了橫切邏輯,例如日志切面、安全切面等。一個切面類里通常包含若干通知方法(@Before、@After等)和切點定義(@Pointcut)。Spring 在運行時會根據(jù)切面定義生成代理對象,將橫切邏輯織入目標(biāo)對象的方法調(diào)用。提供模塊: org.aspectj.lang.annotation.Aspect(需要 spring-boot-starter-aop 或 Spring AOP 模塊依賴)。

使用示例:

@Aspect
@Component  // 切面本身也需注冊為Bean
public class LoggingAspect {
    // 切點定義:匹配 service 包下所有類的公共方法
    @Pointcut("execution(public * com.example.service..*(..))")
    public void serviceMethods() {}
    // 前置通知:在滿足切點的方法執(zhí)行之前執(zhí)行
    @Before("serviceMethods()")
    public void logBefore(JoinPoint joinPoint) {
        System.out.println("Entering: " + joinPoint.getSignature());
    }
    // 后置通知:無論方法正?;虍惓=Y(jié)束都會執(zhí)行
    @After("serviceMethods()")
    public void logAfter(JoinPoint joinPoint) {
        System.out.println("Exiting: " + joinPoint.getSignature());
    }
}

上面定義了一個日志切面類 LoggingAspect

  • 使用 @Aspect 標(biāo)記為切面類,結(jié)合 @Component 使其成為 Spring Bean。
  • serviceMethods() 方法使用 @Pointcut 定義了一個切點,表達式 "execution(public * com.example.service..*(..))" 表示匹配 com.example.service 包及子包下所有類的任意公共方法執(zhí)行。切點方法本身沒有實現(xiàn),僅作標(biāo)識。
  • logBefore 方法使用 @Before("serviceMethods()") 注解,表示在執(zhí)行匹配 serviceMethods() 切點的任意方法之前,先執(zhí)行該通知。
  • 通過 JoinPoint 參數(shù)可以獲取被調(diào)用方法的信息。logAfter 方法使用 @After("serviceMethods()"),表示目標(biāo)方法執(zhí)行完成后(無論成功與否)執(zhí)行。輸出方法簽名的退出日志。

為使上述 AOP 生效,需要啟用 Spring 對 AspectJ 切面的支持。Spring Boot 自動配置已經(jīng)啟用了 AOP(如果引入了 starter-aop,默認(rèn)會開啟 @AspectJ 支持),在非 Boot 環(huán)境可能需要在配置類上添加 @EnableAspectJAutoProxy 注解來開啟代理機制。如果未啟用,@Aspect 注解不會生效??傊?,@Aspect 注解的類定義了 AOP 的橫切邏輯,是實現(xiàn)日志、事務(wù)、權(quán)限等橫切關(guān)注點的關(guān)鍵。

@Pointcut

簡介: @Pointcut 用于定義一個切點表達式,以命名方式重用切點。由 AspectJ 注解提供。通常是一個簽名為 void 且無實現(xiàn)的方法注解,用于給切點命名。

作用與場景: 切點定義了哪些連接點(Join Point)需要織入切面邏輯。通過@Pointcut可以將復(fù)雜的切點表達式進行抽象,方便在多個通知上引用,避免重復(fù)書寫表達式。提供模塊: AspectJ。

使用示例:

@Aspect
@Component
public class SecurityAspect {
    // 切點:controller 包下的所有含 @GetMapping 注解的方法
    @Pointcut("within(@org.springframework.web.bind.annotation.RestController *) && @annotation(org.springframework.web.bind.annotation.GetMapping)")
    public void allGetEndpoints() {}
    @Before("allGetEndpoints()")
    public void checkAuthentication() {
        // 執(zhí)行權(quán)限驗證邏輯
        if (!SecurityContext.isAuthenticated()) {
            throw new SecurityException("User not authenticated");
        }
    }
}

此處,SecurityAspect 定義了一個切點 allGetEndpoints(),通過 @Pointcut 注解的表達式指定:凡是標(biāo)注了@RestController的類中,標(biāo)注了@GetMapping的方法,都是切點。然后在 @Before("allGetEndpoints()") 通知中引用這個切點,執(zhí)行權(quán)限檢查。如果當(dāng)前用戶未認(rèn)證則拋出異常阻止方法執(zhí)行。

切點表達式語言十分豐富,可以基于執(zhí)行方法簽名(execution)、注解(@annotation, within 等)、this/target對象等進行匹配組合。通過適當(dāng)?shù)那悬c定義,可以靈活地選擇哪些點應(yīng)用橫切邏輯。

@Before

簡介: @Before 定義一個前置通知(Advice),即在目標(biāo)方法執(zhí)行之前執(zhí)行的切面方法。它由 AspectJ 提供(org.aspectj.lang.annotation.Before)。需要在 @Aspect 切面類中使用,注解的值是一個切點表達式或命名切點。

作用與場景: 前置通知通常用于在方法調(diào)用前執(zhí)行一些檢查、日志或準(zhǔn)備工作。例如權(quán)限驗證(見上例)、記錄方法開始日志、在方法執(zhí)行前設(shè)置環(huán)境(如初始化 ThreadLocal)等。在目標(biāo)方法之前執(zhí)行,不影響目標(biāo)方法參數(shù)和執(zhí)行結(jié)果,只作附加操作。

使用示例: 參考前述 LoggingAspectSecurityAspect 中的 @Before 用法。在 LoggingAspect 中:

@Before("serviceMethods()")
public void logBefore(JoinPoint joinPoint) { ... }

這表示在匹配 serviceMethods() 切點的每個目標(biāo)方法執(zhí)行前調(diào)用 logBefore 方法。JoinPoint 參數(shù)可以獲取方法簽名、參數(shù)等信息,用于日志輸出。

@Before 通知不能阻止目標(biāo)方法執(zhí)行(除非拋出異常)。如果在通知中拋異常,目標(biāo)方法將不會執(zhí)行且異常向上拋出。因此一般前置通知不故意拋異常(權(quán)限驗證除外,驗證失敗則通過異常中斷執(zhí)行)。

@After

簡介: @After 定義一個后置通知,即在目標(biāo)方法執(zhí)行結(jié)束后執(zhí)行的切面方法,無論目標(biāo)方法正常返回還是拋出異常都會執(zhí)行(類似 finally block)。由 AspectJ 提供。

作用與場景: 常用于清理資源、記錄方法結(jié)束日志等操作。例如在方法完成后記錄執(zhí)行時間(需要結(jié)合開始時間),或確保某些線程上下文數(shù)據(jù)被清除。不關(guān)心方法的結(jié)果,只要離開方法就執(zhí)行通知。

使用示例: 參考 LoggingAspect 中:

@After("serviceMethods()")
public void logAfter(JoinPoint joinPoint) { ... }

不管 serviceMethods() 匹配的方法成功或異常返回,都會執(zhí)行 logAfter。可以用它來打印離開方法的日志。

如果需要根據(jù)方法是否拋異常做區(qū)分,可以使用 @AfterReturning@AfterThrowing(詳見下文)。@After 通常用來放置最終執(zhí)行的操作,比如解鎖資源,不管成功失敗都要執(zhí)行的。

@AfterReturning

簡介: @AfterReturning 定義一個返回通知,在目標(biāo)方法成功返回后執(zhí)行(未拋異常)。可以捕獲返回值。由 AspectJ 提供。

作用與場景: 當(dāng)需要獲取目標(biāo)方法的返回結(jié)果進行處理時,可使用 @AfterReturning。例如日志中記錄返回值,或者根據(jù)返回值做后續(xù)動作。若目標(biāo)方法拋異常則不會執(zhí)行此通知。注解可指定 returning 屬性綁定返回值。

使用示例:

@AfterReturning(pointcut = "execution(* com.example.service.OrderService.placeOrder(..))", returning = "result")
public void logOrderResult(Object result) {
    System.out.println("Order placed result: " + result);
}

此通知針對 OrderService.placeOrder 方法執(zhí)行,如果其正常完成,則將返回值綁定到 result 形參并打印日志。比如 result 可能是訂單ID或確認(rèn)對象。若 placeOrder 拋異常,則該通知不執(zhí)行。

@AfterThrowing

簡介: @AfterThrowing 定義一個異常通知,在目標(biāo)方法拋出指定異常后執(zhí)行。由 AspectJ 提供??刹东@異常對象。

作用與場景: 用于統(tǒng)一處理或記錄目標(biāo)方法拋出的異常,例如記錄錯誤日志、發(fā)送告警等??梢灾付?throwing 屬性將異常綁定到參數(shù)。只在有未捕獲異常時執(zhí)行,正常返回不執(zhí)行。

使用示例:

@AfterThrowing(pointcut = "execution(* com.example..*.*(..))", throwing = "ex")
public void logException(Exception ex) {
    System.err.println("Exception in method: " + ex.getMessage());
}

該切面方法會在應(yīng)用中任何未捕獲的異常拋出時執(zhí)行,打印異常信息。ex 參數(shù)即目標(biāo)方法拋出的異常對象(可以指定具體異常類型過濾,如 throwing="ex" throwing=RuntimeException.class)。

通過 @AfterThrowing 可以集中處理異常情況,例如對特定異常進行額外處理(如事務(wù)補償或資源回收),或統(tǒng)一記錄。

@Around

簡介: @Around 定義一個環(huán)繞通知,它包裹了目標(biāo)方法的執(zhí)行。由 AspectJ 提供。環(huán)繞通知最為強大,可以在方法執(zhí)行前后都進行處理,并可決定是否、如何執(zhí)行目標(biāo)方法(通過 ProceedingJoinPoint 調(diào)用)。

作用與場景: 可以用來計算執(zhí)行時間、控制方法執(zhí)行(比如實現(xiàn)自定義注解的權(quán)限校驗并決定是否調(diào)用原方法)、修改方法的返回值甚至攔截異常。@Around 通知需要顯式調(diào)用 proceed() 才會執(zhí)行目標(biāo)方法,如果不調(diào)用則目標(biāo)方法不執(zhí)行。這讓我們有機會在調(diào)用前后插入邏輯,甚至改變執(zhí)行流程。

使用示例:

@Around("execution(* com.example.service.*.*(..))")
public Object measureExecutionTime(ProceedingJoinPoint pjp) throws Throwable {
    long start = System.currentTimeMillis();
    Object result;
    try {
        result = pjp.proceed(); // 執(zhí)行目標(biāo)方法
    } finally {
        long end = System.currentTimeMillis();
        System.out.println(pjp.getSignature() + " executed in " + (end - start) + "ms");
    }
    return result;
}

這個環(huán)繞通知為 service 包下所有方法計算執(zhí)行時間:

  • 在調(diào)用目標(biāo)方法前記錄開始時間。
  • 通過 pjp.proceed() 執(zhí)行目標(biāo)方法,將返回結(jié)果保存。
  • 方法執(zhí)行后計算時間差并打印。
  • 將目標(biāo)方法的返回值返回,保證調(diào)用流程正常進行。

如果目標(biāo)方法拋異常,proceed() 會拋出異常到外層(如上例沒有 catch,finally執(zhí)行后異常繼續(xù)拋出)。也可以在環(huán)繞通知中捕獲異常并處理,甚至返回替代結(jié)果,從而吞掉異常(視業(yè)務(wù)需要謹(jǐn)慎處理)。

@Around 通知還可以實現(xiàn)諸如自定義注解攔截功能,例如檢查方法上是否有某注解,有則執(zhí)行特殊邏輯等,靈活性最高。

@EnableAspectJAutoProxy

簡介: @EnableAspectJAutoProxy 是 Spring 提供的注解(org.springframework.context.annotation.EnableAspectJAutoProxy),用于開啟基于注解的 AOP 支撐。它會啟用 AspectJ 注解的自動代理機制。

作用與場景: 在純 Spring 配置中,需要在配置類上添加此注解才能使前述 @Aspect 切面生效(等同于 XML 配置中的 <aop:aspectj-autoproxy/>)。Spring Boot 在引入 AOP 起步依賴時,默認(rèn)已經(jīng)啟用了該功能 ,因此多數(shù)情況下無需顯式添加。但了解這個注解有助于在需要調(diào)整 AOP 代理選項時使用(比如 proxyTargetClass=true 強制使用CGLIB代理)。

使用示例:

@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class AopConfig {
    // 切面類Bean或通過@Component掃描切面類
}

這將在容器中搜索 @Aspect 注解的類,自動創(chuàng)建代理。proxyTargetClass=true 強制使用類代理而不是接口代理。默認(rèn)為 false,即如果有實現(xiàn)接口則用JDK動態(tài)代理。這一點在需要代理沒有接口的類或者希望統(tǒng)一使用CGLIB代理時可以設(shè)置。

總結(jié)而言,Spring AOP 的注解允許我們以聲明方式實現(xiàn)橫切邏輯,將日志、性能監(jiān)控、安全檢查等與業(yè)務(wù)代碼分離,提升模塊化和可維護性。

九、異步與定時任務(wù)注解

Spring 提供了對多線程異步任務(wù)和定時調(diào)度的支持,只需通過注解即可開啟這些功能。

@Async

簡介: @Async 注解用于將某個方法聲明為異步執(zhí)行。由 Spring 提供(org.springframework.scheduling.annotation.Async)。標(biāo)注該注解的方法會在調(diào)用時由 Spring 異步執(zhí)行,而不是同步阻塞當(dāng)前線程。通常需要配合 @EnableAsync 一起使用。

作用與場景: 當(dāng)某些操作不需要同步完成、可以在后臺線程執(zhí)行時,用 @Async 能簡化并發(fā)編程。例如發(fā)送郵件、短信通知,執(zhí)行耗時的計算而不阻塞主流程,或并行調(diào)用多個外部服務(wù)等。Spring 會基于 TaskExecutor (默認(rèn)SimpleAsyncTaskExecutor)調(diào)度異步方法。方法可以返回 voidFuture/CompletableFuture 以便獲取結(jié)果。

使用示例:

@Service
public class NotificationService {
    @Async
    public void sendEmail(String to, String content) {
        // 模擬發(fā)送郵件的耗時操作
        try {
            Thread.sleep(5000);
            System.out.println("Email sent to " + to);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
}
@SpringBootApplication
@EnableAsync  // 開啟異步支持
public class MyApp { ... }

NotificationService 中,sendEmail 標(biāo)注了 @Async,因此當(dāng)它被調(diào)用時,Spring 會從線程池中拿出一個線程來異步執(zhí)行該方法,原調(diào)用方線程不必等待5秒。需要在應(yīng)用主類或配置類上添加 @EnableAsync 以激活異步處理能力。使用默認(rèn)配置時,Spring 會使用一個簡單線程池執(zhí)行,也可以通過定義 Executor Bean 并加上 @Async("beanName") 來指定特定線程池。

調(diào)用異步方法示例:

@RestController
public class OrderController {
    @Autowired
    private NotificationService notificationService;
    @PostMapping("/order")
    public ResponseEntity<String> placeOrder(@RequestBody Order order) {
        orderService.process(order);
        // 異步發(fā)送通知
        notificationService.sendEmail(order.getEmail(), "Your order is placed.");
        return ResponseEntity.ok("Order received");
    }
}

placeOrder 方法調(diào)用了 sendEmail,因為后者是異步的,所以 placeOrder 在觸發(fā)郵件發(fā)送后會立即返回響應(yīng),郵件發(fā)送在另一個線程進行,不影響接口響應(yīng)時間。異步調(diào)用的異常需特別處理,可以使用 AsyncUncaughtExceptionHandler 或返回 Future 在調(diào)用方監(jiān)聽??傊?code>@Async 大大方便了將任務(wù)異步化。

@EnableAsync

簡介: @EnableAsync 是 Spring 提供的注解(org.springframework.scheduling.annotation.EnableAsync),用于開啟對 @Async 注解的處理。加在配置類或主啟動類上,激活 Spring 異步方法執(zhí)行的能力。

作用與場景: 類似于 @EnableAspectJAutoProxy 之于 AOP,對于異步也需要顯式開啟。Spring Boot 自動配置通常不會主動開啟異步,所以需要開發(fā)者添加此注解。提供模塊: Spring Context 調(diào)度任務(wù)支持。

使用示例: 見上方,將 @EnableAsync 放在 @SpringBootApplication 類上或獨立的配置類上均可。

啟用后,Spring 容器會搜索應(yīng)用中標(biāo)注了 @Async 的 Bean 方法,并通過代理的方式調(diào)用線程池執(zhí)行它們。默認(rèn)的執(zhí)行器可以通過定義 TaskExecutor Bean 來覆蓋。如:

@Bean(name = "taskExecutor")
public Executor taskExecutor() {
    ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
    executor.setCorePoolSize(5);
    executor.setMaxPoolSize(10);
    executor.initialize();
    return executor;
}

定義名為 “taskExecutor” 的執(zhí)行器后,Spring @Async 會自動使用它(因為默認(rèn)執(zhí)行器名稱就是 taskExecutor)。也可在 @Async 注解的參數(shù)中指定一個自定義執(zhí)行器 Bean 名稱。

@Scheduled

簡介: @Scheduled 注解用于將方法標(biāo)記為定時任務(wù)。由 Spring 提供(org.springframework.scheduling.annotation.Scheduled)??梢酝ㄟ^ cron 表達式或固定間隔等配置何時運行該方法。需要配合 @EnableScheduling 開啟調(diào)度支持。

作用與場景: 當(dāng)需要周期性地執(zhí)行某段代碼時,例如每隔一段時間檢查庫存,每天夜間生成報表等,可以使用 @Scheduled 注解而不需要借助外部的調(diào)度框架。Spring 容器會在后臺線程按指定計劃調(diào)用這些方法。支持多種調(diào)度配置:

  • cron 表達式:通過 Cron 定義復(fù)雜時間計劃。
  • 固定速率 fixedRate:以上一次開始時間為基準(zhǔn),間隔固定毫秒執(zhí)行。
  • 固定延遲 fixedDelay:以上一次完成時間為基準(zhǔn),延遲固定毫秒執(zhí)行。
  • 可選屬性如 initialDelay 等設(shè)置啟動延遲。

使用示例:

@Component
public class ReportTask {
    @Scheduled(cron = "0 0 2 * * ?")
    public void generateDailyReport() {
        // 每天凌晨2點生成報告
        System.out.println("Generating daily report at " + LocalDate.now());
        // ... 報表生成邏輯
    }
    @Scheduled(fixedRate = 60000)
    public void checkSystemHealth() {
        // 每隔60秒檢查系統(tǒng)健康
        System.out.println("Health check at " + Instant.now());
        // ... 健康檢查邏輯
    }
}

這里,ReportTask 類中:

  • generateDailyReport() 使用 cron="0 0 2 * * ?",表示每天2:00執(zhí)行(Cron表達式:“秒 分 時 日 月 周”,“?”表示不指定周幾)。這個方法將在主線程之外的調(diào)度線程按計劃調(diào)用。
  • checkSystemHealth() 使用 fixedRate=60000 表示每60秒執(zhí)行一次,不論上次執(zhí)行多長時間,都按固定頻率觸發(fā)。若上次尚未執(zhí)行完,新周期到了默認(rèn)不會并發(fā)執(zhí)行(調(diào)度器會等待),但可以通過配置 Scheduler 實現(xiàn)并發(fā)。

為了使 @Scheduled 生效,需要在配置類上添加 @EnableScheduling(見下文)。Spring Boot 應(yīng)用通常也需要手動加這一注解。定時任務(wù)執(zhí)行由 Spring 的 TaskScheduler(默認(rèn)SingleThreadScheduler)驅(qū)動,可能需要注意任務(wù)不應(yīng)長時間阻塞,否則會影響后續(xù)任務(wù)調(diào)度??勺远x線程池 TaskScheduler 以提高并發(fā)度。

@EnableScheduling

簡介: @EnableScheduling 注解用于開啟 Spring 對定時任務(wù)調(diào)度的支持(org.springframework.scheduling.annotation.EnableScheduling)。添加在配置類或主類上。

作用與場景: 沒有這個注解,@Scheduled 等注解不會被識別處理。啟用后,Spring 容器會啟動一個調(diào)度線程池,定時調(diào)用標(biāo)記的方法。提供模塊: Spring Context 定時任務(wù)支持。

使用示例:

@SpringBootApplication
@EnableScheduling
public class Application { ... }

@EnableScheduling 放在啟動類上即可激活調(diào)度機制。然后所有 @Scheduled 注解的方法都會按照配置的計劃執(zhí)行。Spring Boot 不會自動開啟定時任務(wù)支持,因為有的應(yīng)用可能不需要調(diào)度功能,所以必須顯式聲明。

如果需要自定義調(diào)度器,可以定義 Scheduler Bean 或 TaskScheduler Bean。默認(rèn)使用單線程執(zhí)行所有定時任務(wù),若多個任務(wù)需要并行,建議提供 ThreadPoolTaskScheduler Bean。

通過 @Async@Scheduled 這組注解,Spring 讓并發(fā)編程和任務(wù)調(diào)度變得非常容易,不再需要顯式創(chuàng)建線程或使用外部調(diào)度平臺,在應(yīng)用內(nèi)部即可完成這些邏輯。

十、緩存注解

Spring 提供了便捷的緩存機制,通過注解即可實現(xiàn)方法級緩存,把方法調(diào)用結(jié)果存儲起來,避免重復(fù)計算或數(shù)據(jù)庫查詢。

@EnableCaching

簡介: @EnableCaching 注解用于開啟 Spring 對緩存注解的支持(org.springframework.cache.annotation.EnableCaching)。通常加在配置類或主類上,激活緩存管理能力。

作用與場景: 開啟后,Spring 會自動配置一個緩存管理器(可基于內(nèi)存、EhCache、Redis等,取決于依賴配置),并掃描應(yīng)用中的緩存注解(如 @Cacheable 等),在運行時用AOP代理實現(xiàn)緩存邏輯。提供模塊: Spring Cache。

使用示例:

@SpringBootApplication
@EnableCaching
public class Application { ... }

這樣,Spring Boot 就會自動根據(jù) classpath 中的緩存庫選擇緩存實現(xiàn)(如有 spring-boot-starter-cache 默認(rèn)用 ConcurrentMapCache 簡單實現(xiàn);如果引入 spring-boot-starter-redis 則使用 RedisCacheManager 等)。確保在使用緩存注解前調(diào)用了 @EnableCaching,否則緩存注解不會生效。

@Cacheable

簡介: @Cacheable 用于標(biāo)記方法,將其返回結(jié)果緩存起來。由 Spring 提供(org.springframework.cache.annotation.Cacheable)。再次調(diào)用該方法時,如果傳入?yún)?shù)相同且緩存中有結(jié)果,則直接返回緩存而不執(zhí)行方法。

作用與場景: 典型用于讀取操作緩存,例如從數(shù)據(jù)庫查詢數(shù)據(jù)后緩存,下次查詢相同參數(shù)可以直接返回緩存值,提高性能。@Cacheable 需要指定緩存的名稱(cacheName)以及緩存鍵(key),可以是 SpEL 表達式。默認(rèn)鍵根據(jù)所有參數(shù)自動生成(需參數(shù)可哈希)。

提供模塊: Spring Cache。

使用示例:

@Service
public class ProductService {
    @Cacheable(value = "products", key = "#id")
    public Product getProductById(Long id) {
        // 假設(shè)這里有復(fù)雜計算或慢速數(shù)據(jù)庫查詢
        System.out.println("Loading product " + id + " from DB...");
        return productRepository.findById(id).orElse(null);
    }
}

配置 @Cacheable(value="products", key="#id")

  • value 指定緩存的名字叫 “products”(類似分類,可對應(yīng)不同緩存存儲)。
  • key="#id" 表示使用方法參數(shù) id 作為緩存鍵。

第一次調(diào)用 getProductById(1L) 時,會打印“Loading product 1 from DB…”并查詢數(shù)據(jù)庫,然后結(jié)果緩存到名為 “products” 的緩存中,鍵為 1。第二次調(diào)用 getProductById(1L),Spring 檢測到相同鍵在緩存中有值,直接返回緩存,不執(zhí)行方法主體,因此不會再打印那條日志。

@Cacheable 還有一些屬性:

  • condition:滿足條件時才緩存或才查緩存,如 condition="#id > 10".
  • unless:方法執(zhí)行完后判斷,如果滿足條件則不緩存結(jié)果,如 unless="#result == null".
  • sync:是否在并發(fā)場景下同步,只讓一個線程計算緩存,其它等待。

@CachePut

簡介: @CachePut 注解用于將方法返回值直接放入緩存,但與 @Cacheable 不同的是,它始終執(zhí)行方法,不會跳過。它通常用于更新緩存數(shù)據(jù)。由 Spring 提供。

作用與場景: 當(dāng)執(zhí)行了修改操作后,希望緩存與數(shù)據(jù)庫同步更新,可使用 @CachePut 標(biāo)記修改方法,使其結(jié)果及時寫入緩存。這樣后續(xù)再讀緩存可以得到最新值。提供模塊: Spring Cache。

使用示例:

@CachePut(value = "products", key = "#product.id")
public Product updateProduct(Product product) {
    System.out.println("Updating product " + product.getId());
    return productRepository.save(product);
}

每次調(diào)用 updateProduct,都會執(zhí)行保存操作并返回更新后的 Product。@CachePut 注解確保無論如何,這個返回的 Product 對象會以其 id 作為鍵,存入 “products” 緩存(覆蓋舊值)。因此,即便之前通過 @Cacheable 緩存過舊的 Product 數(shù)據(jù),這里也會更新緩存,使之與數(shù)據(jù)庫一致。值得注意的是,@CachePut 不會影響方法執(zhí)行(總會執(zhí)行方法),它只是在返回后把結(jié)果寫緩存。

@CacheEvict

簡介: @CacheEvict 注解用于移除緩存。標(biāo)記在方法上,可以在方法執(zhí)行前或后將指定 key 或整個緩存清除。由 Spring 提供。

作用與場景: 當(dāng)數(shù)據(jù)被刪除或改變且緩存不再有效時,需要清除緩存。例如刪除一個記錄后,需要把對應(yīng)緩存刪掉;批量更新后,可以選擇清空整個緩存。@CacheEvict 支持指定 key 或設(shè)置 allEntries=true 清空整個命名緩存。提供模塊: Spring Cache。

使用示例:

@CacheEvict(value = "products", key = "#id")
public void deleteProduct(Long id) {
    System.out.println("Deleting product " + id);
    productRepository.deleteById(id);
}

調(diào)用 deleteProduct(5) 時,@CacheEvict 會使緩存 “products” 中鍵為5的條目無效(刪除)。默認(rèn)地,它在方法成功執(zhí)行后清除緩存。如果希望無論方法是否成功都清除,可設(shè)定 beforeInvocation=true,那將在方法進入時就清除(防止方法拋異常緩存未清)。allEntries=true 則可以不顧鍵,直接清空整個緩存空間。例如:

@CacheEvict(value = "products", allEntries = true)
public void refreshAllProducts() { ... }

會清除 “products” 緩存的所有條目。

通過 @CacheEvict@CachePut,我們可以維護緩存與底層數(shù)據(jù)的一致性。

注意: 使用緩存注解要求配置正確的 CacheManager 和緩存存儲。Spring Boot 默認(rèn)使用簡單的內(nèi)存緩存(ConcurrentMapCacheManager)用于開發(fā)測試。生產(chǎn)中常結(jié)合 Redis、Ehcache等實現(xiàn),更換實現(xiàn)通常無需改動注解,只需配置 CacheManager Bean。

十一、事件監(jiān)聽注解

Spring 提供了應(yīng)用內(nèi)事件發(fā)布-訂閱機制,支持松耦合的消息通信。通過注解可以方便地訂閱事件。

@EventListener

簡介: @EventListener 是 Spring 4.2+ 引入的注解(org.springframework.context.event.EventListener),用于將任意 Spring Bean 的方法標(biāo)識為事件監(jiān)聽器。當(dāng)有匹配的事件發(fā)布時(實現(xiàn) ApplicationEvent 或自定義事件對象),該方法會被調(diào)用。相比實現(xiàn) ApplicationListener 接口,注解方式更簡潔。

作用與場景: 在應(yīng)用內(nèi),不同組件之間可以通過發(fā)布事件進行解耦通訊。例如用戶注冊后發(fā)布一個 UserRegisteredEvent,由其他監(jiān)聽器監(jiān)聽來發(fā)送歡迎郵件或統(tǒng)計指標(biāo)。使用 @EventListener,方法簽名定義了它感興趣的事件類型,也可以通過 condition 屬性設(shè)置過濾條件(比如只處理某字段滿足條件的事件)。提供模塊: Spring Context 事件機制。

使用示例:

// 定義事件類(可以繼承 ApplicationEvent 也可以是普通類)
public class UserRegisteredEvent /* extends ApplicationEvent */ {
    private final User user;
    public UserRegisteredEvent(User user) { this.user = user; }
    public User getUser() { return user; }
}
// 發(fā)布事件的組件
@Service
public class UserService {
    @Autowired 
    private ApplicationEventPublisher eventPublisher;
    public void register(User user) {
        // ... 保存用戶邏輯
        // 發(fā)布事件
        eventPublisher.publishEvent(new UserRegisteredEvent(user));
    }
}
// 監(jiān)聽事件的組件
@Component
public class WelcomeEmailListener {
    @EventListener
    public void handleUserRegistered(UserRegisteredEvent event) {
        User newUser = event.getUser();
        // 發(fā)送歡迎郵件
        System.out.println("Sending welcome email to " + newUser.getEmail());
        // ... 實際發(fā)送郵件邏輯
    }
}

流程說明:

  • UserService.register 方法在新用戶注冊成功后,通過 ApplicationEventPublisher 發(fā)布了一個 UserRegisteredEvent 事件。Spring Boot 默認(rèn)通過 ApplicationEventPublisher 將事件發(fā)布到應(yīng)用上下文。
  • WelcomeEmailListener 是一個普通組件(被 @Component 掃描)。其中方法 handleUserRegistered 標(biāo)注了 @EventListener,且參數(shù)是 UserRegisteredEvent。這表明它訂閱此類型事件。當(dāng)事件被發(fā)布時,Spring 檢測到存在匹配的監(jiān)聽方法,便調(diào)用該方法并將事件對象傳入。
  • 監(jiān)聽方法運行,完成發(fā)送歡迎郵件的功能。

這樣,發(fā)送郵件的邏輯和用戶服務(wù)邏輯完全解耦,只通過事件聯(lián)系。如果以后不需要發(fā)送郵件,只需移除監(jiān)聽器,而不影響用戶注冊流程。另外,可以很容易地新增其它監(jiān)聽,如統(tǒng)計注冊用戶數(shù)的監(jiān)聽器,而不需要修改 UserService。

@EventListener 還支持 condition 屬性使用 SpEL 表達式進行事件內(nèi)容過濾。例如:

@EventListener(condition = "#event.user.vip")
public void handleVipUserRegistered(UserRegisteredEvent event) { ... }

僅當(dāng)用戶是VIP時才處理。這種細粒度控制進一步增強了事件機制的靈活性。

需要注意,默認(rèn)事件監(jiān)聽器在發(fā)布線程內(nèi)同步執(zhí)行。如果想異步處理事件,可以結(jié)合 @Async 注解,將監(jiān)聽方法異步執(zhí)行(前提是已啟用 @EnableAsync)。或者使用 Spring 5 提供的 ApplicationEventMulticaster 配置為異步模式。

ApplicationListener 接口 (替代方案)

說明:@EventListener 出現(xiàn)之前,Spring 使用實現(xiàn) ApplicationListener<E> 接口的方式來監(jiān)聽事件。雖然這不是注解,但與事件注解結(jié)合使用時值得一提。任何 Spring Bean 實現(xiàn)了 ApplicationListener<MyEvent>,當(dāng) MyEvent 發(fā)布時其 onApplicationEvent 方法會被調(diào)用。自 Spring 4.2 起推薦使用 @EventListener 代替,更加簡潔。

使用示例:

@Component
public class StatsListener implements ApplicationListener<UserRegisteredEvent> {
    @Override
    public void onApplicationEvent(UserRegisteredEvent event) {
        // 統(tǒng)計用戶注冊
        metrics.increment("user.register.count");
    }
}

這個監(jiān)聽器無須注解,Spring根據(jù)泛型自動注冊。但相比注解方式,它需要一個獨立的類實現(xiàn)接口,不如 @EventListener 可以直接用任意方法方便。而且一個類只能實現(xiàn)對一種事件的監(jiān)聽,要監(jiān)聽多種事件需要寫多個類或使用一些if判斷,不如注解靈活。因此現(xiàn)在開發(fā)中更多使用 @EventListener

綜上,Spring 的事件模型通過發(fā)布訂閱實現(xiàn)了應(yīng)用內(nèi)部的解耦協(xié)作。@EventListener 極大降低了使用門檻,使得監(jiān)聽事件就像寫普通方法一樣便捷。配合異步能力,還能實現(xiàn)類似消息隊列的效果,用于不太關(guān)鍵的異步通知等場景。

十二、測試相關(guān)注解

Spring 為了方便編寫測試,特別是針對 Spring MVC 或 JPA等組件的測試,提供了一系列注解來簡化配置測試上下文。

@SpringBootTest

簡介: @SpringBootTest 是 Spring Boot 測試框架提供的注解(org.springframework.boot.test.context.SpringBootTest),用于在測試類上,表示啟動一個完整的 Spring Boot 應(yīng)用上下文進行集成測試。

作用與場景: 標(biāo)注此注解的測試類在運行時會通過 Spring Boot 引導(dǎo)啟動應(yīng)用(除非配置特定屬性使其部分引導(dǎo)),這意味著:

  • 會掃描并創(chuàng)建所有 Bean,加載完整應(yīng)用上下文。
  • 提供對 Bean 的依賴注入支持,使測試類可以直接 @Autowired 需要的 Bean 進行集成測試。

它常用于需要測試多個層級協(xié)同工作的場景,例如驗證服務(wù)層和倉庫層交互,或者整個請求流程。

使用示例:

@SpringBootTest
class ApplicationTests {
    @Autowired
    private UserService userService;
    @Test
    void testUserRegistration() {
        User user = new User("alice");
        userService.register(user);
        // 驗證注冊結(jié)果,比如檢查數(shù)據(jù)庫或事件發(fā)布效果
        assertNotNull(user.getId());
    }
}

這個測試類使用 @SpringBootTest,則測試運行時 Spring Boot 會啟動應(yīng)用上下文并注入 UserService Bean,測試方法里可以直接調(diào)用業(yè)務(wù)代碼進行驗證。@SpringBootTest 還可以指定啟動端口、環(huán)境等參數(shù),或通過 properties 覆蓋配置,比如:

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)

用于啟動嵌入式服務(wù)器在隨機端口,以進行 Web 集成測試。

@WebMvcTest

簡介: @WebMvcTest 是用于測試 Spring MVC 控制器的注解(org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest)。它會啟動一個精簡的 Spring MVC 環(huán)境,只包含Web相關(guān)的Bean,如@Controller、@RestController等,以及MVC配置,而不加載整個應(yīng)用上下文。

作用與場景: 主要用于單元測試控制器。默認(rèn)只掃描 @Controller@RestController 等 Web 層組件,以及必要的配置(如 Jackson 轉(zhuǎn)換、Validator)。不會加載服務(wù)層、倉庫層Bean,除非通過配置指定。這樣測試運行速度快且聚焦于MVC層邏輯。常配合 MockMvc (Spring提供的模擬MVC請求的工具)使用進行控制器的請求/響應(yīng)測試。

使用示例:

@WebMvcTest(controllers = UserController.class)
class UserControllerTests {
    @Autowired
    private MockMvc mockMvc;
    @MockBean
    private UserService userService;  // 將UserService模擬
    @Test
    void testGetUser() throws Exception {
        User user = new User(1L, "Bob");
        // 定義當(dāng)userService.findById(1)被調(diào)用時返回user對象
        given(userService.findById(1L)).willReturn(user);
        mockMvc.perform(get("/users/1"))
               .andExpect(status().isOk())
               .andExpect(jsonPath("$.name").value("Bob"));
    }
}

此測試類標(biāo)注 @WebMvcTest(UserController.class)

  1. Spring Boot 會僅啟動與 UserController 相關(guān)的 MVC 組件,如 UserController 本身,MVC配置,序列化組件等。
  2. UserService 因為不是@Controller組件,不會自動加載。因此使用了 @MockBean 注解(見后)創(chuàng)建一個模擬的 UserService Bean,將其注入到 UserController 中,避免涉及真實的服務(wù)層邏輯。
  3. 測試使用 MockMvc 發(fā)起GET請求到 /users/1,并斷言返回狀態(tài)200和返回JSON中的name字段為"Bob"。由于我們預(yù)先通過 given(userService.findById(1L)) 指定了模擬行為,所以控制器調(diào)用userService時會得到我們構(gòu)造的user對象。

通過這種方式,不需要啟動整個應(yīng)用,也不需要真實數(shù)據(jù)庫等,就能測試控制器映射、參數(shù)解析、返回結(jié)果等。@WebMvcTest 提供了對Spring MVC各方面的支持(如可以自動配置MockMvc)。

@DataJpaTest

簡介: @DataJpaTest 是用于測試 JPA 持久層的注解(org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest)。它會啟動一個只包含 JPA 相關(guān)組件的 Spring 應(yīng)用上下文,例如實體管理器、Spring Data JPA 倉庫、嵌入式數(shù)據(jù)庫等。

作用與場景: 主要用于單元測試 Repository 層。它會:

  • 配置嵌入式內(nèi)存數(shù)據(jù)庫(如H2)用于測試,除非明確指定其他DataSource。
  • 掃描 @Entity 實體和 Spring Data Repository 接口并注冊。
  • 不加載 web、安全等其他非持久層Bean,以加快測試速度。
  • 默認(rèn)使用事務(wù)包裝每個測試,并在結(jié)束時回滾,保證測試隔離。

使用示例:

@DataJpaTest
class UserRepositoryTests {
    @Autowired
    private UserRepository userRepository;
    @Test
    void testFindByEmail() {
        // 準(zhǔn)備測試數(shù)據(jù)
        User user = new User();
        user.setEmail("test@example.com");
        user.setName("Test");
        userRepository.save(user);
        // 執(zhí)行查詢方法
        User found = userRepository.findByEmail("test@example.com");
        assertEquals("Test", found.getName());
    }
}

這里 @DataJpaTest 將自動配置一個內(nèi)存數(shù)據(jù)庫并初始化 JPA 環(huán)境。UserRepository 接口(假設(shè)繼承自 JpaRepository)會被加載為Bean。測試中先保存一個用戶,然后調(diào)用倉庫自定義方法 findByEmail 驗證結(jié)果。由于測試結(jié)束時事務(wù)會回滾,插入的測試數(shù)據(jù)不會污染下一個測試或?qū)嶋H數(shù)據(jù)庫。

@DataJpaTest 同樣可以與 @MockBean 配合如果需要模擬一些非JPA的Bean,但是通常持久層測試不需要。也可以通過 properties 指定連接真實數(shù)據(jù)庫進行集成測試,不過大多數(shù)情況下,使用內(nèi)存數(shù)據(jù)庫足以測試Repository邏輯。

@MockBean

簡介: @MockBean 是 Spring Boot Test 提供的注解(org.springframework.boot.test.mock.mockito.MockBean),用于在 Spring 測試上下文中添加一個由 Mockito 模擬的Bean,并替換掉容器中原本該類型的Bean(如果有)。常用于在 Web層或服務(wù)層測試中,模擬依賴的Bean行為。

作用與場景: 當(dāng)測試的目標(biāo)Bean有依賴,而我們不想測試依賴的真實邏輯(可能復(fù)雜或不確定),就可以用 @MockBean 來提供一個Mockito創(chuàng)建的模擬對象給容器。這比手工使用 Mockito.mock 然后手動注入更方便,因為 Spring 會自動把這個模擬Bean注入到需要它的地方。典型應(yīng)用是在 @WebMvcTest 中模擬服務(wù)層Bean,在 @SpringBootTest 中模擬外部系統(tǒng)客戶端Bean等。

使用示例:

@MockBean
private WeatherService weatherService;

WeatherService 接口模擬為一個 Bean 注入容器。如果應(yīng)用上下文本來有一個該類型的Bean(比如真實的實現(xiàn)),會被模擬對象替換。這使得我們可以用 given(weatherService.getTodayWeather())... 等來預(yù)設(shè)行為。這個注解可以用在測試類的字段上(如上)、也可以用在測試方法內(nèi)參數(shù)上。

具體的用法在前面的 @WebMvcTest 示例已經(jīng)體現(xiàn)。再比如,在一個服務(wù)層測試中:

@SpringBootTest
class OrderServiceTests {
    @Autowired
    private OrderService orderService;
    @MockBean
    private PaymentClient paymentClient;  // 模擬外部支付服務(wù)客戶端
    @Test
    void testOrderPayment() {
        Order order = new Order(...);
        // 假定調(diào)用外部支付返回成功結(jié)果
        given(paymentClient.pay(order)).willReturn(new PaymentResult(true));
        boolean result = orderService.processPayment(order);
        assertTrue(result);
        // 驗證內(nèi)部行為,如訂單狀態(tài)更新
        // ...
    }
}

這里 OrderService 依賴 PaymentClient,但我們不想真的調(diào)用外部服務(wù),于是用 @MockBean 模擬它并規(guī)定返回 PaymentResult 成功。這樣 OrderService.processPayment 執(zhí)行時實際上用的是假的 PaymentClient,但可以測試 OrderService 自身的邏輯是否正確處理了成功結(jié)果。注意: @MockBean 底層使用 Mockito,所以需要確保引入了 Mockito 相關(guān)依賴。

其他測試注解:

  • @SpringBootTest@WebMvcTest, @DataJpaTest 是 Spring Boot Test 提供的測試切面注解,此外還有類似 @WebFluxTest(測試WebFlux控制器)、@JdbcTest(測試JDBC)、@JsonTest(測試JSON序列化)等,根據(jù)需要使用。
  • JUnit本身的注解如 @Test, @BeforeEach, @AfterEach 等也在測試中大量使用(如上示例已經(jīng)用到 @Test)。雖然不屬于Spring范疇,但也算開發(fā)中常用的注解之一。

通過這些測試注解,開發(fā)者可以方便地編寫隔離的測試用例。例如只啟動Web層或持久層進行單元測試,大大提高測試執(zhí)行速度和定位問題的精準(zhǔn)度。Spring Boot 自動配置為測試裁剪了上下文,避免加載無關(guān)bean,使測試既保持類似生產(chǎn)環(huán)境的行為,又能高效運行。

十三、安全相關(guān)注解

Spring Security 框架提供了方法級安全控制的注解和配置注解,方便對控制器或服務(wù)方法實施權(quán)限檢查。此外還有開啟安全的配置注解等。

@EnableWebSecurity

簡介: @EnableWebSecurity 是用于開啟 Spring Security Web 安全支持的注解(org.springframework.security.config.annotation.web.configuration.EnableWebSecurity)。通常加在一個繼承 WebSecurityConfigurerAdapter(Spring Security 5.7 之前)的配置類上,或者加在包含 SecurityFilterChain Bean 的配置類上。它啟用了 Spring Security 的過濾器鏈。

作用與場景: 使用 Spring Security 時,需要此注解來加載 Web 安全配置,使應(yīng)用受 Spring Security 管理。提供模塊: Spring Security Config。

使用示例:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
            .antMatchers("/admin/**").hasRole("ADMIN")
            .anyRequest().authenticated()
            .and().formLogin();
    }
}

上述經(jīng)典用法在 Spring Security 5.7 之前通過繼承 WebSecurityConfigurerAdapter 來配置。@EnableWebSecurity 注解開啟安全功能。Spring Boot 自動配置也會在引入 starter-security 時添加該注解,因此有時無需手動添加;但當(dāng)我們提供自定義安全配置類時,一般會注明此注解。注意: Spring Security 5.7 開始,官方更推薦不繼承類而是聲明 SecurityFilterChain Bean 配合 @EnableWebSecurity 使用,但注解作用相同。

@EnableGlobalMethodSecurity (已過時) / @EnableMethodSecurity

簡介: @EnableGlobalMethodSecurity 用于開啟方法級安全注解的支持(如 @PreAuthorize, @Secured)。這是 Spring Security 舊版本使用的注解,位于 org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity。它已經(jīng)在 Spring Security 6 被替換為新的 @EnableMethodSecurity@EnableGlobalMethodSecurity 標(biāo)記為已棄用)。

作用與場景: 加在 Security 配置類上,啟用對 @PreAuthorize, @PostAuthorize, @Secured, @RolesAllowed 注解的識別??梢酝ㄟ^其屬性啟用各類注解,如 prePostEnabled=true 支持 Pre/PostAuthorize,securedEnabled=true 支持@Secured,jsr250Enabled=true 支持@RolesAllowed 等。提供模塊: Spring Security Config。

使用示例(舊):

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    // ...
}

這將開啟 @PreAuthorize/@PostAuthorize(因為 prePostEnabled=true) 和 @Secured 注解(因為 securedEnabled=true)。在 Security 6 中,等價的做法是:

@Configuration
@EnableWebSecurity
@EnableMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
public class SecurityConfig { ... }

@EnableMethodSecurity 默認(rèn)就啟用了 Pre/Post,所以可以不用顯式 prePostEnabled,secured和jsr250需要明確true。

總而言之,在當(dāng)前的 Spring Boot 3 / Security 6 環(huán)境中,使用 @EnableMethodSecurity 取代 @EnableGlobalMethodSecurity 來開啟方法安全注解支持。

@PreAuthorize

簡介: @PreAuthorize 是 Spring Security 的方法級權(quán)限注解(org.springframework.security.access.prepost.PreAuthorize)。它可以用在方法或類上,在方法調(diào)用之前基于給定的表達式進行權(quán)限驗證。需要啟用了全局方法安全后(如上),此注解才會生效。

作用與場景: @PreAuthorize 可以檢查當(dāng)前認(rèn)證用戶是否具備某權(quán)限或角色,或者滿足SpEL表達式定義的任意條件,然后才允許方法執(zhí)行。常用于服務(wù)層或控制層方法,保護敏感操作。例如只有ADMIN角色能調(diào)用刪除用戶方法,或者只有資源擁有者才能訪問資源等。它比 @Secured 更強大,因為可以使用Spring EL編寫復(fù)雜的邏輯。

使用示例:

@Service
public class AccountService {
    @PreAuthorize("hasRole('ADMIN')")
    public void deleteAccount(Long accountId) {
        // 只有ADMIN角色用戶才能執(zhí)行
        accountRepository.deleteById(accountId);
    }
    @PreAuthorize("#user.name == authentication.name or hasAuthority('SCOPE_profile')")
    public Profile getUserProfile(User user) {
        // 用戶本人或具有profile權(quán)限的可以查看
        return profileRepository.findByUser(user);
    }
}
  • deleteAccount 方法上,@PreAuthorize("hasRole('ADMIN')") 限制只有具有ROLE_ADMIN的用戶可以調(diào)用,否則會被拒絕(拋出 AccessDeniedException)。getUserProfile 方法上,使用了表達式:#user.name == authentication.name or hasAuthority('SCOPE_profile')authentication.name 代表當(dāng)前登錄用戶名。如果傳入的 user.name 等于當(dāng)前用戶名(即查詢自己的資料),或當(dāng)前主體具有 SCOPE_profile 權(quán)限(例如 OAuth2 scope),則允許訪問。否則拒絕??梢钥吹絇reAuthorize能夠引用方法參數(shù)(通過#參數(shù)名)和安全上下文信息(authentication對象)進行復(fù)雜判斷。

@PreAuthorize 非常靈活,也支持調(diào)用自定義權(quán)限評估方法等。但要注意權(quán)限表達式越復(fù)雜可能越難維護,需要在安全和可讀性之間平衡。Spring Security官方推薦使用PreAuthorize勝過Secured,因為其表達能力更強。

@Secured

簡介: @Secured 是較早的 Spring Security 提供的簡單方法安全注解(org.springframework.security.access.annotation.Secured)。它指定一組允許的角色,調(diào)用該方法的用戶必須具備其中一個角色才行。需要在全局方法安全配置中啟用 securedEnabled=true 才生效。

作用與場景: 適用于簡單的基于角色的訪問控制。如果系統(tǒng)的授權(quán)模型主要基于角色,可以使用 @Secured("ROLE_X") 來保護方法。相對于 PreAuthorize,它不支持復(fù)雜表達式,只能指定角色列表。提供模塊: Spring Security(需要 @EnableMethodSecurity(securedEnabled=true) 或舊的相應(yīng)配置)。

使用示例:

@Secured("ROLE_ADMIN")
public void createUser(User user) { ... }
@Secured({"ROLE_USER", "ROLE_ADMIN"})
public Data getData() { ... }
  • createUser 方法要求調(diào)用者必須擁有 ROLE_ADMIN 角色。
  • getData 方法允許 ROLE_USERROLE_ADMIN 擁有者訪問(邏輯是OR的關(guān)系)。

如果不滿足要求,Spring Security同樣會拋出訪問拒絕異常。@Secured 內(nèi)部實際上也是通過 AOP 攔截,與 @PreAuthorize 實現(xiàn)機制類似,但因為其功能有限,Spring官方更推薦使用Pre/PostAuthorize。

需要留意的是,@Secured 注解中的字符串需要包含完整的角色前綴(如默認(rèn)前綴是 “ROLE_”)。如上必須寫 “ROLE_ADMIN” 而不是 “ADMIN”,除非通過配置修改了前綴策略。

@RolesAllowed

簡介: @RolesAllowed 來自 JSR-250(jakarta.annotation.security.RolesAllowed),功能與 @Secured 類似,也是指定允許訪問方法的角色列表。Spring Security 支持它,需要 jsr250Enabled=true。它和 Secured的區(qū)別主要在注解來源不同。

作用與場景: 可以作為 @Secured 的替代,用標(biāo)準(zhǔn)注解來聲明角色限制。在Spring環(huán)境下兩者效果一樣。提供模塊: JSR-250,Spring Security需啟用支持。

使用示例:

@RolesAllowed("ADMIN")
public void updateSettings(Settings settings) { ... }

這里假設(shè)已將角色前綴配置成無"ROLE_"前綴或 SecurityConfigurer里做了處理,否則 Spring Security會把 “ADMIN” 當(dāng)作角色名直接匹配 GrantedAuthority “ADMIN”。一般Secured和RolesAllowed不能混用不同前綴,否則容易出錯。

綜上,Spring Security提供的這些注解允許我們無需在方法內(nèi)部手動檢查權(quán)限,而由框架自動在調(diào)用前進行驗證,符合條件才執(zhí)行。需要注意:

  • 要在配置類上開啟相應(yīng)支持(使用 @EnableMethodSecurity 或舊版 @EnableGlobalMethodSecurity)。
  • @PreAuthorize/@PostAuthorize 功能最強,但稍復(fù)雜,@Secured/@RolesAllowed簡單直接,但只能基于角色判斷。
  • 這類注解只檢查Spring Security的上下文,對于未經(jīng)過濾器鏈保護的方法調(diào)用(比如同類中自調(diào)用方法不會觸發(fā)注解檢查,或者在無Security環(huán)境下)就不起作用。這是常見陷阱——所以帶有安全注解的方法最好不要在內(nèi)部直接調(diào)用,否則繞過了切面檢查。

十四、其他常用注解

除了上述類別,Spring & Spring Boot 中還有一些常用但未分類到的注解,例如:

  • 參數(shù)校驗相關(guān): Spring 對 JSR 303 Bean Validation 的支持,讓我們可以在模型上使用如 @NotNull, @Size, @Valid 等注解。其中在 Controller 方法參數(shù)上使用 @Valid 可觸發(fā)校驗,并結(jié)合 @ExceptionHandler@ControllerAdvice 統(tǒng)一處理校驗結(jié)果。
  • JSON 序列化控制:@JsonInclude(來自 Jackson)可以注解類或?qū)傩?,控制JSON序列化包含規(guī)則,例如 @JsonInclude(JsonInclude.Include.NON_NULL) 表示忽略null值字段。這在返回REST數(shù)據(jù)時很有用。
  • 條件裝配注解: Spring Boot 提供了一系列 @ConditionalOn... 注解用于自動配置(如 @ConditionalOnProperty, @ConditionalOnClass, @ConditionalOnMissingBean 等)來有條件地裝配Bean。這些主要在開發(fā)Spring Boot自動配置模塊時使用,在應(yīng)用層較少直接用到,但理解它們有助于明白Boot的裝配機制。

以上羅列的注解涵蓋了Spring核心開發(fā)中最常用的部分。從應(yīng)用啟動配置、Bean裝配,到Web層開發(fā)、數(shù)據(jù)持久化、AOP、異步、緩存、事件、測試、安全,各個方面都有簡潔的注解支持。掌握它們的用法能顯著提高開發(fā)效率,減少樣板代碼,讓我們更多關(guān)注業(yè)務(wù)邏輯實現(xiàn)。

總結(jié): Spring & Spring Boot 常用注解極大地便利了開發(fā),它們遵循“約定優(yōu)于配置”的理念,通過簡單的注解聲明即可完成以前繁瑣的XML配置或手動編碼工作。在使用時要注意啟用相應(yīng)功能的開關(guān)(如異步、事務(wù)、緩存等),理解注解背后機制(如AOP代理、運行時處理)以避免踩坑。熟練運用上述注解,能覆蓋大部分日常開發(fā)場景,實現(xiàn)優(yōu)雅、高效和可維護的Spring應(yīng)用。

到此這篇關(guān)于Spring Boot 常用注解整理的文章就介紹到這了,更多相關(guān)Spring Boot 常用注解內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • springboot2.x集成swagger的方法示例

    springboot2.x集成swagger的方法示例

    這篇文章主要介紹了springboot2.x集成swagger的方法示例,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-05-05
  • Mybatis-Plus條件構(gòu)造器的具體使用方法

    Mybatis-Plus條件構(gòu)造器的具體使用方法

    這篇文章主要介紹了Mybatis-Plus條件構(gòu)造器的具體使用方法,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08
  • Java讀取DBF文件(GBK編碼)的方法

    Java讀取DBF文件(GBK編碼)的方法

    在Java開發(fā)中,有時需要讀取DBF(dBase文件)格式的數(shù)據(jù)文件,而這些文件通常采用GBK(簡體中文)編碼,本文將介紹如何使用Java讀取采用GBK編碼的DBF文件,需要的朋友可以參考下
    2024-11-11
  • idea查看class字節(jié)碼的示例代碼

    idea查看class字節(jié)碼的示例代碼

    本文給大家分享三種方法介紹idea查看class字節(jié)碼,每種方法給大家介紹的非常詳細,感興趣的朋友一起看看吧
    2025-04-04
  • spring cloud如何集成nacos配置中心

    spring cloud如何集成nacos配置中心

    這篇文章主要介紹了spring cloud如何集成nacos配置中心操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • Java多線程編程中使用Condition類操作鎖的方法詳解

    Java多線程編程中使用Condition類操作鎖的方法詳解

    Condition是java.util.concurrent.locks包下的類,提供了對線程鎖的更精細的控制方法,下面我們就來看一下Java多線程編程中使用Condition類操作鎖的方法詳解
    2016-07-07
  • @RequestBody注解Ajax post json List集合數(shù)據(jù)請求400/415的處理

    @RequestBody注解Ajax post json List集合數(shù)據(jù)請求400/41

    這篇文章主要介紹了@RequestBody注解Ajax post json List集合數(shù)據(jù)請求400/415的處理方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-10-10
  • java?Date獲取本月的開始時間與結(jié)束時間

    java?Date獲取本月的開始時間與結(jié)束時間

    這篇文章主要為大家介紹了java?Date獲取本月的開始時間與結(jié)束時間示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步早日升職加薪
    2023-05-05
  • Spring?Bean后處理器詳細介紹

    Spring?Bean后處理器詳細介紹

    Bean后置處理器允許在調(diào)用初始化方法前后對Bean進行額外的處理。可以在?Spring容器通過插入一個或多個BeanPostProcessor的實現(xiàn)來完成實例化,配置和初始化一個?bean?之后實現(xiàn)一些自定義邏輯回調(diào)方法
    2023-01-01
  • 使用@Transactional 設(shè)置嵌套事務(wù)不回滾

    使用@Transactional 設(shè)置嵌套事務(wù)不回滾

    這篇文章主要介紹了使用@Transactional 設(shè)置嵌套事務(wù)不回滾問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-07-07

最新評論

曰本无码人妻丰满熟妇啪啪| 2022精品久久久久久中文字幕| 国产精品久久综合久久| 欧美精产国品一二三区| 老司机福利精品视频在线| 亚洲无码一区在线影院| 国产自拍在线观看成人| 91啪国自产中文字幕在线| 成人30分钟免费视频| 亚洲 自拍 色综合图| 亚洲人人妻一区二区三区| 国产大鸡巴大鸡巴操小骚逼小骚逼| 国产亚洲欧美视频网站| 欧美成人综合色在线噜噜| brazzers欧熟精品系列| 久久麻豆亚洲精品av| wwwxxx一级黄色片| 亚洲高清免费在线观看视频| 久久这里只有精彩视频免费| 不戴胸罩引我诱的隔壁的人妻| 91快播视频在线观看| 夜色撩人久久7777| 亚洲1区2区3区精华液| 福利视频网久久91| 扒开腿挺进肉嫩小18禁视频| 适合午夜一个人看的视频| 中文字幕高清免费在线人妻| 国产精品日韩欧美一区二区| 免费观看成年人视频在线观看| 亚洲一级av无码一级久久精品| 天天操天天操天天碰| 亚洲变态另类色图天堂网| 宅男噜噜噜666免费观看| 日本裸体熟妇区二区欧美| 97香蕉碰碰人妻国产樱花| 久久综合老鸭窝色综合久久| 亚洲av无硬久久精品蜜桃| 国产精品手机在线看片| av日韩在线观看大全| 国产成人精品福利短视频| 国产午夜男女爽爽爽爽爽视频| 91国语爽死我了不卡| 五十路丰满人妻熟妇| 亚洲 国产 成人 在线| 日韩美在线观看视频黄| 揄拍成人国产精品免费看视频| 国产超码片内射在线| 97少妇精品在线观看| www天堂在线久久| 亚洲 中文字幕在线 日韩| 天天操天天干天天艹| 男人靠女人的逼视频| 青春草视频在线免费播放| 自拍偷区二区三区麻豆| 久久香蕉国产免费天天| 人妻少妇性色欲欧美日韩| av在线观看网址av| 2025年人妻中文字幕乱码在线| 最新91九色国产在线观看| 在线视频自拍第三页| 动色av一区二区三区| 91色秘乱一区二区三区| 亚洲欧洲一区二区在线观看| 99一区二区在线观看| 啊啊好大好爽啊啊操我啊啊视频| 亚洲中文精品人人免费| 人妻熟女中文字幕aⅴ在线| 亚洲欧美一区二区三区爱爱动图| 涩爱综合久久五月蜜臀| 啪啪啪啪啪啪啪免费视频| 欧洲亚洲欧美日韩综合| 国产福利小视频免费观看| 亚洲一级av无码一级久久精品| 中文字幕无码日韩专区免费| 国产黑丝高跟鞋视频在线播放| 日韩精品二区一区久久| 天天操天天操天天碰| 日本人妻少妇18—xx| AV天堂一区二区免费试看| 日韩不卡中文在线视频网站| 日韩人妻丝袜中文字幕| 激情色图一区二区三区| 麻豆性色视频在线观看| 含骚鸡巴玩逼逼视频| 好吊视频—区二区三区| 在线免费观看日本片| 国产自拍在线观看成人| 黄色录像鸡巴插进去| 久草电影免费在线观看| 深夜男人福利在线观看| 青青青爽视频在线播放| 偷拍自拍 中文字幕| 在线观看免费视频网| 中文字幕人妻一区二区视频| aⅴ五十路av熟女中出| 香港一级特黄大片在线播放| 一级A一级a爰片免费免会员| 日韩影片一区二区三区不卡免费| 人妻少妇中文有码精品| 日日爽天天干夜夜操| 阿v天堂2014 一区亚洲| 欧美成人小视频在线免费看| 欧美熟妇一区二区三区仙踪林| 国产一区成人在线观看视频 | 好吊操视频这里只有精品| 国产精品伦理片一区二区| 日本一二三中文字幕| 亚洲推理片免费看网站| 2021天天色天天干| 午夜精品一区二区三区更新| 中文字幕国产专区欧美激情| 最新中文字幕乱码在线| 亚洲欧美另类自拍偷拍色图| 免费高清自慰一区二区三区网站| 欧美黄片精彩在线免费观看| 成年人啪啪视频在线观看| 黑人借宿ntr人妻的沦陷2| 人人妻人人爽人人添夜| 91精品视频在线观看免费| 色av色婷婷人妻久久久精品高清| 在线免费观看亚洲精品电影| 午夜福利资源综合激情午夜福利资| 国产普通话插插视频| 国产精选一区在线播放| 岛国av高清在线成人在线| 中文字幕 码 在线视频| 亚洲av自拍天堂网| gav成人免费播放| 亚洲中文字幕国产日韩| 欧美日韩情色在线观看| 亚洲综合一区成人在线| 91麻豆精品久久久久| 天天日天天添天天爽| 色婷婷精品大在线观看| 精品黑人一区二区三区久久国产| 超鹏97历史在线观看| 精品亚洲国产中文自在线| 国产男女视频在线播放| 初美沙希中文字幕在线| 中文字幕人妻一区二区视频| 亚洲熟妇久久无码精品| 青青青青青手机视频| 午夜久久久久久久精品熟女| 97欧洲一区二区精品免费| 女生自摸在线观看一区二区三区 | 福利视频网久久91| 久久午夜夜伦痒痒想咳嗽P| 成年人黄色片免费网站| 亚洲综合色在线免费观看| 99久久99久国产黄毛片| 亚洲国产精品久久久久蜜桃| 人妻少妇精品久久久久久| 久草视频在线看免费| 噜噜色噜噜噜久色超碰| 青青青青爽手机在线| 秋霞午夜av福利经典影视| 青娱乐最新视频在线| 国产黄色大片在线免费播放| 伊人综合免费在线视频| 青青色国产视频在线| 日韩欧美在线观看不卡一区二区 | 激情综合治理六月婷婷| 亚洲av日韩精品久久久| 精产国品久久一二三产区区别 | 日本韩国免费一区二区三区视频 | 中文字幕之无码色多多| 欧美一区二区三区久久久aaa| 最新日韩av传媒在线| 国产高清精品极品美女| 后入美女人妻高清在线| 人妻最新视频在线免费观看| 午夜免费体验区在线观看 | 黄页网视频在线免费观看| 亚洲高清国产一区二区三区| 国产janese在线播放| 中文字幕奴隷色的舞台50| 亚洲粉嫩av一区二区三区| 亚洲 图片 欧美 图片| 国产成人综合一区2区| 2012中文字幕在线高清| 精品一线二线三线日本| 九九视频在线精品播放| 亚洲免费国产在线日韩| 青草亚洲视频在线观看| 日韩中文字幕福利av| 亚洲日本一区二区三区| 日本熟妇喷水xxx| 视频在线免费观看你懂得| 国产成人精品久久二区91| 亚洲图库另类图片区| 夜色17s精品人妻熟女| 在线播放一区二区三区Av无码 | 中文字幕日韩精品日本| 亚洲中文字幕综合小综合| 搡老妇人老女人老熟女| 98视频精品在线观看| 国产又粗又硬又猛的毛片视频| caoporm超碰国产| 青青在线视频性感少妇和隔壁黑丝| 日本男女操逼视频免费看| 青青草原色片网站在线观看| 亚洲熟女久久久36d| 2017亚洲男人天堂| 激情伦理欧美日韩中文字幕| 天天干天天操天天玩天天射| 国产第一美女一区二区三区四区 | 熟女少妇激情五十路| www久久久久久久久久久| 亚洲综合自拍视频一区| 久久久精品国产亚洲AV一| 日本三极片中文字幕| 小穴多水久久精品免费看| 黄色中文字幕在线播放| 美女av色播在线播放| 老司机福利精品视频在线| 中国产一级黄片免费视频播放| 热99re69精品8在线播放| 色综合久久无码中文字幕波多| 91欧美在线免费观看| 欧美日韩熟女一区二区三区| 黑人借宿ntr人妻的沦陷2| 欧亚日韩一区二区三区观看视频| av完全免费在线观看av| 91av中文视频在线| 欧美美女人体视频一区| 特大黑人巨大xxxx| 粗大的内捧猛烈进出爽大牛汉子| 欧美精品欧美极品欧美视频| 午夜dv内射一区区| 大陆胖女人与丈夫操b国语高清 | 97年大学生大白天操逼| 亚洲黄色av网站免费播放| 在线视频免费观看网| asmr福利视频在线观看| 欧美在线偷拍视频免费看| 在线制服丝袜中文字幕| 亚洲综合在线观看免费| 中文字幕+中文字幕| 亚洲一级特黄特黄黄色录像片| 久久久久久久久久性潮| 中文字幕AV在线免费看 | 三级av中文字幕在线观看| 女生被男生插的视频网站| 国产+亚洲+欧美+另类| 亚洲最大黄了色网站| 亚洲va国产va欧美精品88| 亚洲欧美综合另类13p| 免费高清自慰一区二区三区网站| 激情图片日韩欧美人妻| 沙月文乃人妻侵犯中文字幕在线| 亚洲特黄aaaa片| 扒开腿挺进肉嫩小18禁视频| 在线不卡日韩视频播放| 自拍偷拍亚洲精品第2页| 99热久久这里只有精品| 亚洲高清一区二区三区视频在线| 亚洲的电影一区二区三区| 欧美亚洲国产成人免费在线 | 女同互舔一区二区三区| 性欧美激情久久久久久久| 88成人免费av网站| 亚洲中文精品字幕在线观看| 午夜在线观看岛国av,com| 红桃av成人在线观看| 岛国一区二区三区视频在线| 国产卡一卡二卡三乱码手机| 青青青青青青青青青青草青青 | 成人亚洲国产综合精品| 日本xx片在线观看| 狠狠的往里顶撞h百合| 五月天久久激情视频| 欧美久久一区二区伊人| 国产在线91观看免费观看| 国产精品国产三级国产午| 扒开让我视频在线观看| 人妻无码中文字幕专区| 91精品免费久久久久久| 在线免费观看视频一二区| 国产黄网站在线观看播放| 一区二区三区的久久的蜜桃的视频| 日本一区美女福利视频| 国产又粗又黄又硬又爽| 欧洲精品第一页欧洲精品亚洲| 国产福利小视频免费观看| 绝顶痉挛大潮喷高潮无码 | 午夜精品在线视频一区| 91九色国产熟女一区二区| 日韩一区二区电国产精品| 经典亚洲伊人第一页| 韩国三级aaaaa高清视频| 成年人该看的视频黄免费| 久久久久久久久久一区二区三区 | 98精产国品一二三产区区别| 老司机免费福利视频网| 快插进小逼里大鸡吧视频| 不卡一不卡二不卡三| 欧美成人黄片一区二区三区| 啪啪啪18禁一区二区三区 | 懂色av蜜桃a v| 91大神福利视频网| 99精品国产自在现线观看| 美女福利写真在线观看视频| 亚洲卡1卡2卡三卡四老狼| 福利视频网久久91| 中文字幕 人妻精品| 午夜频道成人在线91| 国产janese在线播放| 国产成人无码精品久久久电影| 香蕉片在线观看av| 婷婷久久久久深爱网| 日韩亚洲高清在线观看| 一色桃子久久精品亚洲 | 成人精品在线观看视频| 无码国产精品一区二区高潮久久4 日韩欧美一级精品在线观看 | 亚洲免费在线视频网站| 亚洲国产欧美一区二区丝袜黑人| 性欧美激情久久久久久久| 亚国产成人精品久久久| 亚洲1卡2卡三卡4卡在线观看| 中文字幕成人日韩欧美| 97精品综合久久在线| 狠狠操狠狠操免费视频| 亚洲精品一区二区三区老狼| 老司机福利精品免费视频一区二区 | 人人妻人人爽人人添夜| 日本a级视频老女人| 国产va精品免费观看| 亚洲青青操骚货在线视频| 青青青激情在线观看视频| 国产大学生援交正在播放| 天天日天天爽天天爽| 久久精品在线观看一区二区| 中文字幕中文字幕人妻| 欧美黑人性猛交xxxxⅹooo| 亚洲国产成人在线一区| 18禁无翼鸟成人在线| 天天色天天舔天天射天天爽| 北条麻妃av在线免费观看| 国产一级精品综合av| 91试看福利一分钟| 免费成人av中文字幕| 人妻少妇亚洲一区二区| 福利片区一区二体验区| 沙月文乃人妻侵犯中文字幕在线| aⅴ精产国品一二三产品| 日本女大学生的黄色小视频| 91欧美在线免费观看| 黄片大全在线观看观看| 521精品视频在线观看| 色噜噜噜噜18禁止观看| 国产精品国产三级国产精东| 啊啊啊想要被插进去视频| 国产成人精品亚洲男人的天堂| h国产小视频福利在线观看| 免费费一级特黄真人片| 99婷婷在线观看视频| 中文字幕日韩无敌亚洲精品 | 中文字幕日本人妻中出| 精品一区二区三区三区88| 亚洲国产欧美国产综合在线| 欧美偷拍自拍色图片| 在线免费91激情四射 | 2019av在线视频| 欧美3p在线观看一区二区三区| 黄色av网站免费在线| 日韩欧美一级aa大片| 人人妻人人爽人人澡人人精品| 天天爽夜夜爽人人爽QC| 亚洲一区二区三区五区| 国产一区二区在线欧美| 少妇高潮无套内谢麻豆| 77久久久久国产精产品| 国产日韩av一区二区在线| 日本高清撒尿pissing| 熟女人妻一区二区精品视频| 亚洲第一黄色在线观看| 中文字幕AV在线免费看 | 美女被肏内射视频网站| 91色九色porny| 中文字幕 码 在线视频| 亚洲免费视频欧洲免费视频| av天堂中文免费在线| 久久这里只有精品热视频| 天天日天天日天天射天天干| 在线免费视频 自拍| 夏目彩春在线中文字幕| 久久久久久99国产精品| 日本午夜福利免费视频| 91精品资源免费观看| 无码日韩人妻精品久久| 亚洲男人的天堂a在线| 欧美成人黄片一区二区三区 | 超污视频在线观看污污污| 天天色天天舔天天射天天爽 | 一区二区三区欧美日韩高清播放| 精品成人午夜免费看| 亚洲熟妇x久久av久久| 国产精品3p和黑人大战| 一二三中文乱码亚洲乱码one | 美女骚逼日出水来了| 免费无毒热热热热热热久| 五月激情婷婷久久综合网| 国产成人综合一区2区| 国产普通话插插视频| 人妻熟女中文字幕aⅴ在线| 青青青青青青青青青国产精品视频| 国产欧美精品免费观看视频| 国产一区二区火爆视频| 在线国产中文字幕视频| 精品首页在线观看视频| 亚洲av日韩av第一区二区三区| 丝袜肉丝一区二区三区四区在线看| 日本韩国在线观看一区二区| 51精品视频免费在线观看| 91亚洲精品干熟女蜜桃频道 | 老鸭窝在线观看一区| 大鸡巴插入美女黑黑的阴毛| 亚洲av色图18p| 亚洲熟女女同志女同| 午夜美女福利小视频| 5528327男人天堂| 久久免看30视频口爆视频| 亚洲卡1卡2卡三卡四老狼| 成人蜜臀午夜久久一区| 免费观看理论片完整版| 日本特级片中文字幕| 亚洲蜜臀av一区二区三区九色 | 国产黄色大片在线免费播放| av在线观看网址av| 2018在线福利视频| 欧美中国日韩久久精品| eeuss鲁片一区二区三区| 天天日天天干天天搡| 粗大的内捧猛烈进出爽大牛汉子| 黄片大全在线观看观看| 蜜桃视频在线欧美一区| 日韩美女综合中文字幕pp| 国产精品国产三级麻豆| 精品久久久久久久久久久99| 欧美国产亚洲中英文字幕| 日韩av大胆在线观看| 天堂av在线最新版在线| 国产在线拍揄自揄视频网站| 国产一区av澳门在线观看| 无码精品一区二区三区人| 欧美亚洲免费视频观看| 国产日韩欧美美利坚蜜臀懂色| 扒开让我视频在线观看| 日日摸夜夜添夜夜添毛片性色av| 中文字幕日韩精品就在这里| 亚洲一级美女啪啪啪| 五十路熟女人妻一区二| 岛国毛片视频免费在线观看| 亚洲 中文 自拍 无码| 日韩视频一区二区免费观看| 青青青青青手机视频| 国产精品久久久久国产三级试频| 91综合久久亚洲综合| 在线观看免费视频色97| 岛国一区二区三区视频在线| 日韩人妻丝袜中文字幕| gav成人免费播放| 色爱av一区二区三区| 91九色porny国产蝌蚪视频| 91在线视频在线精品3| 一区二区在线视频中文字幕| 午夜精品福利91av| 日韩亚洲高清在线观看| 韩国女主播精品视频网站| 国产精品久久久久久美女校花| 中文字幕高清在线免费播放| 久久久久久久久久久久久97| 中文字幕人妻熟女在线电影| 337p日本大胆欧美人| 国产男女视频在线播放| 中文字幕日韩精品就在这里| 午夜国产福利在线观看| 在线免费观看国产精品黄色| 天天干天天日天天谢综合156| 日韩av有码一区二区三区4| 91亚洲手机在线视频播放| 鸡巴操逼一级黄色气| 不卡精品视频在线观看| 国产又色又刺激在线视频| 中国视频一区二区三区| 岛国毛片视频免费在线观看| 高潮视频在线快速观看国家快速| 国产精品久久久久网| 久久香蕉国产免费天天| 欧美偷拍亚洲一区二区| 97黄网站在线观看| 蜜桃视频17c在线一区二区| 无套猛戳丰满少妇人妻| 国产精彩福利精品视频| 成人av天堂丝袜在线观看| 97人人模人人爽人人喊| 国产1区,2区,3区| 色婷婷综合激情五月免费观看| 老师啊太大了啊啊啊尻视频| 综合国产成人在线观看| 精品av久久久久久久| 精品久久久久久久久久久a√国产 日本女大学生的黄色小视频 | 亚洲成人av一区在线| 成人动漫大肉棒插进去视频| 日本真人性生活视频免费看| 黑人解禁人妻叶爱071| av亚洲中文天堂字幕网| 亚洲福利精品福利精品福利| 91传媒一区二区三区| 亚洲综合一区二区精品久久| 中文字幕国产专区欧美激情| 揄拍成人国产精品免费看视频| 国产精品探花熟女在线观看| 精品91高清在线观看| 亚洲国产欧美一区二区丝袜黑人| 99精品一区二区三区的区| 日韩av有码一区二区三区4| 黄色黄色黄片78在线| 久久艹在线观看视频| 一级a看免费观看网站| 人妻3p真实偷拍一二区| 亚洲公开视频在线观看| 熟女人妻三十路四十路人妻斩| 人妻爱爱 中文字幕| av亚洲中文天堂字幕网| 五十路av熟女松本翔子| 亚洲在线一区二区欧美| 青青青国产片免费观看视频| 国产av欧美精品高潮网站| 亚洲免费福利一区二区三区| 国产亚洲国产av网站在线| 欧美偷拍亚洲一区二区| 97少妇精品在线观看| 欧美黑人性猛交xxxxⅹooo| 日韩美女综合中文字幕pp| 又粗又长 明星操逼小视频| 亚洲少妇高潮免费观看| 91老师蜜桃臀大屁股| 91试看福利一分钟| 亚洲欧美国产麻豆综合| 男人天堂最新地址av| 午夜成午夜成年片在线观看 | 久久精品久久精品亚洲人| 成人亚洲国产综合精品| 亚洲熟女综合色一区二区三区四区 | 亚洲综合一区成人在线| 国产日韩精品免费在线| 大学生A级毛片免费视频| av手机在线免费观看日韩av| 亚洲一区久久免费视频| 在线免费观看靠比视频的网站| 偷拍自拍亚洲视频在线观看| 五色婷婷综合狠狠爱| 亚洲国产精品美女在线观看| 亚洲 国产 成人 在线| 日韩av熟妇在线观看| 一级a看免费观看网站| 大陆精品一区二区三区久久| 亚洲图库另类图片区| 亚洲欧美人精品高清| 欧美乱妇无乱码一区二区| 美女福利视频导航网站 | 中文亚洲欧美日韩无线码| 中国产一级黄片免费视频播放| 黑人大几巴狂插日本少妇| 一级黄色av在线观看| 78色精品一区二区三区| 日韩特级黄片高清在线看| 亚洲欧美国产综合777| 蜜臀av久久久久久久| 非洲黑人一级特黄片| 亚洲综合另类精品小说| 嫩草aⅴ一区二区三区| 最新中文字幕免费视频| 毛茸茸的大外阴中国视频| av森泽佳奈在线观看 | 亚洲国产在人线放午夜| 日本a级视频老女人| 人人妻人人爽人人添夜| 欧美va亚洲va天堂va| 亚洲一区二区三区精品视频在线 | 成人av在线资源网站| 蜜臀av久久久久蜜臀av麻豆| 1000小视频在线| 久草视频在线一区二区三区资源站| 久久精品美女免费视频| 天天摸天天亲天天舔天天操天天爽| 91久久国产成人免费网站| 国产精品熟女久久久久浪潮| 热99re69精品8在线播放| 人妻爱爱 中文字幕| 午夜福利资源综合激情午夜福利资| 黄色大片免费观看网站| 在线免费观看日本片| 天天日天天干天天搡| 欧美视频综合第一页| 农村胖女人操逼视频| 国产女孩喷水在线观看| 日韩av有码中文字幕| 97人人妻人人澡人人爽人人精品| 大学生A级毛片免费视频| 快点插进来操我逼啊视频| 在线观看成人国产电影| 日本一二三中文字幕| 人人爽亚洲av人人爽av| 欧美偷拍亚洲一区二区| 91久久人澡人人添人人爽乱| 亚洲图库另类图片区| 亚洲熟妇无码一区二区三区| 亚洲欧美成人综合视频| 欧美日韩国产一区二区三区三州| 女生自摸在线观看一区二区三区 | 白白操白白色在线免费视频| 欧美va不卡视频在线观看| 成年人的在线免费视频| 国产福利在线视频一区| 伊人开心婷婷国产av| 青青青青青青青青青国产精品视频| 99久久超碰人妻国产| 2022国产综合在线干| 天天摸天天亲天天舔天天操天天爽| 亚洲午夜电影之麻豆| sw137 中文字幕 在线| 精品首页在线观看视频| 亚洲综合乱码一区二区| 亚洲av第国产精品| 国产精品精品精品999| 国产高清女主播在线| 国产91精品拍在线观看| 最新激情中文字幕视频| 中文字幕日韩精品就在这里| 黑人巨大精品欧美视频| 天天日天天日天天射天天干 | 57pao国产一区二区| 久久午夜夜伦痒痒想咳嗽P| 日韩影片一区二区三区不卡免费| 新97超碰在线观看| 日本午夜福利免费视频| 一区二区视频视频视频| 中文字幕中文字幕 亚洲国产| 搡老妇人老女人老熟女| 亚洲国产精品美女在线观看| 亚洲 清纯 国产com| 欧美男人大鸡吧插女人视频| 大香蕉日本伊人中文在线| 中文字幕av一区在线观看| 一级黄片大鸡巴插入美女| 欧美黑人性猛交xxxxⅹooo| 超级福利视频在线观看| 性色av一区二区三区久久久 | 中文字幕一区二区自拍| 91成人精品亚洲国产| 久久久久久久久久一区二区三区 | 青青色国产视频在线| 91国内精品自线在拍白富美| 国产自拍黄片在线观看| 黄色无码鸡吧操逼视频| 超级碰碰在线视频免费观看| 欧洲欧美日韩国产在线| 青草久久视频在线观看| 女生被男生插的视频网站| 欧美精品亚洲精品日韩在线| 大胸性感美女羞爽操逼毛片| 五十路息与子猛烈交尾视频 | 成年人黄视频在线观看| 啊慢点鸡巴太大了啊舒服视频 | 日韩精品中文字幕福利| 亚洲一区制服丝袜美腿| yellow在线播放av啊啊啊| 日本中文字幕一二区视频| 91麻豆精品久久久久| 欧美专区日韩专区国产专区| 亚洲高清自偷揄拍自拍| 亚洲1卡2卡三卡4卡在线观看| 天天干天天操天天玩天天射| 适合午夜一个人看的视频| 91精品资源免费观看| 国产九色91在线观看精品| 最新日韩av传媒在线| 成人sm视频在线观看| 久草视频福利在线首页| av老司机亚洲一区二区| 久久精品在线观看一区二区 | av大全在线播放免费| 亚洲成人国产综合一区| 黄色片黄色片wyaa| 欧美美女人体视频一区| 51精品视频免费在线观看| 国产变态另类在线观看| 国产视频一区二区午夜| 亚洲天堂av最新网址| 日美女屁股黄邑视频| 精彩视频99免费在线| 青青青青草手机在线视频免费看| 欧美日韩高清午夜蜜桃大香蕉| av在线免费观看亚洲天堂| 精品91高清在线观看| 男大肉棒猛烈插女免费视频| 亚洲精品久久视频婷婷| 在线成人日韩av电影| 免费黄高清无码国产| 亚洲欧美人精品高清| 91p0rny九色露脸熟女| 绝顶痉挛大潮喷高潮无码| 亚洲精品在线资源站| 日本免费一级黄色录像| 色狠狠av线不卡香蕉一区二区 | 免费在线福利小视频| 一区二区熟女人妻视频| 色综合久久无码中文字幕波多| 欧美特色aaa大片| 一区二区三区四区中文| 人妻素人精油按摩中出| 9色精品视频在线观看| 日韩人妻xxxxx| 精品亚洲在线免费观看| 婷婷五月亚洲综合在线| 老司机深夜免费福利视频在线观看| 丰满少妇翘臀后进式| 亚洲一区二区三区久久受| 动漫美女的小穴视频| 免费黄色成人午夜在线网站| 国产成人精品午夜福利训2021| 3344免费偷拍视频| 大白屁股精品视频国产| 亚洲精品午夜久久久久| 国产精品大陆在线2019不卡| 国产精彩对白一区二区三区| 亚洲国产精品黑丝美女| 天堂资源网av中文字幕| 桃色视频在线观看一区二区 | 在线视频国产欧美日韩| 天天日天天透天天操| 亚洲中文字幕乱码区| 偷青青国产精品青青在线观看 | 成人伊人精品色xxxx视频| 亚洲高清国产一区二区三区| 欧美精产国品一二三产品价格 | 熟女妇女老妇一二三区| 午夜激情精品福利视频| 天天想要天天操天天干| 大胸性感美女羞爽操逼毛片| 另类av十亚洲av| 少妇露脸深喉口爆吞精| 2022国产精品视频| 中文字幕亚洲中文字幕| 中文字幕免费在线免费| 激情啪啪啪啪一区二区三区 | 成年人黄色片免费网站| 欧美美女人体视频一区| 国产亚洲视频在线观看| 91www一区二区三区| 91快播视频在线观看| 丝袜美腿视频诱惑亚洲无| 国产成人精品av网站| 最新国产亚洲精品中文在线| 日韩精品一区二区三区在线播放| 亚洲中文字幕乱码区| 蜜桃视频入口久久久| 色狠狠av线不卡香蕉一区二区| 久草视频首页在线观看| 99视频精品全部15| 天天躁日日躁狠狠躁躁欧美av| 91国内精品自线在拍白富美| 国产视频网站国产视频| 国产福利小视频大全| 国产极品精品免费视频| 天天色天天操天天透| 黑人性生活视频免费看| 天天干天天插天天谢| 天天射夜夜操综合网| 狠狠躁夜夜躁人人爽天天天天97| 中文字幕人妻av在线观看 | 91免费黄片可看视频| 中文字幕视频一区二区在线观看| chinese国产盗摄一区二区| 人妻少妇亚洲一区二区| 涩涩的视频在线观看视频| 91精品资源免费观看| 综合激情网激情五月五月婷婷| 扒开让我视频在线观看| 日本裸体熟妇区二区欧美| 巨乳人妻日下部加奈被邻居中出 | 国产视频网站一区二区三区| 国产九色91在线观看精品| 天天干天天爱天天色| 天天日天天干天天搡| www日韩毛片av| 91老师蜜桃臀大屁股| 538精品在线观看视频| 精品91自产拍在线观看一区| 快点插进来操我逼啊视频| 丰满的子国产在线观看| 国产一级麻豆精品免费| 视频 国产 精品 熟女 | 91国偷自产一区二区三区精品| 天天日夜夜干天天操| 97人人妻人人澡人人爽人人精品| 日本熟妇一区二区x x| 阴茎插到阴道里面的视频| 在线观看一区二区三级| 亚洲国产欧美一区二区三区…| 亚洲1区2区3区精华液| 自拍偷拍vs一区二区三区| 国产污污污污网站在线| 一区二区三区蜜臀在线| 视频一区二区在线免费播放| 婷婷久久久综合中文字幕| 99热碰碰热精品a中文| 天堂va蜜桃一区入口| lutube在线成人免费看| 中国产一级黄片免费视频播放| 中文字幕第三十八页久久 | 影音先锋女人av噜噜色| 国产精品sm调教视频| 91九色porny蝌蚪国产成人| 日本成人一区二区不卡免费在线| 毛茸茸的大外阴中国视频| 偷偷玩弄新婚人妻h视频| 中文字幕在线永久免费播放| 99re国产在线精品| 桃色视频在线观看一区二区| 91久久人澡人人添人人爽乱| 欧美老妇精品另类不卡片| 在线观看成人国产电影| 操人妻嗷嗷叫视频一区二区| 欧美日本在线视频一区| 欧美性感尤物人妻在线免费看| av线天堂在线观看| 香蕉片在线观看av| 国内自拍第一页在线观看| 亚洲粉嫩av一区二区三区| 偷拍美女一区二区三区| 亚洲va国产va欧美va在线| 日本熟妇丰满厨房55| 2025年人妻中文字幕乱码在线| 中文字幕无码日韩专区免费| 天天日天天玩天天摸| 天天日天天做天天日天天做| 国产超码片内射在线| 性色蜜臀av一区二区三区| 午夜在线观看岛国av,com| 欧美日韩熟女一区二区三区| 亚洲少妇高潮免费观看| 亚洲熟女综合色一区二区三区四区| 又黄又刺激的午夜小视频| 一级黄色片夫妻性生活| 日韩欧美中文国产在线| 在线制服丝袜中文字幕| 国产又粗又黄又硬又爽| 2018在线福利视频| 可以在线观看的av中文字幕| 成年人该看的视频黄免费| 国产黄色大片在线免费播放| 97欧洲一区二区精品免费| 欧美黄色录像免费看的| 综合一区二区三区蜜臀| 91啪国自产中文字幕在线| 国产三级片久久久久久久| 馒头大胆亚洲一区二区| 国产白袜脚足J棉袜在线观看| 亚洲综合在线观看免费| 扒开让我视频在线观看| 无套猛戳丰满少妇人妻| 一区二区免费高清黄色视频| 欧美精品黑人性xxxx| 2022精品久久久久久中文字幕| 国产精品sm调教视频| 国产成人综合一区2区| 韩国爱爱视频中文字幕| 在线亚洲天堂色播av电影| 少妇露脸深喉口爆吞精| 综合激情网激情五月五月婷婷| 国产在线91观看免费观看| 成人24小时免费视频| 黑人3p华裔熟女普通话| 天天操天天插天天色| 三上悠亚和黑人665番号| 热久久只有这里有精品| 大胆亚洲av日韩av| 自拍偷拍亚洲另类色图| 欧美亚洲偷拍自拍色图| 欧美香蕉人妻精品一区二区| 人妻少妇av在线观看| 蜜桃久久久久久久人妻| 亚洲精品三级av在线免费观看| 爱爱免费在线观看视频| 国产九色91在线视频| 传媒在线播放国产精品一区| 摧残蹂躏av一二三区| 女同性ⅹxx女同h偷拍| 亚洲第一黄色在线观看| 国产精品三级三级三级| 最新97国产在线视频| 国产欧美精品不卡在线| 大香蕉日本伊人中文在线| 亚洲午夜高清在线观看| 成熟熟女国产精品一区| 1024久久国产精品| 在线观看视频一区麻豆| avjpm亚洲伊人久久| 91麻豆精品91久久久久同性| 国产妇女自拍区在线观看| 欧美爆乳肉感大码在线观看 | 青青草亚洲国产精品视频| 97人人妻人人澡人人爽人人精品| 青青青国产片免费观看视频| 97资源人妻免费在线视频| a v欧美一区=区三区| 91香蕉成人app下载| 熟女国产一区亚洲中文字幕| 国产高清女主播在线| 中国老熟女偷拍第一页| 啊啊好大好爽啊啊操我啊啊视频 | 久久这里只有精彩视频免费| 人妻凌辱欧美丰满熟妇| 美女吃鸡巴操逼高潮视频| 日韩一个色综合导航| 中文字幕日韩精品日本| 偷偷玩弄新婚人妻h视频| 亚洲熟妇久久无码精品| 91国内精品久久久久精品一| 日韩不卡中文在线视频网站| 一区二区视频视频视频| 亚洲av日韩精品久久久| 国产日本精品久久久久久久| 色婷婷综合激情五月免费观看| 一级A一级a爰片免费免会员| 韩国一级特黄大片做受| 亚洲天堂精品久久久| 韩国亚洲欧美超一级在线播放视频| 综合页自拍视频在线播放| 亚洲av第国产精品| 97超碰国语国产97超碰| 亚洲综合另类欧美久久| av完全免费在线观看av| 中文字幕在线乱码一区二区| 白白操白白色在线免费视频 | 亚洲欧洲一区二区在线观看| 日日爽天天干夜夜操| 亚洲欧美国产综合777| 2022精品久久久久久中文字幕| 全国亚洲男人的天堂| 亚洲码av无色中文| 中文字幕日韩91人妻在线| 2022天天干天天操| 欧美中国日韩久久精品| 欧美一区二区三区乱码在线播放| 在线观看欧美黄片一区二区三区| 社区自拍揄拍尻屁你懂的 | 国产精品国产三级国产精东 | 偷拍自拍亚洲美腿丝袜| 成年女人免费播放视频| 亚洲一区二区三区精品乱码| 在线免费观看日本伦理| 天美传媒mv视频在线观看| 91久久人澡人人添人人爽乱| 国产精品伦理片一区二区| 美女在线观看日本亚洲一区| 99re国产在线精品| 一区二区久久成人网| 狠狠躁夜夜躁人人爽天天天天97| 欧洲日韩亚洲一区二区三区| av欧美网站在线观看| 国产免费av一区二区凹凸四季| 97国产福利小视频合集| 日本黄在免费看视频| 蜜桃视频入口久久久| 亚洲精品午夜aaa久久| 国产精品成久久久久三级蜜臀av | 夏目彩春在线中文字幕| av网站色偷偷婷婷网男人的天堂| 老司机99精品视频在线观看 | 啪啪啪操人视频在线播放| 久久久久久cao我的性感人妻| 午夜dv内射一区区| 欧美另类重口味极品在线观看| 人妻丝袜精品中文字幕| 国产精品人久久久久久| 一级a看免费观看网站| 久久永久免费精品人妻专区| 国产美女精品福利在线| 欧美成人综合视频一区二区| 国产九色91在线视频| 日辽宁老肥女在线观看视频| 不卡精品视频在线观看| 无忧传媒在线观看视频| 人妻少妇性色欲欧美日韩| 99av国产精品欲麻豆| 欧美性受xx黑人性猛交| 97人人模人人爽人人喊| 欧美一区二区三区四区性视频| 精产国品久久一二三产区区别| av无限看熟女人妻另类av| 天天做天天爽夜夜做少妇| 人妻凌辱欧美丰满熟妇| 欧美色呦呦最新网址| 直接观看免费黄网站| 国产精品三级三级三级| 97少妇精品在线观看| 男人天堂最新地址av| 亚洲日本一区二区久久久精品| 日本熟女精品一区二区三区| 沙月文乃人妻侵犯中文字幕在线| 亚洲欧美另类自拍偷拍色图| 一级A一级a爰片免费免会员| 亚洲第一黄色在线观看| 亚洲欧美成人综合在线观看| av网址国产在线观看| 日韩欧美高清免费在线| 日日夜夜大香蕉伊人| 亚洲视频在线观看高清| 国产在线观看免费人成短视频| 国产精品一二三不卡带免费视频| 中文字幕免费在线免费| 天天日天天玩天天摸| 免费看国产又粗又猛又爽又黄视频| 深田咏美亚洲一区二区| av高潮迭起在线观看| 性欧美激情久久久久久久| 国产内射中出在线观看| 噜噜色噜噜噜久色超碰| 五十路av熟女松本翔子| 国产精品入口麻豆啊啊啊| 乱亲女秽乱长久久久| 日韩北条麻妃一区在线| 全国亚洲男人的天堂| 91桃色成人网络在线观看| 伊人网中文字幕在线视频| 亚洲狠狠婷婷综合久久app | 国产麻豆精品人妻av| 黑人变态深video特大巨大| 水蜜桃国产一区二区三区| 国产视频一区二区午夜| caoporn蜜桃视频| 在线观看免费视频色97| 97人妻总资源视频| 日本性感美女视频网站| 国产精品国产三级麻豆| 国产精品精品精品999| 日韩精品中文字幕播放| 国产久久久精品毛片| 2025年人妻中文字幕乱码在线| 国产乱子伦一二三区| 成人免费毛片aaaa| 欧美精品激情在线最新观看视频| 天天色天天爱天天爽| 免费观看污视频网站| 激情啪啪啪啪一区二区三区| 精品国产污污免费网站入口自| 日本精品视频不卡一二三| 91在线免费观看成人| 亚洲午夜在线视频福利| 免费观看丰满少妇做受| 国产精品中文av在线播放 | eeuss鲁片一区二区三区| 日本五十路熟新垣里子| 亚洲在线一区二区欧美| 国产精品人久久久久久| 日韩欧美一级精品在线观看| 青青热久免费精品视频在线观看| 中字幕人妻熟女人妻a62v网 | 精品久久久久久高潮| av大全在线播放免费| 青青擦在线视频国产在线| 少妇ww搡性bbb91| 久久永久免费精品人妻专区 | 神马午夜在线观看视频| 水蜜桃一区二区三区在线观看视频| 国产三级精品三级在线不卡| 中国熟女@视频91| 亚洲麻豆一区二区三区| 亚洲人妻国产精品综合| 91人妻精品久久久久久久网站| 亚洲精品国产综合久久久久久久久| 天堂av在线最新版在线| 巨乳人妻日下部加奈被邻居中出 | 黑人巨大的吊bdsm| 大香蕉大香蕉在线有码 av| 51国产成人精品视频| 日韩av有码一区二区三区4| 天天日天天敢天天干| 天堂av在线最新版在线| 亚洲嫩模一区二区三区| 日本免费一级黄色录像| 天天做天天干天天操天天射| 2018在线福利视频| 97香蕉碰碰人妻国产樱花| 亚洲男人在线天堂网| 青青青青操在线观看免费| 狠狠躁狠狠爱网站视频| 桃色视频在线观看一区二区| 蜜桃视频入口久久久| 国产亚州色婷婷久久99精品| 中国黄片视频一区91| 亚洲精品久久视频婷婷| 在线视频免费观看网| 老师啊太大了啊啊啊尻视频| 久久热久久视频在线观看| 国产成人综合一区2区| 青春草视频在线免费播放| 夜女神免费福利视频| 国产高潮无码喷水AV片在线观看| yellow在线播放av啊啊啊| 自拍偷区二区三区麻豆| 狍和女人的王色毛片| 久久农村老妇乱69系列| 在线成人日韩av电影| 人妻自拍视频中国大陆| 视频久久久久久久人妻| 欧美色呦呦最新网址| 伊人网中文字幕在线视频| 国产精品探花熟女在线观看| 亚洲精品 日韩电影| 国产精品污污污久久| 日韩二区视频一线天婷婷五| 国产av自拍偷拍盛宴| 一级黄色片夫妻性生活| 欧美aa一级一区三区四区| 人妻少妇中文有码精品| 天天干天天操天天摸天天射| 中国黄色av一级片| 成人性黑人一级av| 国产精品成久久久久三级蜜臀av| 日本熟妇一区二区x x| 少妇被强干到高潮视频在线观看| 色综合天天综合网国产成人| 青青青青青免费视频| av黄色成人在线观看| 亚洲av可乐操首页| 天天夜天天日天天日| 日本欧美视频在线观看三区| 久久永久免费精品人妻专区| 91 亚洲视频在线观看| 成年人该看的视频黄免费| 欧美久久久久久三级网| 亚洲偷自拍高清视频| 久久热久久视频在线观看| 丁香花免费在线观看中文字幕 | 在线观看成人国产电影| 亚洲av男人的天堂你懂的| 在线观看操大逼视频| av黄色成人在线观看| 男人的网址你懂的亚洲欧洲av| 沈阳熟妇28厘米大战黑人| 亚洲成高清a人片在线观看| 欧美亚洲牲夜夜综合久久| 中文字幕在线乱码一区二区| 国产成人精品av网站| 欧美黑人与人妻精品| 五月激情婷婷久久综合网| 免费高清自慰一区二区三区网站 | 久久久久久久亚洲午夜综合福利| 天天艹天天干天天操| 少妇高潮一区二区三区| 91色老99久久九九爱精品| 黄片大全在线观看观看| okirakuhuhu在线观看| 国产av国片精品一区二区| 天天日天天玩天天摸| 一区二区三区另类在线| 免费看国产又粗又猛又爽又黄视频 | 日本高清撒尿pissing| 91麻豆精品久久久久| 1769国产精品视频免费观看| 国产视频在线视频播放| 北条麻妃肉色丝袜视频| 日韩特级黄片高清在线看| 夜色17s精品人妻熟女| 久久久久久久99精品| 亚洲综合一区成人在线| 国产亚洲成人免费在线观看 | 亚洲免费福利一区二区三区| 成人影片高清在线观看 | 伊人精品福利综合导航| 国产高清97在线观看视频| 精品suv一区二区69| 精品美女福利在线观看| 97a片免费在线观看| 免费看国产又粗又猛又爽又黄视频| 精品高跟鞋丝袜一区二区| 精品一区二区亚洲欧美| 精品人妻一二三区久久| 在线免费观看日本伦理| av手机免费在线观看高潮| 国产高清在线观看1区2区| 午夜免费观看精品视频| 男人的天堂av日韩亚洲| 在线观看免费av网址大全| 国产伊人免费在线播放| 97色视频在线观看| 亚洲熟妇久久无码精品| 成人在线欧美日韩国产| 日本少妇人妻xxxxxhd| 欲乱人妻少妇在线视频裸| 北条麻妃高跟丝袜啪啪| 欧美精品一区二区三区xxxx| 天天操天天干天天插| 欧美激情电影免费在线| 亚洲第一黄色在线观看| 久青青草视频手机在线免费观看| 在线观看成人国产电影| 亚洲综合在线观看免费| 免费在线福利小视频| 免费手机黄页网址大全| 亚洲av午夜免费观看| 成年女人免费播放视频| 最新91精品视频在线| 亚洲精品麻豆免费在线观看| 亚洲免费福利一区二区三区| 国产精品久久久久久久久福交| 非洲黑人一级特黄片| 久精品人妻一区二区三区| 一个色综合男人天堂| 天天射夜夜操狠狠干| 新婚人妻聚会被中出| 国产一区成人在线观看视频| 国产内射中出在线观看| 视频一区 二区 三区 综合| 超pen在线观看视频公开97| 2018最新中文字幕在线观看| 蝴蝶伊人久久中文娱乐网| 欧美偷拍亚洲一区二区| 在线观看av2025| 国产日韩精品电影7777| 视频啪啪啪免费观看| AV天堂一区二区免费试看| 久久久久国产成人精品亚洲午夜| 99热国产精品666| 夜夜嗨av蜜臀av| 亚洲另类在线免费观看| 黄色录像鸡巴插进去| 蜜桃色婷婷久久久福利在线| 日比视频老公慢点好舒服啊| 亚洲少妇高潮免费观看| 亚洲欧美久久久久久久久| 激情五月婷婷综合色啪| 91在线视频在线精品3| 999九九久久久精品| 在线免费观看日本片| 中文字幕 码 在线视频| 精品高潮呻吟久久av| 97国产在线观看高清| 国产女孩喷水在线观看| 国产在线91观看免费观看| 美洲精品一二三产区区别| 好男人视频在线免费观看网站| 日韩成人综艺在线播放| 日本韩国在线观看一区二区| 视频啪啪啪免费观看| 成年美女黄网站18禁久久| 国产自拍在线观看成人| 一级黄片久久久久久久久| 久久尻中国美女视频| 91大神福利视频网| 国产亚洲精品品视频在线| 国产精品久久综合久久| 日韩人妻在线视频免费| 国产熟妇一区二区三区av| 91中文字幕免费在线观看| 精品视频国产在线观看| 99re久久这里都是精品视频| 一本一本久久a久久精品综合不卡| 红杏久久av人妻一区| 日本一二三区不卡无| 久草视频在线一区二区三区资源站| 天天日天天做天天日天天做| 中国黄色av一级片| 国产精品成久久久久三级蜜臀av| 男人的网址你懂的亚洲欧洲av| 亚洲成人三级在线播放| 在线免费观看99视频| 99久久超碰人妻国产| 亚洲2021av天堂| 日韩近亲视频在线观看| 老师啊太大了啊啊啊尻视频| 韩国AV无码不卡在线播放| 超pen在线观看视频公开97| 在线播放一区二区三区Av无码| 淫秽激情视频免费观看| 可以在线观看的av中文字幕 | 亚洲高清一区二区三区视频在线| 国际av大片在线免费观看| 国产无遮挡裸体免费直播视频| 操的小逼流水的文章| 香港三日本三韩国三欧美三级| 亚洲天堂有码中文字幕视频| 好吊视频—区二区三区| 2022中文字幕在线| 大鸡巴操b视频在线| 人妻另类专区欧美制服| 黄色三级网站免费下载| 夜夜嗨av蜜臀av| 日韩精品一区二区三区在线播放| 精品一区二区亚洲欧美| 亚洲成人三级在线播放| 91亚洲精品干熟女蜜桃频道| 北条麻妃高跟丝袜啪啪| 男人插女人视频网站| 一级A一级a爰片免费免会员 | av中文字幕电影在线看| 国产chinesehd精品麻豆| av视屏免费在线播放| 91免费观看在线网站 | 91免费观看国产免费| 天天操天天干天天日狠狠插| 边摸边做超爽毛片18禁色戒| 国产黑丝高跟鞋视频在线播放| av一区二区三区人妻| 国产成人精品午夜福利训2021| 午夜精彩视频免费一区| 在线国产精品一区二区三区| 1769国产精品视频免费观看| 77久久久久国产精产品| 国产精品手机在线看片| 日韩精品中文字幕福利| 538精品在线观看视频| 久久久久久性虐视频| 女同互舔一区二区三区| 免费啪啪啪在线观看视频| 亚洲美女美妇久久字幕组| 91成人在线观看免费视频| 国产精品3p和黑人大战| 日韩美女福利视频网| 性感美女高潮视频久久久 | 亚洲一级av无码一级久久精品| 国内资源最丰富的网站| 亚洲成人国产综合一区| 黑人借宿ntr人妻的沦陷2| 宅男噜噜噜666国产| 18禁精品网站久久| 亚洲av自拍偷拍综合| 天天日天天添天天爽| 青青青青青青草国产| 精品亚洲中文字幕av| av中文字幕国产在线观看| gogo国模私拍视频| 亚洲av黄色在线网站| 久草免费人妻视频在线| 亚洲男人让女人爽的视频| 午夜国产福利在线观看| 老熟妇xxxhd老熟女| 久久永久免费精品人妻专区| 久久这里有免费精品| 亚洲高清免费在线观看视频| 亚洲老熟妇日本老妇| 欧美特级特黄a大片免费| 91精品国产黑色丝袜| 五十路在线观看完整版| 北条麻妃av在线免费观看| 亚洲精品乱码久久久久久密桃明| 日韩不卡中文在线视频网站| av男人天堂狠狠干| 91p0rny九色露脸熟女| 日韩av中文在线免费观看| 人妻少妇av在线观看| 午夜婷婷在线观看视频| 欲乱人妻少妇在线视频裸| 免费十精品十国产网站| 最新日韩av传媒在线| 91天堂精品一区二区| 青青色国产视频在线| 午夜的视频在线观看| 日本高清在线不卡一区二区| 天天操天天弄天天射| 日韩美女综合中文字幕pp| 粉嫩av蜜乳av蜜臀| 直接能看的国产av| av黄色成人在线观看| 国产三级影院在线观看| 青青青视频手机在线观看| 熟妇一区二区三区高清版| 国产不卡av在线免费| 色婷婷综合激情五月免费观看| 老司机在线精品福利视频| 丝袜肉丝一区二区三区四区在线看| 青草久久视频在线观看| 精品一区二区三区三区88 | 动漫美女的小穴视频| 天天操天天污天天射| 国际av大片在线免费观看| 久久99久久99精品影院| 在线观看的a站 最新| 亚洲欧美成人综合在线观看| 欧美视频一区免费在线| 91桃色成人网络在线观看| 国产乱子伦精品视频潮优女| asmr福利视频在线观看| av完全免费在线观看av| av成人在线观看一区| 国产V亚洲V天堂无码欠欠| av在线免费资源站| 99re国产在线精品| 中文字幕中文字幕 亚洲国产| 久久这里只有精品热视频 | 91人妻精品一区二区在线看| 亚洲一区二区三区在线高清| 亚洲福利精品福利精品福利| 免费观看理论片完整版| 欧美国产亚洲中英文字幕| 亚洲国产在人线放午夜| 北条麻妃av在线免费观看| 欧美va不卡视频在线观看| 亚洲一级av大片免费观看| 人妻少妇av在线观看| 伊人网中文字幕在线视频| 中国无遮挡白丝袜二区精品| 国产精品系列在线观看一区二区| 精品av国产一区二区三区四区| 黄色资源视频网站日韩| 9l人妻人人爽人人爽| 国产在线91观看免费观看| 97人人模人人爽人人喊| 亚洲图库另类图片区| 天干天天天色天天日天天射| 97国产在线av精品| 欧美香蕉人妻精品一区二区| av无限看熟女人妻另类av| 免费看美女脱光衣服的视频| 啊慢点鸡巴太大了啊舒服视频| 三级等保密码要求条款| 一区二区视频在线观看免费观看| 蜜臀av久久久久蜜臀av麻豆| 亚洲综合另类精品小说| 一二三区在线观看视频| 国产福利在线视频一区| 亚洲欧美人精品高清| 在线网站你懂得老司机| 亚洲国产在人线放午夜| 在线免费观看靠比视频的网站| 精品av国产一区二区三区四区| 亚洲熟妇久久无码精品| 91亚洲手机在线视频播放| 天天干天天插天天谢| 国产极品精品免费视频| 99人妻视频免费在线| 五十路丰满人妻熟妇| 久久久久久久一区二区三| 91久久精品色伊人6882| 亚洲青青操骚货在线视频| 亚洲在线一区二区欧美| 国产精品国产三级国产午| 大香蕉伊人国产在线| 99re6热在线精品| 日本av在线一区二区三区| 熟女人妻在线观看视频| 亚洲成人国产综合一区| 91九色国产熟女一区二区| 国产美女午夜福利久久| japanese日本熟妇另类| 天码人妻一区二区三区在线看| 毛片av在线免费看| 国产品国产三级国产普通话三级| 成人30分钟免费视频| 国产成人精品一区在线观看| 日韩欧美一级黄片亚洲| av完全免费在线观看av| 男人在床上插女人视频| 中文字幕综合一区二区| av亚洲中文天堂字幕网| 中国黄片视频一区91| 亚洲国产40页第21页| 开心 色 六月 婷婷| 国产乱弄免费视频观看| 久久久91蜜桃精品ad| 亚洲精品国产在线电影| 粗大的内捧猛烈进出爽大牛汉子| 精品亚洲国产中文自在线| 亚洲成人午夜电影在线观看| 97超碰最新免费在线观看| 中文字幕在线乱码一区二区| 亚洲成高清a人片在线观看| 国产自拍黄片在线观看| 亚洲熟女综合色一区二区三区四区| 日韩美女综合中文字幕pp| 三级等保密码要求条款| 成人H精品动漫在线无码播放| 成人av亚洲一区二区| 538精品在线观看视频| 啪啪啪啪啪啪啪啪av| 摧残蹂躏av一二三区| 亚洲推理片免费看网站| 亚洲区欧美区另类最新章节| 中文字幕成人日韩欧美| 久久久噜噜噜久久熟女av| 国产成人自拍视频播放| 五十路息与子猛烈交尾视频| 日本性感美女视频网站| 夜女神免费福利视频| 中文字母永久播放1区2区3区| 在线免费91激情四射 | 欧美激情电影免费在线| 久久精品亚洲成在人线a| 日日操夜夜撸天天干| 最新91精品视频在线| 亚洲中文字幕国产日韩| 在线视频自拍第三页| 在线观看操大逼视频| 久久艹在线观看视频| 丝袜长腿第一页在线| 一区二区三区四区视频在线播放| 天天操天天污天天射| 中国无遮挡白丝袜二区精品| av乱码一区二区三区| 红桃av成人在线观看| 欧美日韩熟女一区二区三区| 天天日天天干天天爱| 粗大的内捧猛烈进出爽大牛汉子| 天天插天天狠天天操| 特级欧美插插插插插bbbbb| 中文字幕网站你懂的| 老司机福利精品视频在线| 在线国产中文字幕视频| 国产精品国产三级国产午| 少妇系列一区二区三区视频| 一区二区三区久久久91| 9国产精品久久久久老师| 午夜精品亚洲精品五月色| 亚洲av黄色在线网站| 日韩av有码中文字幕| 在线视频自拍第三页| av大全在线播放免费| 18禁污污污app下载| 亚洲变态另类色图天堂网| 人妻丝袜精品中文字幕| 国产精品中文av在线播放| 真实国产乱子伦一区二区| 国产 在线 免费 精品| 视频 国产 精品 熟女 | 中文字幕乱码人妻电影| 97成人免费在线观看网站| 91色网站免费在线观看| 日韩视频一区二区免费观看| 人人妻人人爽人人添夜| 天天夜天天日天天日| 亚欧在线视频你懂的| 九九视频在线精品播放| 摧残蹂躏av一二三区| 狠狠嗨日韩综合久久| 成年美女黄网站18禁久久| 午夜在线观看岛国av,com| 91人妻精品久久久久久久网站| 国产精品一区二区三区蜜臀av| 亚洲一区av中文字幕在线观看| 精品国产成人亚洲午夜| 成人久久精品一区二区三区| 男人靠女人的逼视频| 人人妻人人爽人人澡人人精品| 亚洲中文字幕综合小综合| 在线 中文字幕 一区| 99精品亚洲av无码国产另类| 夜色福利视频在线观看| 制服丝袜在线人妻中文字幕| 在线观看免费视频色97| 懂色av蜜桃a v| 少妇ww搡性bbb91| 噜噜色噜噜噜久色超碰| 97人妻色免费视频| 青青青青操在线观看免费| 日本少妇精品免费视频| 午夜在线精品偷拍一区二| 四虎永久在线精品免费区二区| 1000部国产精品成人观看视频| 久久精品美女免费视频| 丝袜肉丝一区二区三区四区在线看| 激情内射在线免费观看| 综合页自拍视频在线播放| 亚洲色偷偷综合亚洲AV伊人| 揄拍成人国产精品免费看视频| 国产成人精品一区在线观看| 日韩av大胆在线观看| 伊人成人综合开心网| 黄色av网站免费在线| 国产无遮挡裸体免费直播视频| 精品久久久久久高潮| 亚洲成人情色电影在线观看| 国产女人叫床高潮大片视频| 91中文字幕免费在线观看| 久草福利电影在线观看| 人人超碰国字幕观看97| 激情五月婷婷综合色啪| 国产丰满熟女成人视频| 亚洲va欧美va人人爽3p| 中文字幕一区二区人妻电影冢本| 国产性色生活片毛片春晓精品| 成年女人免费播放视频| 国产va精品免费观看| 免费在线观看视频啪啪| 亚洲熟女综合色一区二区三区四区| 亚洲国产中文字幕啊啊啊不行了| 亚洲天堂有码中文字幕视频| 玩弄人妻熟妇性色av少妇| 99国内小视频在现欢看| 国产在线免费观看成人| 美女福利视频网址导航| 超黄超污网站在线观看| 国产综合精品久久久久蜜臀| 青青青青视频在线播放| 国产夫妻视频在线观看免费| 91免费放福利在线观看| 色秀欧美视频第一页| 欧美成人黄片一区二区三区| 天天干夜夜操天天舔| 国产一区二区神马久久| 硬鸡巴动态操女人逼视频| 福利视频一区二区三区筱慧 | 亚洲成人av在线一区二区| 国产熟妇一区二区三区av| 国内精品在线播放第一页| 在线不卡日韩视频播放| 天堂av在线最新版在线| 2025年人妻中文字幕乱码在线| 日本黄色特一级视频| 亚洲少妇高潮免费观看| 99精品国产免费久久| 免费看国产又粗又猛又爽又黄视频| 欧美80老妇人性视频| 一个色综合男人天堂| 非洲黑人一级特黄片| 亚洲少妇高潮免费观看| 香港三日本三韩国三欧美三级| 黑人性生活视频免费看| 97精品视频在线观看| 成人影片高清在线观看| 国产+亚洲+欧美+另类| 中文字幕AV在线免费看 | 欧美视频中文一区二区三区| 成人av久久精品一区二区| 亚洲一级av无码一级久久精品| 伊人情人综合成人久久网小说| 最近中文字幕国产在线| 天天日天天玩天天摸| 亚洲偷自拍高清视频| 激情五月婷婷综合色啪| 国产片免费观看在线观看| 婷婷久久一区二区字幕网址你懂得| 国产熟妇乱妇熟色T区| 自拍偷拍亚洲另类色图| av网址国产在线观看| 日韩熟女av天堂系列| 中文字幕午夜免费福利视频| 在线免费观看视频一二区| 亚洲欧美国产综合777| 国产成人自拍视频播放| 亚洲熟妇x久久av久久| 久久精品美女免费视频| 亚洲熟妇x久久av久久| 2012中文字幕在线高清| 视频久久久久久久人妻| 只有精品亚洲视频在线观看| 国产女孩喷水在线观看| 亚洲国产第一页在线观看| 午夜影院在线观看视频羞羞羞| 国产伊人免费在线播放| 欧美亚洲牲夜夜综合久久| 国产刺激激情美女网站| 中文字幕 亚洲av| 精品欧美一区二区vr在线观看| 北条麻妃av在线免费观看| 亚洲综合在线观看免费| 青娱乐极品视频青青草| 可以免费看的www视频你懂的| 欧美偷拍亚洲一区二区| 成人免费做爰高潮视频| 丝袜肉丝一区二区三区四区在线看| 香港一级特黄大片在线播放| 热思思国产99re| 91成人在线观看免费视频| 人人超碰国字幕观看97| 久久久久只精品国产三级| 天天日夜夜干天天操| 天天草天天色天天干| 久久麻豆亚洲精品av| 国产又粗又硬又大视频| 国产午夜亚洲精品麻豆| 日本18禁久久久久久| 一级黄片久久久久久久久| 亚洲成a人片777777| 老有所依在线观看完整版 | 成人免费公开视频无毒| 在线免费观看国产精品黄色| av天堂中文免费在线| av成人在线观看一区| 亚洲国产免费av一区二区三区 | 欧美综合婷婷欧美综合| 国产剧情演绎系列丝袜高跟| 女蜜桃臀紧身瑜伽裤| 一区二区三区四区五区性感视频| 黑人巨大精品欧美视频| 国产清纯美女al在线| 日韩a级黄色小视频| 欧美日韩情色在线观看| 97人妻夜夜爽二区欧美极品| 92福利视频午夜1000看| 在线观看成人国产电影| 首之国产AV医生和护士小芳| 极品性荡少妇一区二区色欲| 久草视频中文字幕在线观看| 视频在线亚洲一区二区| 亚洲中文字幕人妻一区| 少妇ww搡性bbb91| 免费黄高清无码国产| 亚洲高清国产拍青青草原| 中文字幕在线一区精品| 天天日天天干天天搡| 2018在线福利视频| 蜜臀成人av在线播放| 美女张开腿让男生操在线看| 婷婷午夜国产精品久久久| 亚洲午夜福利中文乱码字幕| 91国产资源在线视频| 日视频免费在线观看| 欧美亚洲自偷自拍 在线| 国产妇女自拍区在线观看| 成人av亚洲一区二区| 91人妻精品久久久久久久网站 | 成人国产激情自拍三区| 国产精品人妻一区二区三区网站| 国产妇女自拍区在线观看| 免费69视频在线看| 天天日天天干天天要| 亚洲中文字幕人妻一区| 视频一区二区三区高清在线| 最近中文字幕国产在线| av日韩在线观看大全| 国产老熟女伦老熟妇ⅹ| 成人精品在线观看视频| 国产白袜脚足J棉袜在线观看| 国产在线自在拍91国语自产精品| 扒开让我视频在线观看| 天天做天天干天天舔| 亚洲av色香蕉一区二区三区| 91亚洲手机在线视频播放| 女蜜桃臀紧身瑜伽裤| 天堂va蜜桃一区入口| 日韩av免费观看一区| 青青青青青手机视频| 中文字幕日本人妻中出| 亚洲高清国产自产av| 中文字幕日韩91人妻在线| 精品人妻一二三区久久| 精品亚洲国产中文自在线| 日噜噜噜夜夜噜噜噜天天噜噜噜| 久久久超爽一二三av| 欧美精品黑人性xxxx| 国产精彩对白一区二区三区| 亚洲综合乱码一区二区| 国产精选一区在线播放| 制丝袜业一区二区三区| 粗大的内捧猛烈进出爽大牛汉子| 国产麻豆国语对白露脸剧情| 欧美一区二区三区四区性视频| 国产91久久精品一区二区字幕| 日韩欧美亚洲熟女人妻| 一二三中文乱码亚洲乱码one| v888av在线观看视频| 国产中文字幕四区在线观看| 日本少妇的秘密免费视频| 最新欧美一二三视频| 97精品综合久久在线| 中国把吊插入阴蒂的视频| 亚洲国产在人线放午夜| 亚洲欧美清纯唯美另类 | 亚洲欧美色一区二区| 久久综合老鸭窝色综合久久| 国产精品国产三级国产精东| 强行扒开双腿猛烈进入免费版| 好太好爽好想要免费| 91极品新人『兔兔』精品新作| 亚洲av无乱一区二区三区性色| 插逼视频双插洞国产操逼插洞| 亚洲 欧美 自拍 偷拍 在线| 国产日韩一区二区在线看 | 韩国一级特黄大片做受| 欧美激情精品在线观看| 午夜精品福利一区二区三区p| 日韩精品二区一区久久| 99精品视频在线观看婷婷| 天天干天天操天天摸天天射| 天天操天天插天天色| 很黄很污很色的午夜网站在线观看| av中文字幕国产在线观看| 亚洲精品久久视频婷婷| 美女视频福利免费看| 适合午夜一个人看的视频| 午夜激情高清在线观看| 天美传媒mv视频在线观看| 亚洲综合另类欧美久久| 青青青国产片免费观看视频| 91精品国产观看免费| 白嫩白嫩美女极品国产在线观看| 欧美在线一二三视频| 一区二区久久成人网| 动漫黑丝美女的鸡巴| 久久www免费人成一看片| 亚洲精品三级av在线免费观看| 国产精品黄色的av| 精品国产午夜视频一区二区| 国产97在线视频观看| 大鸡巴操b视频在线| 一区二区视频在线观看免费观看| 成人30分钟免费视频| 亚洲区欧美区另类最新章节| 亚洲区美熟妇久久久久| 小穴多水久久精品免费看| 自拍偷拍日韩欧美一区二区| 精品首页在线观看视频| sejizz在线视频| gogo国模私拍视频| 国产午夜福利av导航| 天天操天天射天天操天天天| 亚洲国产欧美一区二区三区久久| 亚洲精品国品乱码久久久久| 成人乱码一区二区三区av| 亚洲高清视频在线不卡| 国产成人精品av网站| 人妻另类专区欧美制服| 久久久精品999精品日本| 手机看片福利盒子日韩在线播放| 免费一级特黄特色大片在线观看| www久久久久久久久久久| 风流唐伯虎电视剧在线观看| 亚洲最大免费在线观看| 日韩a级精品一区二区| 精品国产午夜视频一区二区| 中文字幕乱码人妻电影| 精品91高清在线观看| 91人妻人人做人人爽在线| 日韩中文字幕福利av| 日本熟女50视频免费| 天天操天天插天天色| 久久精品亚洲成在人线a| 成人乱码一区二区三区av| 亚洲成a人片777777| 欧美一级片免费在线成人观看| 免费在线看的黄网站| 91国内精品自线在拍白富美| av亚洲中文天堂字幕网| 日本性感美女写真视频| 国产福利小视频免费观看| 青青青青青免费视频| 中文字幕乱码人妻电影| 韩国亚洲欧美超一级在线播放视频| 亚洲国产美女一区二区三区软件| 日本脱亚入欧是指什么| 护士特殊服务久久久久久久| 国产性色生活片毛片春晓精品| 不卡日韩av在线观看| 天天做天天爽夜夜做少妇| 国产亚洲国产av网站在线| 晚上一个人看操B片| 午夜久久久久久久99| brazzers欧熟精品系列| 噜噜色噜噜噜久色超碰| 亚洲图片偷拍自拍区| 5528327男人天堂| 大陆精品一区二区三区久久| 久久99久久99精品影院| 一区二区在线视频中文字幕| 一区二区三区精品日本| asmr福利视频在线观看| 国产熟妇人妻ⅹxxxx麻豆| 天天做天天干天天操天天射| 久久久久久久精品老熟妇| 99热这里只有国产精品6| 中文字幕av第1页中文字幕| 精品suv一区二区69| 久久一区二区三区人妻欧美 | 传媒在线播放国产精品一区| 日辽宁老肥女在线观看视频| 亚洲一区二区三区偷拍女厕91| 国产视频在线视频播放| 国产三级片久久久久久久| 精品一线二线三线日本| 日韩一个色综合导航| 最近中文字幕国产在线| 亚洲午夜电影之麻豆| 3337p日本欧洲大胆色噜噜| 日本少妇人妻xxxxx18| 国际av大片在线免费观看| 一区二区三区av高清免费| 日韩人妻在线视频免费| 少妇人妻100系列| 五月色婷婷综合开心网4438| 老熟妇xxxhd老熟女| 亚洲熟女女同志女同| 漂亮 人妻被中出中文| 亚洲卡1卡2卡三卡四老狼| 在线视频这里只有精品自拍| 亚洲男人的天堂a在线| 超碰97人人澡人人| 青青青青视频在线播放| 午夜在线一区二区免费| 亚洲 人妻 激情 中文| sejizz在线视频| av天堂加勒比在线| 久久久久久久精品成人热| 免费看国产又粗又猛又爽又黄视频| 在线视频国产欧美日韩| 自拍偷拍亚洲精品第2页| 日本av高清免费网站| 男人的天堂在线黄色| 国产一区二区三免费视频| 91片黄在线观看喷潮| 青青操免费日综合视频观看| 午夜成午夜成年片在线观看| 中文字幕+中文字幕| 亚洲av日韩精品久久久久久hd| 免费人成黄页网站在线观看国产| av中文字幕在线观看第三页| 天天通天天透天天插| 青青青视频手机在线观看| 一级黄片大鸡巴插入美女| 揄拍成人国产精品免费看视频| 中国无遮挡白丝袜二区精品| 91亚洲精品干熟女蜜桃频道| 国产高清精品极品美女| 欧美日韩高清午夜蜜桃大香蕉| 欧美成人黄片一区二区三区 | 40道精品招牌菜特色| h国产小视频福利在线观看| 天天日天天鲁天天操| 熟女少妇激情五十路| 国产精品一区二区av国| 国产精品三级三级三级| 男人的天堂在线黄色| 91精品免费久久久久久| 97人妻总资源视频| 男人天堂最新地址av| 清纯美女在线观看国产| 福利视频一区二区三区筱慧| 国产免费av一区二区凹凸四季| 内射久久久久综合网| 日本熟女50视频免费| 亚洲伊人av天堂有码在线| 2020国产在线不卡视频| 黄色视频成年人免费观看| 黄片三级三级三级在线观看| 国产三级影院在线观看| 少妇与子乱在线观看| 亚洲中文字字幕乱码| 五月天久久激情视频| 国产91嫩草久久成人在线视频| 精品久久久久久高潮| 国产va在线观看精品| 中文字幕无码一区二区免费| av无限看熟女人妻另类av| 日本精品视频不卡一二三| 国产美女精品福利在线| 啊啊啊想要被插进去视频| 免费观看丰满少妇做受| 内射久久久久综合网| 久久久极品久久蜜桃| 岛国av高清在线成人在线| 国产福利在线视频一区| 青青青视频手机在线观看| 午夜精品亚洲精品五月色| 老师啊太大了啊啊啊尻视频| 五十路av熟女松本翔子| 丝袜美腿欧美另类 中文字幕| 欧美精产国品一二三产品区别大吗| 92福利视频午夜1000看 | 欧美精品资源在线观看| 1024久久国产精品| 巨乳人妻日下部加奈被邻居中出| 亚洲 自拍 色综合图| 五十路av熟女松本翔子| 亚洲av色图18p| 日本韩国免费一区二区三区视频| 亚洲的电影一区二区三区| 只有精品亚洲视频在线观看| 久久www免费人成一看片| 欧美女同性恋免费a| 日韩成人综艺在线播放| 99热99这里精品6国产| 亚洲护士一区二区三区| 亚洲国产精品久久久久蜜桃| 久草视频首页在线观看| 99热99re在线播放| 九色porny九色9l自拍视频| 中文字幕一区的人妻欧美日韩| 2022天天干天天操| 中文字幕成人日韩欧美| 国产一区二区三免费视频| 97超碰最新免费在线观看| 欧美3p在线观看一区二区三区| 国产欧美精品一区二区高清 | 中文字幕亚洲久久久| 日韩美av高清在线| 在线亚洲天堂色播av电影| 天天射夜夜操狠狠干| 少妇人妻100系列| 日韩美av高清在线| 中文字幕高清免费在线人妻| 亚洲国产精品美女在线观看| 在线国产中文字幕视频| 一区二区三区久久中文字幕| 日韩一区二区三区三州| 2021国产一区二区| 国产成人自拍视频播放| 91免费观看国产免费| 午夜国产免费福利av| 综合色区亚洲熟妇shxstz| 大香蕉伊人中文字幕| 熟女少妇激情五十路| 成人久久精品一区二区三区| 丰满少妇翘臀后进式| 成人免费公开视频无毒| 欧美日韩情色在线观看| 加勒比视频在线免费观看 | 亚洲精品福利网站图片| 欧美综合婷婷欧美综合| 亚洲福利天堂久久久久久| 亚洲va国产va欧美精品88| 中文字幕一区二区人妻电影冢本| 91久久精品色伊人6882| 五月精品丁香久久久久福利社| 天堂av中文在线最新版| 婷婷五月亚洲综合在线| 伊人综合免费在线视频| 999久久久久999| 免费黄高清无码国产| 欧洲欧美日韩国产在线| 久久免费看少妇高潮完整版| 精彩视频99免费在线| 777奇米久久精品一区| 国产在线免费观看成人| 水蜜桃一区二区三区在线观看视频| 一级黄片久久久久久久久| 久草视频在线一区二区三区资源站| 中文字幕人妻三级在线观看| 国产九色91在线观看精品| 色婷婷精品大在线观看| 2o22av在线视频| 女同互舔一区二区三区| 欧美国产亚洲中英文字幕| 欲满人妻中文字幕在线| 91精品国产综合久久久蜜| 亚洲高清自偷揄拍自拍| 日本啪啪啪啪啪啪啪| 欧美成人综合视频一区二区| 欧美 亚洲 另类综合| 成熟丰满熟妇高潮xx×xx| 欧美一区二区三区在线资源 | 毛片一级完整版免费| 又色又爽又黄又刺激av网站| 精品成人午夜免费看| 色吉吉影音天天干天天操| 日韩在线视频观看有码在线| 亚洲av午夜免费观看| 亚洲av天堂在线播放| 久久综合老鸭窝色综合久久| 午夜精品一区二区三区福利视频| 日韩欧美一级黄片亚洲| 喷水视频在线观看这里只有精品| 91色老99久久九九爱精品| 在线观看免费av网址大全| 国际av大片在线免费观看| 99国内小视频在现欢看| 成年午夜免费无码区| 精品亚洲国产中文自在线| 特级无码毛片免费视频播放 | 55夜色66夜色国产精品站| 可以免费看的www视频你懂的| 可以在线观看的av中文字幕| 国产精品精品精品999| 91社福利《在线观看| 无忧传媒在线观看视频| 亚洲一区二区三区久久受| 成人30分钟免费视频| 亚洲无线观看国产高清在线| 天天插天天狠天天操| 亚洲国产欧美一区二区丝袜黑人| 岛国av高清在线成人在线| 国产va精品免费观看 | av森泽佳奈在线观看| 亚洲av日韩av网站| 狠狠嗨日韩综合久久| 亚洲精品在线资源站| 最新中文字幕乱码在线| 手机看片福利盒子日韩在线播放| 天堂av狠狠操蜜桃| 2022精品久久久久久中文字幕| 在线观看视频污一区| 玩弄人妻熟妇性色av少妇| 日韩写真福利视频在线观看| 女生自摸在线观看一区二区三区| 亚洲精品欧美日韩在线播放| 中文字幕综合一区二区| 51精品视频免费在线观看| 偷拍自拍视频图片免费| 黄色男人的天堂视频| 黑人借宿ntr人妻的沦陷2| 一区二区麻豆传媒黄片| 天天干天天日天天干天天操| 80电影天堂网官网| 亚洲成a人片777777| 国产麻豆剧传媒精品国产av蜜桃| 哥哥姐姐综合激情小说| av中文字幕在线观看第三页| 欧美成人一二三在线网| 天天插天天色天天日| 国产性生活中老年人视频网站| 国产揄拍高清国内精品对白| 91成人精品亚洲国产| 久久热这里这里只有精品| 亚洲成人熟妇一区二区三区| 成人激情文学网人妻| 国产视频在线视频播放| 毛茸茸的大外阴中国视频| 日本特级片中文字幕| 久久丁香花五月天色婷婷| 久久亚洲天堂中文对白| 在线 中文字幕 一区| 亚洲欧美久久久久久久久| 黑人进入丰满少妇视频| 麻豆精品成人免费视频| 国产性感美女福利视频| 不戴胸罩引我诱的隔壁的人妻| 超碰公开大香蕉97| 日本在线不卡免费视频| 亚洲精品在线资源站| 91成人精品亚洲国产| 99久久99久国产黄毛片| 999九九久久久精品| 日本韩国免费福利精品| 天天日天天干天天爱| 直接能看的国产av| av完全免费在线观看av| 天天日夜夜干天天操| 韩国男女黄色在线观看| 春色激情网欧美成人| 青娱乐在线免费视频盛宴| 欧美区一区二区三视频| 边摸边做超爽毛片18禁色戒 | 国产高清精品极品美女| 国产av欧美精品高潮网站| 亚洲成人午夜电影在线观看| 国产黄色高清资源在线免费观看| 大肉大捧一进一出好爽在线视频| 内射久久久久综合网| 国产黄色a级三级三级三级| 亚洲av日韩精品久久久久久hd| 五十路丰满人妻熟妇| 老师啊太大了啊啊啊尻视频| 亚洲伊人久久精品影院一美女洗澡 | 偷拍自拍福利视频在线观看| 日韩中文字幕精品淫| 岛国一区二区三区视频在线| 午夜精品久久久久久99热| 亚洲精品ww久久久久久| 男人插女人视频网站| 在线观看操大逼视频| 中国熟女一区二区性xx| 少妇高潮一区二区三区| 国产精品国产三级麻豆| 免费男阳茎伸入女阳道视频 | 插逼视频双插洞国产操逼插洞 | 亚洲国产精品黑丝美女| 亚洲欧美日韩视频免费观看| 中文字幕一区二区人妻电影冢本| 欧美性感尤物人妻在线免费看| 中文字幕无码一区二区免费| 无码日韩人妻精品久久| av在线观看网址av| 亚洲一区二区激情在线| 99热99这里精品6国产| 操人妻嗷嗷叫视频一区二区| 99精品一区二区三区的区| 国产精品手机在线看片| 亚欧在线视频你懂的| 亚洲av天堂在线播放| 亚洲 人妻 激情 中文| 国产精品系列在线观看一区二区 | 黄色大片男人操女人逼| 天堂av中文在线最新版| 欧美黑人性暴力猛交喷水| 75国产综合在线视频| 黄色av网站免费在线| 五十路人妻熟女av一区二区 | 91she九色精品国产| 天天日天天添天天爽| 国产精品久久久久久美女校花| 日本精品一区二区三区在线视频。| 欧美香蕉人妻精品一区二区| 国产亚洲成人免费在线观看| 国产日本欧美亚洲精品视| 婷婷午夜国产精品久久久| 亚洲免费va在线播放| 888亚洲欧美国产va在线播放| 欧美黑人性猛交xxxxⅹooo| 精品久久久久久久久久久a√国产 日本女大学生的黄色小视频 | 黑人巨大精品欧美视频| 涩涩的视频在线观看视频| 五十路人妻熟女av一区二区| 91麻豆精品传媒国产黄色片| 人妻3p真实偷拍一二区| 少妇与子乱在线观看| 五色婷婷综合狠狠爱| 国产av国片精品一区二区| 青青草精品在线视频观看| 婷婷综合亚洲爱久久| 男生用鸡操女生视频动漫| 78色精品一区二区三区| 亚洲高清一区二区三区视频在线| 欧美日韩一区二区电影在线观看| 国产日韩欧美视频在线导航| 天天做天天干天天舔| 少妇人妻真实精品视频| 熟妇一区二区三区高清版| 日韩影片一区二区三区不卡免费| 国产女人露脸高潮对白视频| japanese日本熟妇另类| 久久www免费人成一看片| 女同性ⅹxx女同h偷拍| 日本女大学生的黄色小视频| 青青草精品在线视频观看| 亚洲av无码成人精品区辽| 中文字幕一区二区自拍| 久久午夜夜伦痒痒想咳嗽P| 国产综合高清在线观看| 99re国产在线精品| 香蕉91一区二区三区| 一本一本久久a久久精品综合不卡| 伊人综合aⅴ在线网| 国产一区二区欧美三区| 亚洲一区久久免费视频| 经典国语激情内射视频| 人人妻人人爱人人草| 人人妻人人澡欧美91精品| 亚洲麻豆一区二区三区| 亚洲的电影一区二区三区| 国产精品久久久久久久精品视频| 一级A一级a爰片免费免会员| 真实国产乱子伦一区二区| 含骚鸡巴玩逼逼视频| 中文字幕—97超碰网| 青青草原网站在线观看| 亚洲精品午夜久久久久| 韩国亚洲欧美超一级在线播放视频| 最后99天全集在线观看| 白嫩白嫩美女极品国产在线观看| 天堂中文字幕翔田av| 亚洲欧美人精品高清| 欧美熟妇一区二区三区仙踪林| av网址在线播放大全| 91色网站免费在线观看| 家庭女教师中文字幕在线播放| 爆乳骚货内射骚货内射在线| 欧美女同性恋免费a| 天天草天天色天天干| 天天日天天日天天擦| 姐姐的朋友2在线观看中文字幕| 国产午夜激情福利小视频在线| 亚洲色偷偷综合亚洲AV伊人| 日韩无码国产精品强奸乱伦| 蝴蝶伊人久久中文娱乐网| 一二三区在线观看视频| 污污小视频91在线观看| 99精品视频在线观看免费播放| 国产欧美精品一区二区高清 | 欧美一区二区三区四区性视频| 天天色天天操天天舔| 欧美日韩高清午夜蜜桃大香蕉| 操操网操操伊剧情片中文字幕网| 青青青青青青青在线播放视频| 精品久久久久久高潮| 色伦色伦777国产精品| 亚洲公开视频在线观看| 国产janese在线播放| 成人av天堂丝袜在线观看| 91九色porny蝌蚪国产成人| 日韩人妻xxxxx| 午夜在线一区二区免费| 天天干天天啪天天舔| nagger可以指黑人吗| 含骚鸡巴玩逼逼视频| 午夜美女少妇福利视频| 国产精彩福利精品视频| 国产极品美女久久久久久| 婷婷综合蜜桃av在线| 91香蕉成人app下载| 国产麻豆国语对白露脸剧情| 日本xx片在线观看| 国产露脸对白在线观看| av俺也去在线播放| 青青青青视频在线播放| 成人蜜臀午夜久久一区| 国产普通话插插视频| 亚洲欧美色一区二区| 美女av色播在线播放| 97色视频在线观看| 国产日韩一区二区在线看 | 日日日日日日日日夜夜夜夜夜夜| 欧美日韩一区二区电影在线观看| 人人妻人人爽人人澡人人精品| 午夜大尺度无码福利视频| 少妇露脸深喉口爆吞精| 天天干夜夜操啊啊啊| 人妻av无码专区久久绿巨人| 亚洲一级av无码一级久久精品| 漂亮 人妻被中出中文| 好吊视频—区二区三区| 免费在线看的黄片视频| 人人在线视频一区二区| 国产在线观看黄色视频| 亚洲成人精品女人久久久| 欧美亚洲国产成人免费在线 | 日韩欧美一级精品在线观看| 国产日韩精品免费在线| 沙月文乃人妻侵犯中文字幕在线| av一区二区三区人妻| 18禁污污污app下载| 扒开腿挺进肉嫩小18禁视频| 久碰精品少妇中文字幕av| 精品suv一区二区69| 亚洲熟女久久久36d| 999久久久久999| 亚洲欧美自拍另类图片| 国产精品久久久久久美女校花| 99一区二区在线观看| 成人亚洲精品国产精品| 在线播放国产黄色av| 国产熟妇乱妇熟色T区| 中文字幕免费福利视频6| 大香蕉大香蕉大香蕉大香蕉大香蕉| 少妇人妻久久久久视频黄片| 亚洲欧美另类手机在线| av手机在线观播放网站| 精品视频国产在线观看| 午夜精品九一唐人麻豆嫩草成人| 亚洲成人情色电影在线观看| 夜夜嗨av蜜臀av| 免费看国产又粗又猛又爽又黄视频| av天堂中文字幕最新| 天天插天天色天天日| 日本熟女精品一区二区三区| 久久精品美女免费视频| 搡老熟女一区二区在线观看| 欧美怡红院视频在线观看| 激情色图一区二区三区| 狠狠躁狠狠爱网站视频| 99热久久极品热亚洲| japanese五十路熟女熟妇| 日本黄在免费看视频| 精品人妻每日一部精品| 开心 色 六月 婷婷| 免费观看成年人视频在线观看| 天天草天天色天天干| 同居了嫂子在线播高清中文| 男生用鸡操女生视频动漫| 婷婷久久久综合中文字幕| 亚洲精品久久视频婷婷| 3337p日本欧洲大胆色噜噜| 99av国产精品欲麻豆| 国产亚洲欧美视频网站| 不卡一区一区三区在线| 国产刺激激情美女网站| 操操网操操伊剧情片中文字幕网| 端庄人妻堕落挣扎沉沦| 国产精品自拍在线视频| 亚洲中文字幕人妻一区| 男生舔女生逼逼视频| 天天日天天舔天天射进去| 久草视频在线一区二区三区资源站| 国产午夜福利av导航| 亚洲人妻av毛片在线| 亚洲一区二区三区久久午夜| 激情国产小视频在线| 97人妻夜夜爽二区欧美极品| 神马午夜在线观看视频| 91久久国产成人免费网站| 成人av久久精品一区二区| 亚洲熟女久久久36d| 国产精品人妻熟女毛片av久| 老司机福利精品视频在线| 天天操天天弄天天射| 亚洲麻豆一区二区三区| 国产一区二区火爆视频| 自拍 日韩 欧美激情| 自拍偷拍,中文字幕| 亚洲最大黄 嗯色 操 啊| 自拍偷拍亚洲另类色图| 中文字幕在线永久免费播放| 国产日韩欧美视频在线导航| 九九热99视频在线观看97| 清纯美女在线观看国产| 国产美女精品福利在线| 美女日逼视频免费观看| 大胆亚洲av日韩av| 国产午夜福利av导航| 欧亚乱色一区二区三区| 一区二区三区日韩久久| 色哟哟在线网站入口| 插逼视频双插洞国产操逼插洞| 成年人午夜黄片视频资源| 亚洲欧美激情国产综合久久久| 天天干天天操天天玩天天射| 青娱乐最新视频在线| 91自产国产精品视频| 毛茸茸的大外阴中国视频| 一区二区久久成人网| av欧美网站在线观看| 久久机热/这里只有| 春色激情网欧美成人| 男人靠女人的逼视频| gav成人免费播放| 欧美激情电影免费在线| 4个黑人操素人视频网站精品91| 日本欧美视频在线观看三区| 91麻豆精品传媒国产黄色片| 91精品国产观看免费| 91中文字幕免费在线观看| 91社福利《在线观看| 日韩美女搞黄视频免费| 中文字幕人妻一区二区视频| 免费69视频在线看| 亚洲2021av天堂| 99精品免费久久久久久久久a| 成人伊人精品色xxxx视频| 天天做天天干天天舔| 香港三日本三韩国三欧美三级| 久久久久国产成人精品亚洲午夜| 超碰97免费人妻麻豆| 中文字幕高清资源站| 天天操天天爽天天干| 亚洲av一妻不如妾| 扒开腿挺进肉嫩小18禁视频| 成人影片高清在线观看|