spring boot的常用註解有哪些?

蝴蝶飛啊飛發表於2019-09-27

一、什麼是SpringBoot?

SpringBoot 是一個快速開發框架,快速的將一些常用的第三方依賴整合(原理:通過 Maven 子父工程的方式),簡化 XML 配置,全部採用註解形式,內建 Http 伺服器( Jetty Tomcat ),最終以 java 應用程式進行執行。

二、SpringBoot 核心原理

1> 基於 SpringMVC 無配置檔案(純 Java )完全註解化 + 內建 tomcat-embed-core 實現 SpringBoot 框架, Main 函式啟動。

2> SpringBoot 核心快速整合第三方框架原理 :Maven 繼承依賴關係。

三、SpringBoot 重點

3.1: 快速整合第三方依賴: maven 子父依賴關係。

springboot 通過引用 spring-boot-starter-web 依賴,整合 SpingMVC 框架。只需要引用一個 jar 包,就可以通過 Maven 繼承的方式引用到 Spring-aop,Spring-beans,Spring-core,Spring-web 等相關依賴。

<parent>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-parent</artifactId>

<version>2.0.0.RELEASE</version>

</parent>

<dependencies>

<!-- SpringBoot 整合 SpringMVC -->

<!-- 為什麼我們映入 spring-boot-starter-web 能夠幫我整合 Spring 環境 原理通過 Maven 子父工程 -->

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-web</artifactId>

</dependency>

</dependencies>

springBoot 框架流程:先建立 Tomcat 容器,然後載入 class 檔案,載入過程中如果發現有 java 程式碼編寫的 SpringMVC 初始化,就會建立 SpringMVC 容器。所有程式執行完畢後,專案就可以訪問了。

四、SpringBoot 常用註解

1 @RestController @RequestMapping 註解

@RestController 註解,它繼承自 @Controller 註解。 4.0 之前的版本, Spring MVC 的元件都使用 @Controller 來標識當前類是一個控制器 servlet 。使用這個特性,我們可以開發 REST 服務的時候不需要使用 @Controller 而專門的 @RestController

當你實現一個RESTful web services 的時候, response 將一直通過 response body 傳送。為了簡化開發, Spring 4.0 提供了一個專門版本的 controller 。下面我們來看看 @RestController 實現的定義:

  @Target(value=TYPE)    

  @Retention(value=RUNTIME)    

  @Documented    

  @Controller    

  @ResponseBody    

 public @interface RestController

注: @RestController @RequestMapping 註解是 Spring MVC 註解(它們不是 Spring Boot 的特定部分)

2 @EnableAutoConfiguration 註解

第二個類級別的註解是 @EnableAutoConfiguration 。這個註解告訴 Spring Boot 根據新增的 jar 依賴猜測你想如何配置 Spring 。由於 spring-boot-starter-web 新增了 Tomcat Spring MVC ,所以 auto-configuration 將假定你正在開發一個 web 應用並相應地對 Spring 進行設定。 Starter POMs Auto-Configuration :設計 auto-configuration 的目的是更好的使用 "Starter POMs" ,但這兩個概念沒有直接的聯絡。你可以自由地挑選 starter POMs 以外的 jar 依賴,並且 Spring Boot 將仍舊盡最大努力去自動配置你的應用。

你可以通過將 @EnableAutoConfiguration @SpringBootApplication 註解新增到一個 @Configuration 類上來選擇自動配置。

注:你只需要新增一個 @EnableAutoConfiguration 註解。我們建議你將它新增到主 @Configuration 類上。

如果發現應用了你不想要的特定自動配置類,你可以使用 @EnableAutoConfiguration 註解的排除屬性來禁用它們。

<pre name="code">import org.springframework.boot.autoconfigure.*;  

     import org.springframework.boot.autoconfigure.jdbc.*;  

     import org.springframework.context.annotation.*;  

     @Configuration  

     @EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class})  

     public class MyConfiguration {  

     }  

3 @Configuration

