自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Quarkus依賴注入之一:創(chuàng)建Bean

開(kāi)發(fā) 前端
作為《Quarkus依賴注入》的開(kāi)篇,本文先介紹CDI,再學(xué)習(xí)如何創(chuàng)建Bean實(shí)例。

關(guān)于依賴注入

  • 對(duì)一名java程序員來(lái)說(shuō),依賴注入應(yīng)該是個(gè)熟悉的概念,簡(jiǎn)單的說(shuō)就是:我要用XXX,但我不負(fù)責(zé)XXX的生產(chǎn)
  • 以下代碼來(lái)自spring官方,serve方法要使用MyComponent類的doWork方法,但是不負(fù)責(zé)MyComponent對(duì)象的實(shí)例化,只要用注解Autowired修飾成員變量myComponent,spring環(huán)境會(huì)負(fù)責(zé)為myComponent賦值一個(gè)實(shí)例
@Service
public class MyService {
    
    @Autowired
    MyComponent myComponent;
    
    public String serve() {
        myComponent.doWork();
        return "success";
    }
}
  • 關(guān)于依賴注入,網(wǎng)上有很多優(yōu)秀文章,這里就不展開(kāi)了,咱們要關(guān)注的是quarkus框架的依賴注入

關(guān)于《quarkus依賴注入》系列

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

本篇概覽

  • 作為《quarkus依賴注入》的開(kāi)篇,本文先介紹CDI,再學(xué)習(xí)如何創(chuàng)建bean實(shí)例,全文內(nèi)容如下:

  • 學(xué)習(xí)quarkus的依賴注入之前,來(lái)自官方的提醒非常重要。

官方提醒

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

關(guān)于CDI

  • 《 Contexts and Dependency Injection for Java 2.0》,簡(jiǎn)稱CDI,該規(guī)范是對(duì)JSR-346的更新,quarkus對(duì)依賴注入的支持就是基于此規(guī)范實(shí)現(xiàn)的
  • 從 2.0 版開(kāi)始,CDI 面向 Java SE 和 Jakarta EE 平臺(tái),Java SE 中的 CDI 和 Jakarta EE 容器中的 CDI 共享core CDI 中定義的特性。
  • 簡(jiǎn)單看下CDI規(guī)范的內(nèi)容(請(qǐng)?jiān)徯厘返挠⒄Z(yǔ)水平):
  1. 該規(guī)范定義了一組強(qiáng)大的補(bǔ)充服務(wù),有助于改進(jìn)應(yīng)用程序代碼的結(jié)構(gòu)。
  2. 給有狀態(tài)對(duì)象定義了生命周期,這些對(duì)象會(huì)綁定到上下文,上下文是可擴(kuò)展的。
  3. 復(fù)雜的、安全的依賴注入機(jī)制,還有開(kāi)發(fā)和部署階段選擇依賴的能力。
  4. 與Expression Language (EL)集成。
  5. 裝飾注入對(duì)象的能力(個(gè)人想到了AOP,你拿到的對(duì)象其實(shí)是個(gè)代理)。
  6. 攔截器與對(duì)象關(guān)聯(lián)的能力。
  7. 事件通知模型。
  8. web會(huì)話上下文。
  9. 一個(gè)SPI:允許便攜式擴(kuò)展容器的集成(integrate cleanly )。

關(guān)于CDI的bean

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

源碼下載

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

  • 這個(gè)git項(xiàng)目中有多個(gè)文件夾,本次實(shí)戰(zhàn)的源碼在quarkus-tutorials文件夾下,如下圖紅框。

  • quarkus-tutorials是個(gè)父工程,里面有多個(gè)module,本篇實(shí)戰(zhàn)的module是basic-di,如下圖紅框。

