成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Quarkus依賴注入之一:創建Bean

開發 前端
作為《Quarkus依賴注入》的開篇,本文先介紹CDI,再學習如何創建Bean實例。

關于依賴注入

  • 對一名java程序員來說,依賴注入應該是個熟悉的概念,簡單的說就是:我要用XXX,但我不負責XXX的生產
  • 以下代碼來自spring官方,serve方法要使用MyComponent類的doWork方法,但是不負責MyComponent對象的實例化,只要用注解Autowired修飾成員變量myComponent,spring環境會負責為myComponent賦值一個實例
@Service
public class MyService {
    
    @Autowired
    MyComponent myComponent;
    
    public String serve() {
        myComponent.doWork();
        return "success";
    }
}
  • 關于依賴注入,網上有很多優秀文章,這里就不展開了,咱們要關注的是quarkus框架的依賴注入

關于《quarkus依賴注入》系列

  • 《quarkus依賴注入》共十三篇文章,整體規劃上隸屬于《quarkus實戰》系列,但專注于依賴注入的知識點和實戰
  • 如果您熟悉spring的依賴注入,那么閱讀本系列時會發現quarkus與spring之間有太多相似之處,很多地方一看就懂

本篇概覽

  • 作為《quarkus依賴注入》的開篇,本文先介紹CDI,再學習如何創建bean實例,全文內容如下:

  • 學習quarkus的依賴注入之前,來自官方的提醒非常重要。

官方提醒

  • 在使用依賴注入的時候,quankus官方建議不要使用私有變量(用默認可見性,即相同package內可見),因為GraalVM將應用制作成二進制可執行文件時,編譯器名為Substrate VM,操作私有變量需要用到反射,而GraalVM使用反射的限制,導致靜態編譯的文件體積增大。
Quarkus is designed with Substrate VM in mind. For this reason, we encourage you to use *package-private* scope instead of *private*.

關于CDI

  • 《 Contexts and Dependency Injection for Java 2.0》,簡稱CDI,該規范是對JSR-346的更新,quarkus對依賴注入的支持就是基于此規范實現的
  • 從 2.0 版開始,CDI 面向 Java SE 和 Jakarta EE 平臺,Java SE 中的 CDI 和 Jakarta EE 容器中的 CDI 共享core CDI 中定義的特性。
  • 簡單看下CDI規范的內容(請原諒欣宸的英語水平):
  1. 該規范定義了一組強大的補充服務,有助于改進應用程序代碼的結構。
  2. 給有狀態對象定義了生命周期,這些對象會綁定到上下文,上下文是可擴展的。
  3. 復雜的、安全的依賴注入機制,還有開發和部署階段選擇依賴的能力。
  4. 與Expression Language (EL)集成。
  5. 裝飾注入對象的能力(個人想到了AOP,你拿到的對象其實是個代理)。
  6. 攔截器與對象關聯的能力。
  7. 事件通知模型。
  8. web會話上下文。
  9. 一個SPI:允許便攜式擴展容器的集成(integrate cleanly )。

關于CDI的bean

  • CDI的實現(如quarkus),允許對象做這些事情:
  1. 綁定到生命周期上下文。
  2. 注入。
  3. 與攔截器和裝飾器關聯。
  4. 通過觸發和觀察事件,以松散耦合的方式交互。
  • 述場景的對象統稱為bean,上下文中的 bean 實例稱為上下文實例,上下文實例可以通過依賴注入服務注入到其他對象中。
  • 關于CDI的背景知識就介紹到這里吧,接下來要寫代碼了。

