国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Dubbo 新編程模型之注解驅動

chavesgu / 2420人閱讀

摘要:在生態系統中,以和為代表的微服務框架,引入了全新的編程模型,包括注解驅動外部化配置以及自動裝配等。新的編程模型無需配置簡化部署提升開發效率。同時,新的編程模型也是即將發布的的基礎設施。

原文地址 整體愿景

隨著微服務架構的廣泛地推廣和實施。在 Java 生態系統中,以 Spring Boot 和 Spring Cloud 為代表的微服務框架,引入了全新的編程模型,包括注解驅動(Annotation-Driven)、外部化配置(External Configuration)以及自動裝配(Auto-Configure)等。新的編程模型無需 XML 配置、簡化部署、提升開發效率。

為了更好地實踐微服務架構,Dubbo 從 2.5.7 版本開始, 針對 Spring 應用場景(包括 Spring Boot 和 Spring Cloud),新引入注解驅動(Annotation-Driven)、外部化配置(External Configuration)等編程模型。同時,新的編程模型也是即將發布的 Spring Boot Starter(dubbo-spring-boot-starter) 的基礎設施。更為重要的是,從 Dubbo 2.5.8 開始,無論傳統 Spring 應用,還是 Spring Boot 應用,兩者之間可以實現無縫遷移(無需任何調整)。

注解驅動(Annotation-Driven) @DubboComponentScan 起始版本: 2.5.7 歷史遺留問題
1. 注解支持不充分

在 Dubbo 2.5.7之前的版本 ,Dubbo 提供了兩個核心注解 @Service 以及 @Reference,分別用于Dubbo 服務提供和 Dubbo 服務引用。

其中,@Service 作為 XML 元素 的替代注解,與 Spring Framework @org.springframework.stereotype.Service 類似,用于服務提供方 Dubbo 服務暴露。與之相對應的@Reference,則是替代 元素,類似于 Spring 中的 @Autowired

2.5.7 之前的Dubbo,與早期的 Spring Framework 2.5 存在類似的不足,即注解支持不夠充分。注解需要和 XML 配置文件配合使用,如下所示:




    
    
    

2. @Service Bean 不支持 Spring AOP

同時,使用 方式掃描后的Dubbo @Service ,在 Spring 代理方面存在問題,如 GitHub 上的 issue https://github.com/alibaba/du...:

關于dubbo @Service注解生成ServiceBean時, interface獲取成spring 的代理對象的bug

在項目里, 我使用了

@Service
@Transactional
@com.alibaba.dubbo.config.annotation.Service
public class SUserJpushServiceImp

的形式, 來暴露服務。但是在發布服務的時候, interface class 是通過
``
serviceConfig.setInterface(bean.getClass().getInterfaces()[0]);
``
的形式獲取, 剛好, 我的service都使用了@Transactional注解, 對象被代理了。所以獲取到的interface是Spring的代理接口...

不少熱心的小伙伴不僅發現這個歷史遺留問題,而且提出了一些修復方案。同時,為了更好地適配 Spring 生命周期以及將 Dubbo 完全向注解驅動編程模型過渡,因此,引入了全新 Dubbo 組件掃描注解 - @DubboComponentScan

注:    Spring AOP 問題將在 2.5.9 中修復:https://github.com/alibaba/du...
3. @Reference 不支持字段繼承性

假設有一個 Spring Bean AnnotationAction 直接通過字段annotationService 標記 @Reference 引用 AnnotationService

package com.alibaba.dubbo.examples.annotation.action;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.dubbo.examples.annotation.api.AnnotationService;
import org.springframework.stereotype.Component;


@Component("annotationAction")
public class AnnotationAction {

    @Reference
    private AnnotationService annotationService;

    public String doSayHello(String name) {
        return annotationService.sayHello(name);
    }

}

AnnotationAction 被 XML 元素 掃描后:

字段 annotationService 能夠引用到 AnnotationService,執行 doSayHello 方法能夠正常返回。