Spring Boot 提倡基於 Java 的配置。儘管你可以使用一個 XML 源來呼叫 SpringApplication.run() ,我們通常建議你使用 @Configuration 類作為主要源。一般定義外匯返傭http://www.fx61.com/ 方法的類也是主要 @Configuration 的一個很好候選。你不需要將所有的 @Configuration 放進一個單獨的類。 @Import 註解可以用來匯入其他配置類。另外,你也可以使用 @ComponentScan 註解自動收集所有的 Spring 元件,包括 @Configuration 類。

如果你絕對需要使用基於XML 的配置,我們建議你仍舊從一個 @Configuration 類開始。你可以使用附加的 @ImportResource 註解載入 XML 配置檔案。

@Configuration 註解該類,等價 與 XML 中配置 beans ;用 @Bean 標註方法等價於 XML 中配置 bean

@ComponentScan(basePackages = "com.hyxt",includeFilters = {@ComponentScan.Filter(Aspect.class)})

4 @SpringBootApplication

很多Spring Boot 開發者總是使用 @Configuration @EnableAutoConfiguration @ComponentScan 註解他們的 main 類。由於這些註解被如此頻繁地一塊使用(特別是你遵循以上最佳實踐時), Spring Boot 提供一個方便的 @SpringBootApplication 選擇。

@SpringBootApplication 註解等價於以預設屬性使用 @Configuration @EnableAutoConfiguration @ComponentScan

package com.example.myproject;  

    import org.springframework.boot.SpringApplication;  

    import org.springframework.boot.autoconfigure.SpringBootApplication;  

    @SpringBootApplication // same as @Configuration @EnableAutoConfiguration @ComponentScan  

    public class Application {  

        public static void main(String[] args) {  

            SpringApplication.run(Application.class, args);  

        }  

    }

Spring Boot 將嘗試校驗外部的配置,預設使用 JSR-303 (如果在 classpath 路徑中)。你可以輕鬆的為你的 @ConfigurationProperties 類新增 JSR-303 javax.validation 約束註解:

@Component  

    @ConfigurationProperties(prefix="connection")  

    public class ConnectionSettings {  

    @NotNull  

    private InetAddress remoteAddress;  

    // ... getters and setters  

    }

5 @ResponseBody

表示該方法的返回結果直接寫入HTTP response body

一般在非同步獲取資料時使用,在使用@RequestMapping 後,返回值通常解析為跳轉路徑,加上

@responsebody 後返回結果不會被解析為跳轉路徑,而是直接寫入 HTTP response body 中。比如

非同步獲取json 資料,加上 @responsebody 後,會直接返回 json 資料。

6 @Component

泛指元件,當元件不好歸類的時候,我們可以使用這個註解進行標註。一般公共的方法我會用上這個註解

7 @AutoWired

byType 方式。把配置好的 Bean 拿來用,完成屬性、方法的組裝,它可以對類成員變數、方法及構

造函式進行標註,完成自動裝配的工作。

當加上(required=false )時,就算找不到 bean 也不報錯。

8 @RequestParam

用在方法的引數前面:

@RequestParam String a =request.getParameter("abc")

9 @PathVariable

路徑變數。

RequestMapping("user/get/mac/{macAddress}")  

     public String getByMacAddress(@PathVariable String macAddress){  

      //can do something;  

     }  

引數與大括號裡的名字一樣要相同。

以上註解的示範

/**

 * 使用者進行評論及對評論進行管理的 Controller 類;

 */  

@Controller  

@RequestMapping("/msgCenter")  

public class MyCommentController extends BaseController {  

    @Autowired  

    CommentService commentService;  

    @Autowired  

    OperatorService operatorService;  

    /**

     * 新增活動評論;

     *

     * @param applyId 活動 ID

     * @param content 評論內容;

     * @return

     */  

    @ResponseBody  

    @RequestMapping("/addComment")  

    public Map<String, Object> addComment(@RequestParam("applyId") Integer applyId, @RequestParam("content") String content) {  

        ....  

        return result;  

    }  

}

10 @ControllerAdvice

全域性處理異常的:

@ControllerAdvice

包含@Component 。可以被掃描到。

統一處理異常。

@ExceptionHandler Exception.class ):

用在方法上面表示遇到這個異常就執行以下方法。

/**

 * 全域性異常處理

 */  

@ControllerAdvice  

class GlobalDefaultExceptionHandler {  

