Spring的常用註解

来源:https://www.cnblogs.com/gdjlc/archive/2019/09/27/11600975.html
-Advertisement-
Play Games

Spring框架主要包括IoC和AOP,這兩大功能都可以使用註解進行配置。 一、bean定義 二、依賴註入 三、使用Primary註解 四、Scope註解 五、方法註入 六、AOP註解 七、ComponentScan註解 ...


Spring框架主要包括IoC和AOP,這兩大功能都可以使用註解進行配置。

開發環境:IntelliJ IDEA 2019.2.2
Spring Boot版本:2.1.8
新建一個名稱為demo的Spring Boot項目。

一、bean定義

在 Spring 中,構成應用程式主幹並由Spring IoC容器管理的對象稱為bean。
bean是一個由Spring IoC容器實例化、組裝和管理的對象。
使用@Component、@Service或@Configuration註解來修飾一個類,這些類會被Spring自動檢測並註冊到容器中,在類裡面使用@Bean註解修
飾的方法,會被視為一個bean存放到Spring容器中。

下麵例子實現了怎樣根據類型獲取bean的名稱,獲取bean;

1、新建類 MyBean.java

package com.example.demo;

public class MyBean {

    public MyBean(String id){
       this.id = id;
    }

    private String id;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }
}

2、新建類 MyConfig.java

package com.example.demo;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MyConfig {

    //預設bean的名稱為方法名,即下麵的getMyBean
    @Bean
    public MyBean getMyBean(){
        return new MyBean("1");
    }

    //設置bean的名稱為bean
    @Bean("bean2")
    public MyBean getMyBean2(){
        return new MyBean("2");
    }
}

3、修改啟動類代碼 DemoApplication.java

package com.example.demo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
@RestController
public class DemoApplication  {

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

    @Autowired
    ApplicationContext ctx;

    @RequestMapping(value = "/")
    public String index(){
        //根據類型獲取bean的名稱
        String[] names = ctx.getBeanNamesForType(MyBean.class);
        for(String name : names){
            System.out.println(name);
        }

        //獲取bean
        MyBean bean1 = (MyBean)ctx.getBean("getMyBean");
        System.out.println(bean1.getId());

        MyBean bean2 = (MyBean)ctx.getBean("bean2");
        System.out.println(bean2.getId());

        return "";
    }
}

運行項目後,瀏覽器訪問:http://localhost:8080/,IDEA控制台輸出:
getMyBean
bean2
1
2

項目結構

 

 二、依賴註入

使用註解可以實現實例的註入,最常用的是@Resource及@Autowired。
@Resource是JSR-250定義的註解,預設會根據名稱進行註入。
@Autowired預設會根據類型進行註入。

1、繼續使用上面例子的兩個類 MyBean.java、MyConfig.java

2、修改啟動類代碼 DemoApplication.java

package com.example.demo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

@SpringBootApplication
@RestController
public class DemoApplication  {

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

    //使用@Resource註入
    @Resource(name="getMyBean")
    MyBean myBean1;

    //使用@Autowired註入
    @Autowired
    MyBean bean2;

    @RequestMapping(value = "/")
    public String index(){
        System.out.println(myBean1.getId());
        System.out.println(bean2.getId());
        return "";
    }
}

瀏覽器訪問:http://localhost:8080/,IDEA控制台輸出:
getMyBean
bean2
1
2

備註:
上面MyBean bean2的bean2不能修改為別的名稱。原因:
@Autowired根據類型進行註入,如果容器中只有一個MyBean類型的bean,則bean2可以隨便命名。
但本例子容器中有兩個MyBean類型的bean,碰到這種有多個bean的情況,則根據屬性名來查找,這裡屬性名bean2最終會找到相應的bean。
如果把MyBean bean2改成MyBean myBean2,則運行時IEAD控制台會報異常信息:

Field myBean2 in com.example.demo.DemoApplication required a single bean, but 2 were found:
	- getMyBean: defined by method 'getMyBean' in class path resource [com/example/demo/MyConfig.class]
	- bean2: defined by method 'getMyBean2' in class path resource [com/example/demo/MyConfig.class]

以上例子的註入方式為設值註入,還可以使用構造註入,向控制器的構造器中註入bean。
修飾構造器只能使用@Autowired註解,@Resource不能修改構造器。
例子:

package com.example.demo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

@SpringBootApplication
@RestController
public class DemoApplication  {

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

    MyBean bean2;

    //構造註入
    @Autowired
    public DemoApplication(MyBean bean2){
        this.bean2 = bean2;
    }