源碼下載

  • 本篇實戰的完整源碼可在GitHub下載到,地址和鏈接信息如下表所示(https://github.com/zq2599/blog_demos)。

  • 這個git項目中有多個文件夾,本次實戰的源碼在quarkus-tutorials文件夾下,如下圖紅框。

  • quarkus-tutorials是個父工程,里面有多個module,本篇實戰的module是basic-di,如下圖紅框。

創建demo工程

  • 創建個最簡單的web工程,默認生成一個web服務類HobbyResource.java,代碼如下,后面的演示代碼都寫在這個工程中。
package com.bolingcavalry;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import java.time.LocalDateTime;

@Path("/actions")
public class HobbyResource {

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String hello() {

        return "Hello RESTEasy, " + LocalDateTime.now();
    }
}
  • 接下來,從最基礎的創建bean實例創建開始。

創建bean實例:注解修飾在類上

  • 先來看看spring是如何創建bean實例的,回顧文章剛開始的那段代碼,myComponent對象來自哪里?
  • 繼續看spring官方的demo,如下所示,用Component注解修飾在類上,spring就會實例化MyComponent對象并注冊在bean容器中,需要用此bean的時候用Autowired注解就可以注入了。
@Component
public class MyComponent {
    public void doWork() {}
}
  • quarkus框架下也有類似方式,演示類ClassAnnotationBean.java如下,用注解ApplicationScoped去修飾ClassAnnotationBean.類,如此quarkus就會實例化此類并放入容器中
package com.bolingcavalry.service.impl;

import javax.enterprise.context.ApplicationScoped;

@ApplicationScoped
public class ClassAnnotationBean {

    public String hello() {
        return "from " + this.getClass().getSimpleName();
    }
}
  • 這種注解修飾在類上的bean,被quarkus官方成為class-based beans。
  • 使用bean也很簡單,如下,用注解Inject修飾ClassAnnotationBean類型的成員變量即可。
package com.bolingcavalry;

import com.bolingcavalry.service.impl.ClassAnnotationBean;

import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import java.time.LocalDateTime;

@Path("/classannotataionbean")
public class ClassAnnotationController {

    @Inject
    ClassAnnotationBean classAnnotationBean;

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String hello() {
        return String.format("Hello RESTEasy, %s, %s",
                LocalDateTime.now(),
                classAnnotationBean.hello());
    }
}
  • 如何驗證上述代碼是否有效?運行服務,再用瀏覽器訪問classannotataionbean接口,肉眼判斷返回內容是否符合要求,這樣雖然可行,但總覺得會被嘲諷低效…
  • 還是寫一段單元測試代碼吧,如下所示,注意要用QuarkusTest注解修飾測試類(不然服務啟動有問題),測試方法中檢查了返回碼和body,如果前面的依賴注入沒問題,則下面的測試應該能通過才對。
package com.bolingcavalry;

import com.bolingcavalry.service.impl.ClassAnnotationBean;
import io.quarkus.test.junit.QuarkusTest;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.containsString;

@QuarkusTest
class ClassAnnotationControllerTest {

    @Test
    public void testGetEndpoint() {
        given()
                .when().get("/classannotataionbean")
                .then()
                .statusCode(200)
                // 檢查body內容,是否含有ClassAnnotationBean.hello方法返回的字符串
                .body(containsString("from " + ClassAnnotationBean.class.getSimpleName()));
    }
}
  • 執行命令mvn clean test -U開始測試,控制臺輸出如下,提示測試通過。
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO] 
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  5.702 s
[INFO] Finished at: 2022-03-12T15:48:45+08:00
[INFO] ------------------------------------------------------------------------
  • 如果您的開發工具是IDEA,也可以用它的圖形化工具執行測試,如下圖,能得到更豐富的測試信息。

  • 掌握了最基礎的實例化方式,接著看下一種方式:修飾在方法上。

創建bean實例:注解修飾在方法上

  • 下一種創建bean的方式,我們還是先看spring是怎么做的,有了它作對比,對quarkus的做法就好理解了。
  • 來看spring官方文檔上的一段代碼,如下所示,用Bean注解修飾myBean方法,spring框架就會執行此方法,將返回值作為bean注冊到容器中,spring把這種bean的處理過程稱為lite mode。
@Component
 public class Calculator {
     public int sum(int a, int b) {
         return a+b;
     }

     @Bean
     public MyBean myBean() {
         return new MyBean();
     }
 }
  • kuarkus框架下,也能用注解修飾方法來創建bean,為了演示,先定義個普通接口。
package com.bolingcavalry.service;

public interface HelloService {
    String hello();
}
  • kuarkus框架下,也能用注解修飾方法來創建bean,為了演示,先定義個普通接口。