創(chuàng)建demo工程

  • 創(chuàng)建個(gè)最簡(jiǎn)單的web工程,默認(rèn)生成一個(gè)web服務(wù)類HobbyResource.java,代碼如下,后面的演示代碼都寫在這個(gè)工程中。
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();
    }
}
  • 接下來(lái),從最基礎(chǔ)的創(chuàng)建bean實(shí)例創(chuàng)建開(kāi)始。

創(chuàng)建bean實(shí)例:注解修飾在類上

  • 先來(lái)看看spring是如何創(chuàng)建bean實(shí)例的,回顧文章剛開(kāi)始的那段代碼,myComponent對(duì)象來(lái)自哪里?
  • 繼續(xù)看spring官方的demo,如下所示,用Component注解修飾在類上,spring就會(huì)實(shí)例化MyComponent對(duì)象并注冊(cè)在bean容器中,需要用此bean的時(shí)候用Autowired注解就可以注入了。
@Component
public class MyComponent {
    public void doWork() {}
}
  • quarkus框架下也有類似方式,演示類ClassAnnotationBean.java如下,用注解ApplicationScoped去修飾ClassAnnotationBean.類,如此quarkus就會(huì)實(shí)例化此類并放入容器中
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也很簡(jiǎn)單,如下,用注解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());
    }
}
  • 如何驗(yàn)證上述代碼是否有效?運(yùn)行服務(wù),再用瀏覽器訪問(wèn)classannotataionbean接口,肉眼判斷返回內(nèi)容是否符合要求,這樣雖然可行,但總覺(jué)得會(huì)被嘲諷低效…
  • 還是寫一段單元測(cè)試代碼吧,如下所示,注意要用QuarkusTest注解修飾測(cè)試類(不然服務(wù)啟動(dòng)有問(wèn)題),測(cè)試方法中檢查了返回碼和body,如果前面的依賴注入沒(méi)問(wèn)題,則下面的測(cè)試應(yīng)該能通過(guò)才對(duì)。
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內(nèi)容,是否含有ClassAnnotationBean.hello方法返回的字符串
                .body(containsString("from " + ClassAnnotationBean.class.getSimpleName()));
    }
}
  • 執(zhí)行命令mvn clean test -U開(kāi)始測(cè)試,控制臺(tái)輸出如下,提示測(cè)試通過(guò)。
[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] ------------------------------------------------------------------------
  • 如果您的開(kāi)發(fā)工具是IDEA,也可以用它的圖形化工具執(zhí)行測(cè)試,如下圖,能得到更豐富的測(cè)試信息。

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

創(chuàng)建bean實(shí)例:注解修飾在方法上

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

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

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

public interface HelloService {
    String hello();
}
  • 以及HelloService接口的實(shí)現(xiàn)類。
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沒(méi)有任何關(guān)系。
  • 下面的代碼演示了用注解修飾方法,使得quarkus調(diào)用此方法,將返回值作為bean實(shí)例注冊(cè)到容器中,Produces通知quarkus做實(shí)例化,ApplicationScoped表明了bean的作用域是整個(gè)應(yīng)用。
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();
    }
}
  • 這種用于創(chuàng)建bean的方法,被quarkus稱為producer method。
  • 看過(guò)上述代碼,相信聰明的您應(yīng)該明白了用這種方式創(chuàng)建bean的優(yōu)點(diǎn):在創(chuàng)建HelloService接口的實(shí)例時(shí),可以控制所有細(xì)節(jié)(構(gòu)造方法的參數(shù)、或者從多個(gè)HelloService實(shí)現(xiàn)類中選擇一個(gè)),沒(méi)錯(cuò),在SpringBoot的Configuration類中咱們也是這樣做的。
  • 前面的getHelloService方法的返回值,可以直接在業(yè)務(wù)代碼中依賴注入,如下所示。
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());
    }
}
  • 單元測(cè)試代碼如下
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內(nèi)容,HelloServiceImpl.hello方法返回的字符串
                .body(containsString("from " + HelloServiceImpl.class.getSimpleName()));
    }
}
  • 測(cè)試通過(guò)

  • producer method有個(gè)特性需要重點(diǎn)關(guān)注:如果剛才生產(chǎn)bean的getHelloService方法有個(gè)入?yún)?,如下所示,入?yún)⑹荗therService對(duì)象,那么,這個(gè)OtherService對(duì)象也必須是個(gè)bean實(shí)例(這就像你用@Inject注入一個(gè)bean的時(shí)候,這個(gè)bean必須存在一樣),如果OtherService不是個(gè)bean,那么應(yīng)用初始化的時(shí)候會(huì)報(bào)錯(cuò),(其實(shí)這個(gè)特性SpringBoot中也有,相信經(jīng)驗(yàn)豐富的您在使用Configuration類的時(shí)候應(yīng)該用到過(guò))。