    @RequestMapping(value = "/")
    public String index(){
        System.out.println(bean2.getId());
        return "";
    }
}

三、使用Primary註解

根據類型來註入,如果容器中存在多個相同類型的bean時,會拋異常,因為此時Spring不知道將哪個bean註入。
針對這個問題,可以使用@Primary註解。

1、修改MyConfig.java代碼,為第一個bean增加註解@Primary

package com.example.demo;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

@Configuration
public class MyConfig {

    //預設bean的名稱為方法名,即下麵的getMyBean
    @Bean
    @Primary
    public MyBean getMyBean(){
        return new MyBean("1");
    }

    //設置bean的名稱為bean
    @Bean("bean2")
    public MyBean getMyBean2(){
        return new MyBean("2");
    }
}

2、啟動類代碼 DemoApplication.java還是用上面例子

package com.example.demo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

@SpringBootApplication
@RestController
public class DemoApplication  {

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

    //使用@Resource註入
    @Resource(name="getMyBean")
    MyBean myBean1;

    //使用@Autowired註入
    @Autowired
    MyBean bean2;

    @RequestMapping(value = "/")
    public String index(){
        System.out.println(myBean1.getId());
        System.out.println(bean2.getId());
        return "";
    }
}

瀏覽器訪問:http://localhost:8080/,IDEA控制台輸出:
1
1

四、Scope註解

配置bean時可以指定bean的作用域(scope),一般的bean可以配置為單態(singleton)或者非單態(prototype)。
配置為singleton,Spring的bean工廠只返回同一個bean的實例。
配置為prototype,則每次會創建一個新的實例。

1、修改代碼 MyConfig.java

package com.example.demo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

@SpringBootApplication
@RestController
public class DemoApplication  {

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

    @Autowired
    ApplicationContext ctx;

    @RequestMapping(value = "/")
    public String index(){
        String s = "prototype:" + ctx.getBean("bean1") + "<br /> "
                  + "singleton:" + ctx.getBean("bean2") + "<br /> ";
        return s;
    }
}

瀏覽器訪問:http://localhost:8080/,多次刷新,頁面內容都變化:
prototype:com.example.demo.MyBean@6fce7ec4
singleton:com.example.demo.MyBean@7626c5f9
prototype:com.example.demo.MyBean@357b01f6
......

註意:
如果在一個單態的bean裡面註入一個非單態的bean,則這個單態的bean所維護的非單態bean實例,將不會被刷新。
例子Spring MVC的控制器是單態的,如果往控制器裡面註入一個非單態的bean,如下所示:

    //註入一個非單態的bean
    @Autowired
    private MyBean bean1;

    @RequestMapping(value = "/")
    public String index(){        
        return bean1.toString();
    }

瀏覽器訪問:http://localhost:8080/,多次刷新,頁面都是顯示如下:
com.example.demo.MyBean@5d0c61c9
說明index()方法輸出的MyBean都是調用同一個實例,因為控制器在初始化時,就已經被註入了一個bean,而且一直維護著同一個實例。

五、方法註入

如果在一個單態的bean裡面註入一個非單態的bean,則這個單態的bean所維護的非單態bean實例,將不會被刷新。
有兩種簡單的解決方法:
1、在需要註入的一方(單態的bean),直接使用ApplicationContext,每次調用非單態的bean,都由容器返回。

package com.example.demo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class DemoController {

    @Autowired
    private ApplicationContext ctx;

    private MyBean getBean1(){
        return (MyBean)ctx.getBean("bean1");//一個非單態的bean
    }

    @RequestMapping(value = "/")
    public String index(){
        return getBean1().toString();
    }
}

瀏覽器訪問:http://localhost:8080/,多次刷新,頁面每次都變化:
com.example.demo.MyBean@12a7cacc
com.example.demo.MyBean@1776b0ea
......


2、使用Spring的方法註入。
使用@Lookup註解來修飾一個抽象方法,該方法會返回bean的實例。
下麵代碼運行結果和上面使用ApplicationContext一樣。

package com.example.demo;

import org.springframework.beans.factory.annotation.Lookup;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public abstract class DemoController {
    @Lookup("bean1")
    public abstract MyBean createBean() ;

    @RequestMapping(value = "/")
    public String index(){
        return createBean().toString();
    }
}

六、AOP註解

實現AOP功能使用AspectJ註解
1、需要在pom.xml加入依賴:

        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
        </dependency>

2、新建一個業務類 TestServiceImpl.java

package com.example.demo;

import org.springframework.stereotype.Component;

@Component
public class TestServiceImpl {
    public void testService(){
        System.out.println("要代理的業務方法");
    }
}