package com.bolingcavalry.service;

public interface HelloService {
    String hello();
}
  • 以及HelloService接口的實現類。
package com.bolingcavalry.service.impl;

import com.bolingcavalry.service.HelloService;

public class HelloServiceImpl implements HelloService {
    @Override
    public String hello() {
        return "from " + this.getClass().getSimpleName();
    }
}
  • 注意,HelloService.java和HelloServiceImpl.java都是普通的java接口和類,與quarkus沒有任何關系。
  • 下面的代碼演示了用注解修飾方法,使得quarkus調用此方法,將返回值作為bean實例注冊到容器中,Produces通知quarkus做實例化,ApplicationScoped表明了bean的作用域是整個應用。
package com.bolingcavalry.service.impl;

import com.bolingcavalry.service.HelloService;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Produces;

public class MethodAnnonationBean {

    @Produces
    @ApplicationScoped
    public HelloService getHelloService() {
        return new HelloServiceImpl();
    }
}
  • 這種用于創建bean的方法,被quarkus稱為producer method。
  • 看過上述代碼,相信聰明的您應該明白了用這種方式創建bean的優點:在創建HelloService接口的實例時,可以控制所有細節(構造方法的參數、或者從多個HelloService實現類中選擇一個),沒錯,在SpringBoot的Configuration類中咱們也是這樣做的。
  • 前面的getHelloService方法的返回值,可以直接在業務代碼中依賴注入,如下所示。
package com.bolingcavalry;

import com.bolingcavalry.service.HelloService;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import java.time.LocalDateTime;

@Path("/methodannotataionbean")
public class MethodAnnotationController {

    @Inject
    HelloService helloService;

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String get() {
        return String.format("Hello RESTEasy, %s, %s",
                LocalDateTime.now(),
                helloService.hello());
    }
}
  • 單元測試代碼如下
package com.bolingcavalry;

import com.bolingcavalry.service.impl.HelloServiceImpl;
import io.quarkus.test.junit.QuarkusTest;
import org.junit.jupiter.api.Test;

import static io.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.containsString;

@QuarkusTest
class MethodAnnotationControllerTest {

    @Test
    public void testGetEndpoint() {
        given()
                .when().get("/methodannotataionbean")
                .then()
                .statusCode(200)
                // 檢查body內容,HelloServiceImpl.hello方法返回的字符串
                .body(containsString("from " + HelloServiceImpl.class.getSimpleName()));
    }
}
  • 測試通過

  • producer method有個特性需要重點關注:如果剛才生產bean的getHelloService方法有個入參,如下所示,入參是OtherService對象,那么,這個OtherService對象也必須是個bean實例(這就像你用@Inject注入一個bean的時候,這個bean必須存在一樣),如果OtherService不是個bean,那么應用初始化的時候會報錯,(其實這個特性SpringBoot中也有,相信經驗豐富的您在使用Configuration類的時候應該用到過)。
public class MethodAnnonationBean {

    @Produces
    @ApplicationScoped
    public HelloService getHelloService(OtherService otherService) {
        return new HelloServiceImpl();
    }
}
  • quarkus還做了個簡化:如果有了ApplicationScoped這樣的作用域注解,那么Produces可以省略掉,寫成下面這樣也是正常運行的。
public class MethodAnnonationBean {

    @ApplicationScoped
    public HelloService getHelloService() {
        return new HelloServiceImpl();
    }
}

創建bean實例:注解修飾在成員變量上

  • 再來看看最后一種方式,注解在成員變量上,這個成員變量就成了bean。
  • 先寫個普通類用于稍后測試。
package com.bolingcavalry.service.impl;

import com.bolingcavalry.service.HelloService;

public class OtherServiceImpl {

    public String hello() {
        return "from " + this.getClass().getSimpleName();
    }
}
  • 通過成員變量創建bean的方式如下所示,給otherServiceImpl增加兩個注解,Produces通知quarkus做實例化,ApplicationScoped表明了bean的作用域是整個應用,最終OtherServiceImpl實例會被創建后注冊到bean容器中。
package com.bolingcavalry.service.impl;

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Produces;

public class FieldAnnonationBean {