public class MethodAnnonationBean {

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

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

創(chuàng)建bean實(shí)例:注解修飾在成員變量上

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

import com.bolingcavalry.service.HelloService;

public class OtherServiceImpl {

    public String hello() {
        return "from " + this.getClass().getSimpleName();
    }
}
  • 通過(guò)成員變量創(chuàng)建bean的方式如下所示,給otherServiceImpl增加兩個(gè)注解,Produces通知quarkus做實(shí)例化,ApplicationScoped表明了bean的作用域是整個(gè)應(yīng)用,最終OtherServiceImpl實(shí)例會(huì)被創(chuàng)建后注冊(cè)到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();
}
  • 這種用于創(chuàng)建bean的成員變量(如上面的otherServiceImpl),被quarkus稱為producer field。
  • 上述bean的使用方法如下,可見(jiàn)與前面的使用并無(wú)區(qū)別,都是從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());
    }
}
  • 測(cè)試代碼與前面類似就不贅述了,請(qǐng)您自行完成編寫和測(cè)試。

關(guān)于synthetic bean

  • 還有一種bean,quarkus官方稱之為synthetic bean(合成bean),這種bean只會(huì)在擴(kuò)展組件中用到,而咱們?nèi)粘5膽?yīng)用開(kāi)發(fā)不會(huì)涉及,synthetic bean的特點(diǎn)是其屬性值并不來(lái)自它的類、方法、成員變量的處理,而是由擴(kuò)展組件指定的,在注冊(cè)syntheitc bean到quarkus容器時(shí),常用SyntheticBeanBuildItem類去做相關(guān)操作,來(lái)看一段實(shí)例化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依賴注入》的開(kāi)篇已經(jīng)完成,創(chuàng)建bean之后還有更精彩的內(nèi)容為您奉上,敬請(qǐng)期待。
責(zé)任編輯:姜華 來(lái)源: 今日頭條
相關(guān)推薦

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

技術(shù)

2016-12-28 09:30:37

Andriod安卓平臺(tái)依賴注入

2011-05-31 10:00:21

Android Spring 依賴注入

2023-01-30 22:10:12

BeanSpring容器

2022-12-29 08:54:53

依賴注入JavaScript

2017-08-16 16:00:05

PHPcontainer依賴注入

2015-10-09 10:32:21

代碼依賴注入強(qiáng)心劑

2019-09-18 18:12:57

前端javascriptvue.js

2022-04-30 08:50:11

控制反轉(zhuǎn)Spring依賴注入

2023-03-27 21:54:48

方式OptionalAutowird

2015-09-02 11:22:36

JavaScript實(shí)現(xiàn)思路

2021-05-06 07:58:57

Spring BeanIOCAOP

2009-08-24 08:49:51

JavaEE 6依賴注JSR

2021-01-22 06:35:44

IoCxml驅(qū)動(dòng)技術(shù)

2024-12-30 12:00:00

.NET Core依賴注入屬性注入

2024-04-01 00:02:56

Go語(yǔ)言代碼

2024-05-27 00:13:27

Go語(yǔ)言框架
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)