如果將字段annotationService 抽取到AnnotationAction 的父類BaseAction 后,AnnotationService 無法再被引用,改造如下所示:

AnnotationAction.java

@Component("annotationAction")
public class AnnotationAction extends BaseAction {

    public String doSayHello(String name) {
        return getAnnotationService().sayHello(name);
    }

}

BaseAction.java

public abstract class BaseAction {

    @Reference
    private AnnotationService annotationService;

    protected AnnotationService getAnnotationService() {
        return annotationService;
    }
}

改造后,再次執行 doSayHello 方法,NullPointerException 將會被拋出。說明 并不支持@Reference 字段繼承性。

了解了歷史問題,集合整體愿景,下面介紹@DubboComponentScan 的設計原則。

設計原則

Spring Framework 3.1 引入了新 Annotation - @ComponentScan , 完全替代了 XML 元素 。同樣, @DubboComponentScan 作為 Dubbo 2.5.7 新增的 Annotation,也是XML 元素 的替代方案。

在命名上(類名以及屬性方法),為了簡化使用和關聯記憶,Dubbo 組件掃描 Annotation @DubboComponentScan,借鑒了 Spring Boot 1.3 引入的 @ServletComponentScan。定義如下:

public @interface DubboComponentScan {

    /**
     * Alias for the {@link #basePackages()} attribute. Allows for more concise annotation
     * declarations e.g.: {@code @DubboComponentScan("org.my.pkg")} instead of
     * {@code @DubboComponentScan(basePackages="org.my.pkg")}.
     *
     * @return the base packages to scan
     */
    String[] value() default {};

    /**
     * Base packages to scan for annotated @Service classes. {@link #value()} is an
     * alias for (and mutually exclusive with) this attribute.
     * 

* Use {@link #basePackageClasses()} for a type-safe alternative to String-based * package names. * * @return the base packages to scan */ String[] basePackages() default {}; /** * Type-safe alternative to {@link #basePackages()} for specifying the packages to * scan for annotated @Service classes. The package of each class specified will be * scanned. * * @return classes from the base packages to scan */ Class[] basePackageClasses() default {}; }

注意:basePackages()value() 均能支持占位符(placeholder)指定的包名

在職責上,@DubboComponentScan 相對于 Spring Boot @ServletComponentScan 更為繁重,原因在于處理 Dubbo @Service 類暴露 Dubbo 服務外,還有幫助 Spring Bean @Reference字段或者方法注入 Dubbo 服務代理。

在場景上,Spring Framework @ComponentScan 組件掃描邏輯更為復雜。而在 @DubboComponentScan 只需關注 @Service@Reference 處理。

在功能上, @DubboComponentScan 不但需要提供完整 Spring AOP 支持的能力,而且還得具備@Reference 字段可繼承性的能力。

了解基本設計原則后,下面通過完整的示例,簡介@DubboComponentScan 使用方法以及注意事項。

使用方法

后續通過服務提供方(@Serivce)以及服務消費方(@Reference)兩部分來介紹@DubboComponentScan 使用方法。

假設,服務提供方和服務消費分均依賴服務接口DemoService:

package com.alibaba.dubbo.demo;

public interface DemoService {