3、新建一個代理類 ProxyService.java

package com.example.demo;

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class ProxyService {
    @Before("execution(* com.example.demo.*ServiceImpl.*(..))")
    public void before(){
        System.out.println("業務方法調用前執行");
    }
    @After("execution(* com.example.demo.*ServiceImpl.*(..))")
    public void after(){
        System.out.println("業務方法調用後執行");
    }
}

4、修改啟動類方法 DemoApplication.java

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;

@SpringBootApplication
public abstract class DemoApplication  {
    public static void main(String[] args) {
        //SpringApplication.run(DemoApplication.class, args);
        new SpringApplicationBuilder(DemoApplication.class).properties(
                "spring.aop.proxy-target-class=true"
        ).run(args);
    }
}

5、控制器 DemoController.java

package com.example.demo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class DemoController {

    @Autowired
    TestServiceImpl testService;

    @RequestMapping(value = "/")
    public String index(){
        testService.testService();
        System.out.println("TestServiceImpl的class:" + testService.getClass());
        return "";
    }
}

瀏覽器訪問:http://localhost:8080/,控制臺中輸出:
業務方法調用前執行
要代理的業務方法
業務方法調用後執行
TestServiceImpl的class:class com.example.demo.TestServiceImpl$$EnhancerBySpringCGLIB$$2a53cdeb

七、ComponentScan註解

ComponentScan註解主要用於檢測使用@Component修飾的組件,包括間接使用@Component的組件(如@Service、@Repository、@Controller
),並把它們註冊到Spring容器中。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一 鎖 行級鎖 select_for_update(nowait=False, skip_locked=False) 註意必須用在事務裡面,至於如何開啟事務,我們看下麵的事務一節。 返回一個鎖住行直到事務結束的查詢集,如果資料庫支持,它將生成一個 SELECT ... FOR UPDATE 語句。 ...
  • 別看Spring現在玩的這麼花,其實它的“籌碼”就兩個,“容器”和“bean定義”。只有先把bean定義註冊到容器里,後續的一切可能才有可能成為可能。所以在進階的路上如果要想走的順暢些,徹底搞清楚bean定義註冊的所有細節至關重要。畢竟這是萬里長征的第一步。有句話怎麼說來著,“勿在浮沙築高臺”。Sp ...
  • 增加Security配置類 前面演示了一個簡單的登錄入門例子,使用springboot security預設的配置實現,雖然非常簡單,但是基本實現了登錄功能。不過在生產環境下,顯然不能僅僅使用如此簡單的登錄功能,我們還需要更多個性化的登錄配置,所以我們要使用配置類來代替預設配置。新建一個配置類 We ...
  • 前言:C++是博大精深的語言,特性複雜得跟北京二環一樣,繼承亂得跟亂倫似的。 不過它仍然是我最熟悉且必須用在游戲開發上的語言,這篇文章用於挑選出一些個人覺得重要的條款/經驗/技巧進行記錄總結。 文章最後列出一些我看過的C++書籍/博客等,方便參考。 其實以前也寫過相同的筆記博文,現在用markdow ...
  • Web應用安全管理 Web應用的安全管理,主要包括兩個方面的內容,一個是用戶身份的認證,即用戶登錄的設計,二是用戶授權,即一個用戶在一個應用系統中能夠執行哪些操作的許可權管理。許可權管理的設計一般使用角色來管理,即給一個用戶賦予哪些角色,這個用戶就具有哪些許可權。 Spring框架體系中,經典的安全體系框 ...
  • 一、協程 1.歷史進程: (1)3.4引入協程,用yield來實現 (2)3.5引入協程語法 (3)實現協程比較好的包有asyncio,tornado,gevent 2.定義:協程是為非搶占式多任務產生子程式的電腦程式組件,協程允許不同入口點在不同位置暫停或開始執行程式 3.從技術角度講,協程就是 ...
  • python面向函數式編程,模擬用戶登錄驗證、註冊的代碼實現。 主要有以下兩個文件: 1、user.txt文檔文件,相當於資料庫的用戶信息表,主要是記錄用戶名和密碼。 註意:1)此文檔需要與.py文件放在同一個路徑下。 2)用戶名、密碼在存儲時,是以$符號區別開。 2、模擬用戶登錄驗證、註冊的代碼實 ...
  • @[TOC]     下麵向大家介紹一下我在學習python課程的一些題目的解法,如果大家有什麼更好的解法請私信我。這裡只顯示題目與代碼。 1.快樂的數字     描述: 編寫一個演算法來確定一個數字是否“快樂”。 快樂的數字按照如下方式確定 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...