    public static final String DEFAULT_ERROR_VIEW = "error";  

    @ExceptionHandler({TypeMismatchException.class,NumberFormatException.class})  

    public ModelAndView formatErrorHandler(HttpServletRequest req, Exception e) throws Exception {  

        ModelAndView mav = new ModelAndView();  

        mav.addObject("error"," 引數型別錯誤 ");  

        mav.addObject("exception", e);  

        mav.addObject("url", RequestUtils.getCompleteRequestUrl(req));  

        mav.addObject("timestamp", new Date());  

        mav.setViewName(DEFAULT_ERROR_VIEW);  

        return mav;  

}}

11 @ComponentScan

做過web 開發的同學一定都有用過 @Controller @Service @Repository 註解,檢視其原始碼你會發現,他們中有一個共同的註解 @Component ,沒錯 @ComponentScan 註解預設就會裝配標識了 @Controller @Service @Repository @Component 註解的類到 spring 容器中。

@ComponentScan(value = "com.abacus.check.api")

public class CheckApiApplication {

    public static void main(String[] args) {

        SpringApplication.run(CheckApiApplication.class, args);

    }

}

@SpringBootApplication 註解也包含了 @ComponentScan 註解,所以在使用中我們也可以通過 @SpringBootApplication 註解的 scanBasePackages 屬性進行配置。

@SpringBootApplication(scanBasePackages = {"com.abacus.check.api", "com.abacus.check.service"})

public class CheckApiApplication {

    public static void main(String[] args) {

        SpringApplication.run(CheckApiApplication.class, args);

    }

}

12 @Conditional

@Conditional Spring4 新提供的註解,通過 @Conditional 註解可以根據程式碼中設定的條件裝載不同的 bean ,在設定條件註解之前,先要把裝載的 bean 類去實現 Condition 介面,然後對該實現介面的類設定是否裝載的條件。 Spring Boot 註解中的 @ConditionalOnProperty @ConditionalOnBean 等以 @Conditional* 開頭的註解,都是通過整合了 @Conditional 來實現相應功能的。

@Conditional 的定義:

// 此註解可以標註在類和方法上 @Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Conditional { Class<? extends Condition>[] value(); }

從程式碼中可以看到,需要傳入一個Class 陣列,並且需要繼承 Condition 介面:

public interface Condition { boolean matches(ConditionContext var1, AnnotatedTypeMetadata var2); }

Condition 是個介面,需要實現 matches 方法,返回 true 則注入 bean false 則不注入。

示例:

首先,建立Person 類:

public class Person {

private String name;

private Integer age;

public String getName() { return name; }

 public void setName(String name) { this.name = name; }

public Integer getAge() { return age; }

public void setAge(Integer age) { this.age = age; }

public Person(String name, Integer age) { this.name = name; this.age = age; }

 @Override

public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; } }

建立BeanConfig 類,用於配置兩個 Person 例項並注入,一個是比爾蓋茲,一個是林納斯。

@Configuration

public class BeanConfig {

@Bean(name = "bill")

public Person person1(){ return new Person("Bill Gates",62); }

@Bean("linus")

public Person person2(){ return new Person("Linus",48); }

}

接著寫一個測試類進行驗證這兩個Bean 是否注入成功。

public class ConditionalTest {

AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeanConfig.class);

@Test

public void test1(){

Map<String, Person> map = applicationContext.getBeansOfType(Person.class); System.out.println(map);

    }

}

  執行,輸出結果是這樣的,兩個 Person 例項被注入進容器。

執行,輸出結果是這樣的,兩個Person 例項被注入進容器。

這是一個簡單的例子,現在問題來了,如果我想根據當前作業系統來注入Person 例項, windows 下注入 bill linux 下注入 linus ,怎麼實現呢?

  這就需要我們用到 @Conditional 註解了,前言中提到,需要實現 Condition 介面,並重寫方法來自定義 match 規則。

首先,建立一個WindowsCondition 類:

public class WindowsCondition implements Condition {

/**

 * @param conditionContext: 判斷條件能使用的上下文環境

 * @param annotatedTypeMetadata: 註解所在位置的註釋資訊

 * */

@Override public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {

// 獲取 ioc 使用的 beanFactory

ConfigurableListableBeanFactory beanFactory = conditionContext.getBeanFactory();

// 獲取類載入器

ClassLoader classLoader = conditionContext.getClassLoader();

// 獲取當前環境資訊

Environment environment = conditionContext.getEnvironment();

// 獲取 bean 定義的註冊類

BeanDefinitionRegistry registry = conditionContext.getRegistry();

 // 獲得當前系統名

String property = environment.getProperty("os.name");

// 包含 Windows 則說明是 windows 系統,返回 true

 if (property.contains("Windows")){

        return true;

    }

return false;

    }

}

matches 方法的兩個引數的意思在註釋中講述了,值得一提的是, conditionContext 提供了多種方法,方便獲取各種資訊,也是 SpringBoot @ConditonalOnXX 註解多樣擴充套件的基礎。

接著,建立LinuxCondition 類:

public class LinuxCondition implements Condition {

@Override

public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {

Environment environment = conditionContext.getEnvironment();

String property = environment.getProperty("os.name");

if (property.contains("Linux")){

         return true;

        }

        return false;

    }

}

接著就是使用這兩個類了,因為此註解可以標註在方法上和類上,所以分開測試:

標註在方法上:

修改BeanConfig

@Configuration

public class BeanConfig {

// 只有一個類時,大括號可以省略

// 如果 WindowsCondition 的實現方法返回 true ,則注入這個 bean @Conditional({WindowsCondition.class})

@Bean(name = "bill")

 public Person person1(){

        return new Person("Bill Gates",62);

    }

// 如果 LinuxCondition 的實現方法返回 true ,則注入這個 bean

@Conditional({LinuxCondition.class})

 @Bean("linus")

public Person person2(){

        return new Person("Linus",48);

     }

}

修改測試方法,使其可以列印當前系統名:

執行結果如下:

我是執行在windows 上的所以只注入了 bill ,嗯,沒毛病。

接著實驗linux 下的情況,不能執行在 linux 下,但可以修改執行時引數:

修改後啟動測試方法:

  一個方法只能注入一個 bean 例項,所以 @Conditional 標註在方法上只能控制一個 bean 例項是否注入。

標註在類上:

一個類中可以注入很多例項,@Conditional 標註在類上就決定了一批 bean 是否注入。

我們試一下,將BeanConfig 改寫,這時,如果 WindowsCondition 返回 true ,則兩個 Person 例項將被注入 ( 注意:上一個測試將 os.name 改為 linux ,這是我將把這個引數去掉 )

@Conditional({WindowsCondition.class})

@Configuration

public class BeanConfig {

@Bean(name = "bill")

public Person person1(){

        return new Person("Bill Gates",62);

    }

@Bean("linus")

public Person person2(){

        return new Person("Linus",48);

    }

}

結果兩個例項都被注入: 

如果將類上的WindowsCondition.class 改為 LinuxCondition.class ,結果應該可以猜到:

結果就是空的,類中所有bean 都沒有注入。

多個條件類:

前言中說,@Conditional 註解傳入的是一個 Class 陣列,存在多種條件類的情況。

這種情況貌似判斷難度加深了,測試一波,新增新的條件類,實現的matches 返回 false (這種寫死返回 false 的方法純屬測試用,沒有實際意義 O( _ )O

public class ObstinateCondition implements Condition {

 @Override

public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {

        return false;

    }

}

BeanConfig 修改一下:

@Conditional({WindowsCondition.class,ObstinateCondition.class})

@Configuration

public class BeanConfig {

@Bean(name = "bill")

public Person person1(){

        return new Person("Bill Gates",62);

     }

@Bean("linus")

public Person person2(){

        return new Person("Linus",48);

    }

}

結果:

現在如果將ObstinateCondition matches 方法返回值改成 true ,兩個 bean 就被注入進容器:

結論得:

第一個條件類實現的方法返回true ,第二個返回 false ,則結果 false ,不注入進容器。

第一個條件類實現的方法返回true ,第二個返回 true ,則結果 true ,注入進容器中。

 


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69946279/viewspace-2658475/,如需轉載,請註明出處,否則將追究法律責任。

相關文章