    String sayHello(String name);

}
服務提供方(@Serivce
實現 DemoService

服務提供方實現DemoService - AnnotationDemoService ,同時標注 Dubbo @Service

package com.alibaba.dubbo.demo.provider;

import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.dubbo.demo.DemoService;

/**
 * Annotation {@link DemoService} 實現
 *
 * @author Mercy
 */
@Service
public class AnnotationDemoService implements DemoService {

    @Override
    public String sayHello(String name) {
        return "Hello , " + name;
    }

}
服務提供方 Annotation 配置

AnnotationDemoService 暴露成Dubbo 服務,需要依賴 Spring Bean:AplicationConfigProtocolConfig 以及 RegistryConfig 。這三個 Spring Bean 過去可通過 XML 文件方式組裝 Spring Bean:



    
    

    
    

    

以上裝配方式不予推薦,推薦使用 Annotation 配置,因此可以換成 Spring @Configuration Bean 的形式:

package com.alibaba.dubbo.demo.config;

import com.alibaba.dubbo.config.ApplicationConfig;
import com.alibaba.dubbo.config.ProtocolConfig;
import com.alibaba.dubbo.config.RegistryConfig;
import com.alibaba.dubbo.config.spring.context.annotation.DubboComponentScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 服務提供方配置
 *
 * @author Mercy
 */
@Configuration
@DubboComponentScan("com.alibaba.dubbo.demo.provider") // 掃描 Dubbo 組件
public class ProviderConfiguration {

    /**
     * 當前應用配置
     */
    @Bean("dubbo-annotation-provider")
    public ApplicationConfig applicationConfig() {
        ApplicationConfig applicationConfig = new ApplicationConfig();
        applicationConfig.setName("dubbo-annotation-provider");
        return applicationConfig;
    }

    /**
     * 當前連接注冊中心配置
     */
    @Bean("my-registry")
    public RegistryConfig registryConfig() {
        RegistryConfig registryConfig = new RegistryConfig();
        registryConfig.setAddress("N/A");
        return registryConfig;
    }

    /**
     * 當前連接注冊中心配置
     */
    @Bean("dubbo")
    public ProtocolConfig protocolConfig() {
        ProtocolConfig protocolConfig = new ProtocolConfig();
        protocolConfig.setName("dubbo");
        protocolConfig.setPort(12345);
        return protocolConfig;
    }
}
服務提供方引導類
package com.alibaba.dubbo.demo.bootstrap;

import com.alibaba.dubbo.demo.DemoService;
import com.alibaba.dubbo.demo.config.ProviderConfiguration;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * 服務提供方引導類
 *
 * @author Mercy
 */
public class ProviderBootstrap {

    public static void main(String[] args) {
        // 創建 Annotation 配置上下文
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        // 注冊配置 Bean
        context.register(ProviderConfiguration.class);
        // 啟動上下文
        context.refresh();
        // 獲取 DemoService Bean
        DemoService demoService = context.getBean(DemoService.class);
        // 執行 sayHello 方法
        String message = demoService.sayHello("World");
        // 控制臺輸出信息
        System.out.println(message);
    }
    
}

ProviderBootstrap 啟動并執行后,控制輸出與預期一致:

Hello , World

以上直接結果說明 @DubboComponentScan("com.alibaba.dubbo.demo.provider") 掃描后,標注 Dubbo @ServiceAnnotationDemoService 被注冊成 Spring Bean,可從 Spring ApplicationContext 自由獲取。

服務消費方(@Reference
服務 DemoService
package com.alibaba.dubbo.demo.consumer;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.dubbo.demo.DemoService;

/**
 * Annotation 驅動 {@link DemoService} 消費方
 *
 * @author Mercy
 */
public class AnnotationDemoServiceConsumer {

    @Reference(url = "dubbo://127.0.0.1:12345")
    private DemoService demoService;

    public String doSayHell(String name) {
        return demoService.sayHello(name);
    }
}
服務消費方 Annotation 配置

與服務提供方配置類似,服務消費方也許 Dubbo 相關配置 Bean - ConsumerConfiguration

package com.alibaba.dubbo.demo.config;

import com.alibaba.dubbo.config.ApplicationConfig;
import com.alibaba.dubbo.config.RegistryConfig;
import com.alibaba.dubbo.config.spring.context.annotation.DubboComponentScan;
import com.alibaba.dubbo.demo.consumer.AnnotationDemoServiceConsumer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 服務消費方配置
 *
 * @author Mercy
 */
@Configuration
@DubboComponentScan
public class ConsumerConfiguration {

    /**
     * 當前應用配置
     */
    @Bean
    public ApplicationConfig applicationConfig() {
        ApplicationConfig applicationConfig = new ApplicationConfig();
        applicationConfig.setName("dubbo-annotation-consumer");
        return applicationConfig;
    }

    /**
     * 當前連接注冊中心配置
     */
    @Bean
    public RegistryConfig registryConfig() {
        RegistryConfig registryConfig = new RegistryConfig();
        registryConfig.setAddress("N/A");
        return registryConfig;
    }

    /**
     * 注冊 AnnotationDemoServiceConsumer,@DubboComponentScan 將處理其中 @Reference 字段。
     * 如果 AnnotationDemoServiceConsumer 非 Spring Bean 的話,
     * 即使 @DubboComponentScan 指定 package 也不會進行處理,與 Spring @Autowired 同理
     */
    @Bean
    public AnnotationDemoServiceConsumer annotationDemoServiceConsumer() {
        return new AnnotationDemoServiceConsumer();
    }

}
服務消費方引導類

服務消費方需要先引導服務提供方,下面的實例將會啟動兩個 Spring 應用上下文,首先引導服務提供方 Spring 應用上下文,同時,需要復用前面Annotation 配置 ProviderConfiguration

    /**
     * 啟動服務提供方上下文
     */
    private static void startProviderContext() {
        // 創建 Annotation 配置上下文
        AnnotationConfigApplicationContext providerContext = new AnnotationConfigApplicationContext();
        // 注冊配置 Bean
        providerContext.register(ProviderConfiguration.class);
        // 啟動服務提供方上下文
        providerContext.refresh();
    }

然后引導服務消費方Spring 應用上下文:

    /**
     * 啟動并且返回服務消費方上下文
     *
     * @return AnnotationConfigApplicationContext
     */
    private static ApplicationContext startConsumerContext() {
        // 創建服務消費方 Annotation 配置上下文
        AnnotationConfigApplicationContext consumerContext = new AnnotationConfigApplicationContext();
        // 注冊服務消費方配置 Bean
        consumerContext.register(ConsumerConfiguration.class);
        // 啟動服務消費方上下文
        consumerContext.refresh();
        // 返回服務消費方 Annotation 配置上下文
        return consumerContext;
    }

完整的引導類實現:

package com.alibaba.dubbo.demo.bootstrap;

import com.alibaba.dubbo.demo.config.ConsumerConfiguration;
import com.alibaba.dubbo.demo.config.ProviderConfiguration;
import com.alibaba.dubbo.demo.consumer.AnnotationDemoServiceConsumer;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * 服務消費端引導類
 *
 * @author Mercy
 */
public class ConsumerBootstrap {

    public static void main(String[] args) {
        // 啟動服務提供方上下文
        startProviderContext();
        // 啟動并且返回服務消費方上下文
        ApplicationContext consumerContext = startConsumerContext();
        // 獲取 AnnotationDemoServiceConsumer Bean
        AnnotationDemoServiceConsumer consumer = consumerContext.getBean(AnnotationDemoServiceConsumer.class);
        // 執行 doSayHello 方法
        String message = consumer.doSayHello("World");
        // 輸出執行結果
        System.out.println(message);
    }

    /**
     * 啟動并且返回服務消費方上下文
     *
     * @return AnnotationConfigApplicationContext
     */
    private static ApplicationContext startConsumerContext() {
        // 創建服務消費方 Annotation 配置上下文
        AnnotationConfigApplicationContext consumerContext = new AnnotationConfigApplicationContext();
        // 注冊服務消費方配置 Bean
        consumerContext.register(ConsumerConfiguration.class);
        // 啟動服務消費方上下文
        consumerContext.refresh();
        // 返回服務消費方 Annotation 配置上下文
        return consumerContext;
    }

    /**
     * 啟動服務提供方上下文
     */
    private static void startProviderContext() {
        // 創建 Annotation 配置上下文
        AnnotationConfigApplicationContext providerContext = new AnnotationConfigApplicationContext();
        // 注冊配置 Bean
        providerContext.register(ProviderConfiguration.class);
        // 啟動服務提供方上下文
        providerContext.refresh();
    }

}

運行ConsumerBootstrap結果,仍然符合期望,AnnotationDemoServiceConsumer 輸出:

Hello , World
Spring AOP 支持

前面提到 注冊 Dubbo @Service 組件后,在 Spring AOP 支持方面存在問題。事務作為 Spring AOP 的功能擴展,自然也會在 中不支持。

@DubboComponentScan 針對以上問題,實現了對 Spring AOP 是完全兼容。將上述服務提供方 Annotation 配置做出一定的調整,標注@EnableTransactionManagement 以及自定義實現PlatformTransactionManager :

@Configuration
@DubboComponentScan("com.alibaba.dubbo.demo.provider") // 掃描 Dubbo 組件
@EnableTransactionManagement // 激活事務管理
public class ProviderConfiguration {
  // 省略其他配置 Bean 定義
  
    /**
     * 自定義事務管理器
     */
    @Bean
    @Primary
    public PlatformTransactionManager transactionManager() {
        return new PlatformTransactionManager() {

            @Override
            public TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {
                System.out.println("get transaction ...");
                return new SimpleTransactionStatus();
            }

            @Override
            public void commit(TransactionStatus status) throws TransactionException {
                System.out.println("commit transaction ...");
            }

            @Override
            public void rollback(TransactionStatus status) throws TransactionException {
                System.out.println("rollback transaction ...");
            }
        };
    }
}

同時調整 AnnotationDemoService - 增加@Transactional 注解:

@Service
@Transactional
public class AnnotationDemoService implements DemoService {
    // 省略實現,保持不變
}

再次運行ConsumerBootstrap , 觀察控制臺輸出內容:

get transaction ...
commit transaction ...
Hello , World

輸入內容中多處了兩行,說明自定義 PlatformTransactionManager getTransaction(TransactionDefinition) 以及 commit(TransactionStatus) 方法被執行,進而說明 AnnotationDemoServicesayHello(String) 方法執行時,事務也伴隨執行。

注意事項

ConsumerConfiguration 上的 @DubboComponentScan 并沒有指定 basePackages 掃描,這種情況會將ConsumerConfiguration 當做 basePackageClasses ,即掃描ConsumerConfiguration 所屬的 package com.alibaba.dubbo.demo.config 以及子 package。由于當前示例中,不存在標注 Dubbo @Service的類,因此在運行時日志(如果開啟的話)會輸出警告信息:

WARN :  [DUBBO] No Spring Bean annotating Dubbo"s @Service was found in Spring BeanFactory, dubbo version: 2.0.0, current host: 127.0.0.1

以上信息大可不必擔憂,因為 @DubboComponentScan 除了掃描 Dubbo @Service 組件以外,還將處理 @Reference字段注入。然而讀者特別關注@Reference字段注入的規則。

以上實現為例,AnnotationDemoServiceConsumer 必須申明為 Spring @Bean 或者 @Component(或者其派生注解),否則 @DubboComponentScan 不會主動將標注 @Reference字段所在的聲明類提成為 Spring Bean,換句話說,如果 @Reference字段所在的聲明類不是 Spring Bean 的話, @DubboComponentScan 不會處理@Reference注入,其原理與 Spring @Autowired 一致。

以上使用不當可能會導致相關問題,如 GitHub 上曾有小伙伴提問:https://github.com/alibaba/du...

li362692680 提問:

@DubboComponentScan注解在消費端掃描包時掃描的是 @Service注解??不是@Reference注解??
啟動時報
DubboComponentScanRegistrar-85]-[main]-[INFO] 0 annotated @Service Components { [] }

筆者(mercyblitz)回復:

@Reference 類似于 @Autowired 一樣,首先其申明的類必須被 Spring 上下文當做一個Bean,因此,Dubbo 并沒有直接將 @Reference  字段所在的類提升成 Bean。

綜上所述,這并不是一個問題,而是用法不當!

已知問題

最新發布的 Dubbo 2.5.8 中,@DubboComponentScan 在以下特殊場景下存在 Spring @Service 不兼容情況:

假設有兩個服務實現類 AB,同時存放在com.acme 包下:

A 標注 Dubbo @Service

B 標注 Dubbo @Service 和 Spring @Service

當 Spring @ComponentScan 先掃描com.acme 包時,B 被當做 Spring Bean 的候選類。隨后,@DubboComponentScan 也掃描相同的包。當應用啟動時,AB 雖然都是 Spring Bean,可僅 A 能夠暴露 Dubbo 服務,B 則丟失。

問題版本:2.5.72.5.8

問題詳情:https://github.com/alibaba/du...

修復版本:2.5.9(下個版本)

關于作者

小馬哥,十余年Java EE 從業經驗,架構師、微服務布道師、Dubbo 維護者。目前主要負責阿里巴巴集團微服務技術實施、架構衍進、基礎設施構建等。重點關注云計算、微服務以及軟件架構等領域。通過SUN Java(SCJP、SCWCD、SCBCD)以及Oracle OCA 等的認證。

github:https://github.com/mercyblitz

sf.gg : https://segmentfault.com/u/me...

微信/微博:mercyblitz

下篇預告 《Dubbo 新編程模型之外部化配置(External Configuration)》

更多 Dubbo 以及 微服務相關內容,請關注小馬哥公眾號:

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/68075.html

相關文章

  • Dubbo 新編模型外部化配置

    摘要:同時,所標注的需要被應用上下文注冊配置引導類創建配置上下文注冊當前配置獲取和獲取獲取運行結果運行后控制臺輸出輸出的內容與綁定的內容一致,符合期望。 Dubbo 外部化配置(Externalized Configuration) 原文地址 外部化配置(Externalized Configuration) 在Dubbo 注解驅動例子中,無論是服務提供方,還是服務消費方,均需要轉配相關配置...

    baihe 評論0 收藏0
  • 官方 Dubbo Spring Boot Starter 1.0.0 公測版

    摘要:公告今天小馬哥非常高興地向各位小伙伴宣布,官方公測版已開發完畢,即將發布至公有倉庫,目前正在內部測試中。為了收集更多的用戶反饋,小馬哥誠邀大家一同參與使用測試以及共同維護,項目工程地址如果您喜愛并想了解工程的動態,不妨點擊按鈕加以關注。 公告 今天小馬哥非常高興地向各位小伙伴宣布,官方 Dubbo Spring Boot Starter 1.0.0 公測版已開發完畢,即將發布至 Mav...

    MrZONT 評論0 收藏0
  • Dubbo Cloud Native 實踐與思考

    摘要:可簡單地認為它是的擴展,負載均衡自然成為不可或缺的特性。類似的特性在項目也有體現,它是另一種高性能代理的方案,提供服務發現健康和負載均衡。 Dubbo Cloud Native 實踐與思考 分享簡介 Cloud Native 應用架構隨著云技術的發展受到業界特別重視和關注,尤其是 CNCF(Cloud Native Computing Foundation)項目蓬勃發展之際。Dubbo...

    邱勇 評論0 收藏0
  • IMI 基于 Swoole 開發的協 PHP 開發框架 常駐內存、協異步非阻塞

    摘要:介紹是基于開發的協程開發框架,擁有常駐內存協程異步非阻塞等優點。宇潤我在年開發并發布了第一個框架,一直維護使用至今,非常穩定,并且有文檔。于是我走上了開發的不歸路 showImg(https://segmentfault.com/img/bVbcxQH?w=340&h=160); 介紹 IMI 是基于 Swoole 開發的協程 PHP 開發框架,擁有常駐內存、協程異步非阻塞IO等優點。...

    airborne007 評論0 收藏0
  • Dubbo Spring Cloud 重塑微服務治理

    摘要:在服務治理方面,相較于而言,并不成熟。遺憾的是,往往被部分開發者片面地視作服務治理的框架,而非微服務基礎設施。因此,建議開發人員將或者遷移為服務。因此,下一步需要將其配置服務遠程。當服務提供方啟動后,下一步實現一個服務消費方。 原文鏈接:Dubbo Spring Cloud 重塑微服務治理,來自于微信公眾號:次靈均閣 摘要 在 Java 微服務生態中,Spring Cloud1 成為...

    wh469012917 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<