    @Produces
    @ApplicationScoped
    OtherServiceImpl otherServiceImpl = new OtherServiceImpl();
}
  • 這種用于創建bean的成員變量(如上面的otherServiceImpl),被quarkus稱為producer field。
  • 上述bean的使用方法如下,可見與前面的使用并無區別,都是從quarkus的依賴注入。
@Path("/fieldannotataionbean")
public class FieldAnnotationController {

    @Inject
    OtherServiceImpl otherServiceImpl;

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String get() {
        return String.format("Hello RESTEasy, %s, %s",
                LocalDateTime.now(),
                otherServiceImpl.hello());
    }
}
  • 測試代碼與前面類似就不贅述了,請您自行完成編寫和測試。

關于synthetic bean

  • 還有一種bean,quarkus官方稱之為synthetic bean(合成bean),這種bean只會在擴展組件中用到,而咱們日常的應用開發不會涉及,synthetic bean的特點是其屬性值并不來自它的類、方法、成員變量的處理,而是由擴展組件指定的,在注冊syntheitc bean到quarkus容器時,常用SyntheticBeanBuildItem類去做相關操作,來看一段實例化synthetic bean的代碼。
@BuildStep
@Record(STATIC_INIT)
SyntheticBeanBuildItem syntheticBean(TestRecorder recorder) {
   return SyntheticBeanBuildItem.configure(Foo.class).scope(Singleton.class)
                .runtimeValue(recorder.createFoo("parameters are recorder in the bytecode")) 
                .done();
}
  • 至此,《quarkus依賴注入》的開篇已經完成,創建bean之后還有更精彩的內容為您奉上,敬請期待。
責任編輯:姜華 來源: 今日頭條
相關推薦

2023-07-11 09:14:12

Beanquarkus

2023-06-29 08:32:41

Bean作用域

2023-10-07 08:35:07

依賴注入Spring

2021-06-03 07:55:12

技術

2011-05-31 10:00:21

Android Spring 依賴注入

2016-12-28 09:30:37

Andriod安卓平臺依賴注入

2023-01-30 22:10:12

BeanSpring容器

2017-08-16 16:00:05

PHPcontainer依賴注入

2022-12-29 08:54:53

依賴注入JavaScript

2015-10-09 10:32:21

代碼依賴注入強心劑

2022-04-30 08:50:11

控制反轉Spring依賴注入

2019-09-18 18:12:57

前端javascriptvue.js

2015-09-02 11:22:36

JavaScript實現思路

2023-03-27 21:54:48

方式OptionalAutowird

2021-05-06 07:58:57

Spring BeanIOCAOP

2021-01-22 06:35:44

IoCxml驅動技術

2009-08-24 08:49:51

JavaEE 6依賴注JSR

2024-12-30 12:00:00

.NET Core依賴注入屬性注入

2024-04-01 00:02:56

Go語言代碼

2025-01-13 00:13:59

VSCode架構依賴注入
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 精品欧美一区免费观看α√ | 99热国产精品 | 求毛片| 日韩影音 | 欧美一级片在线播放 | 国产黄色小视频在线观看 | 高清18麻豆 | 成人亚洲网站 | 伊人免费在线观看 | 夜久久| 少妇一区二区三区 | 黄色亚洲 | 91影视 | 久久99精品久久久久久国产越南 | 中文字幕在线观看 | 国产精品毛片一区二区在线看 | 亚洲第一区久久 | 日日日日操 | 国产午夜精品久久久 | 岛国二区| 国产精品高清在线 | 交专区videossex农村 | 亚洲欧美综合精品久久成人 | 性一交一乱一伦视频免费观看 | 3p视频在线观看 | 久久夜色精品国产 | 亚洲最大福利网 | 超碰97免费在线 | 国产福利在线播放 | 久久精品 | 一区二区三区不卡视频 | 日本免费在线观看视频 | 欧洲精品码一区二区三区免费看 | 国产成人高清视频 | 免费一级片| 国产激情精品一区二区三区 | 欧美一级二级在线观看 | 色婷婷狠狠 | 久在线 | 日韩综合一区 | 欧美国产视频 |