Skip to content

A More Concise Coding Style #13718

@Aresxue

Description

@Aresxue

Background

Between 2020 and 2021, I frequently utilized HSF, which recommended consolidating multiple providers/consumers into a single configuration class. This approach utilized the native Spring programming style in business logic (with consumers Autowired and providers annotated with @service), effectively decoupling Spring from HSF. Upon transitioning to Dubbo 2.7.x, I noticed the absence of this mechanism. Consequently, I independently implemented related functionality within our company's internal framework. Now, with Dubbo 3.x, I observe the integration of Dubbo and HSF, where Dubbo has finally implemented the ability to configure providers and consumers in a configuration class. However, I find the current approach still lacking in conciseness. Hence, I'd like to explore the possibility of achieving even greater conciseness.

Describe the proposal

1.Consumers using field mode in configuration class:

@RpcConsumerCollector
public class RpcConsumerConfig {

  @RpcConsumer(group = "demo", version = "${dubbo.provider.version:1.0.0}")
  private UserRpcService userRpcService;

}

This method is equivalent to the current approach of using the ReferenceBean in Dubbo 3.x, but the field approach is comparatively more concise.
2.Providers using field mode in configuration class:

@RpcProviderCollector
public class RpcProviderConfig {

  // interfaceClass can be omitted
  @RpcProvider(group = "demo", version = "1.0.0", interfaceClass = UserRpcService.class)
  private UserRpcService userService;

}

This approach is equivalent to the current method of using DubboService in Dubbo 3.x, but the field approach is relatively more concise. It avoids code like new UserRpcServiceImpl. It's worth noting that for providers, there might be cases where the same interface has multiple implementations (for different versions of RPC services). In such cases, the field type can be directly set to UserRpcServiceImpl, and interfaceClass can be specified as UserRpcService.class (interfaceClass can be omitted when the implementation class implements only one interface).
3.Collectors:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@Component
public @interface RpcProviderCollector {

  String version() default "";

  String group() default "";

}

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Component
public @interface RpcConsumerCollector {

  String version() default "";

  String group() default "";

}

As mentioned earlier, while it's advantageous to manage consumers and providers centrally, there are times when you don't want to put all providers/consumers together. In such cases, collectors can be used. For example, you can place the consumers of application A in ARpcConsumerConfig and the consumers of application B in BRpcConsumerConfig. Then, you can directly add @RpcConsumerCollector to the class, specifying group and version. The fields inside will inherit the group and version from @RpcConsumerCollector by default, ideally achieving a very concise program.

@RpcConsumerCollector(group = "demo", version = "${dubbo.consumer.version:1.0.0}")
public class RpcConsumerConfig {
  
  private UserRpcService userRpcService;
  
  private UserRpcService1 userRpcService1;
  
  private UserRpcService2 userRpcService2;

}

Goals

  • Introducing new methods to simplify code implementation, not limited to the use of fields

Non-Goals

  • Replace the original method usage

Replenish

This program has been running in our company for more than 2 years with no obvious side effects.

Metadata

Metadata

Assignees

No one assigned

    Labels

    type/proposalEverything you want Dubbo have

    Type

    No type

    Projects

    Status

    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions