Wang Youzhi , um pescador de ouro mútuo que compartilha a tecnologia Java hard-core,
junta-se ao grupo de pessoas de Java que correm com baldes: pessoas de Java que são ricas juntas
No artigo anterior , apresentamos as funcionalidades fornecidas pelo DUbbo em termos de governança de serviços.Hoje vamos dar uma olhada nas funcionalidades fornecidas pelo Dubbo em outros aspectos. Assim como o artigo de governança de serviços, o objetivo deste artigo é aprender a usar os recursos fornecidos pelo Dubbo no gerenciamento e controle de serviços, e ainda não envolve nenhum princípio de implementação.
estrutura de engenharia
hmm~~
Este é o caso, porque o computador é muito extenso e o IDEA está realmente consumindo memória, então juntei os projetos de teste de acordo com os subprojetos. A estrutura do projeto que estou usando atualmente é a seguinte:
O nome do submódulo consiste em duas partes: método de configuração + função, como: XMLProvider, que significa um provedor de serviços baseado no método de configuração XML.
Dicas : IDEA está prestes a alcançar o CLion "leão da memória".
Esboço local (Esboço)
Ao usar o Dubbo, o consumidor do serviço integra apenas a interface e todas as implementações estão no provedor de serviços. No entanto, em alguns cenários, esperamos que o consumidor do serviço possa concluir algum processamento lógico para reduzir o consumo de desempenho causado pela interação RPC, por exemplo : Coloque a verificação de parâmetro no usuário do serviço para reduzir uma interação de rede com o chamador do serviço.
Nesse cenário, podemos usar o recurso de stub local fornecido pelo Dubbo. Contamos com a seguinte estrutura de engenharia da prestadora de serviço:
A interface XMLProviderService que fornece serviços externos é definida no módulo xml-provider-api. O código é o seguinte:
public interface XMLProviderService {
String say(String message);
}
E o stub da interface XMLProviderServiceStub, o código é o seguinte:
public class XMLProviderServiceStub implements XMLProviderService {
private final XMLProviderService xmlProviderService;
public XMLProviderServiceStub(XMLProviderService xmlProviderService) {
this.xmlProviderService = xmlProviderService;
}
@Override
public String say(String message) {
if (StringUtils.isBlank(message)) {
return "message不能为空!";
}
try {
return this.xmlProviderService.say(message);
} catch (Exception e) {
return "远程调用失败:" + e.getMessage();
}
}
}
Em seguida, configuramos o stub da interface no projeto do consumidor do serviço:
<dubbo:reference id="xmlProviderService" interface="com.wyz.api.XMLProviderService" stub="com.wyz.api.stub.XMLProviderServiceStub"/>
Dicas : Para usar um stub local, a classe de implementação do stub deve ter um construtor que passe na instância do Proxy (a instância do Proxy gerada pelo consumidor do serviço).
Camuflagem local (Mock)
A camuflagem local é a degradação do serviço que mencionamos em " Recursos avançados do Dubbo: governança de serviço ", e faremos uma pequena adição hoje. O mascaramento local é um subconjunto de stubs locais. Os stubs locais podem lidar com vários erros e exceções no link de chamada RPC, enquanto o mascaramento local se concentra no tratamento de RpcException (como falha de rede, tempo limite de resposta, etc.) que requer processamento tolerante a falhas. anormal .
Adicionamos um serviço de máscara local XMLProviderServiceMock para XMLProviderService, a estrutura do projeto é a seguinte:
O código do XMLProviderServiceMock é o seguinte:
public class XMLProviderServiceMock implements XMLProviderService {
@Override
public String say(String message) {
return "服务出错了!";
}
}
O arquivo de configuração pode ser configurado da seguinte forma:
<dubbo:reference id="xmlProviderService" interface="com.wyz.api.XMLProviderService" mock="true"/>
Nesta configuração, a implementação de Mock deve ser nomeada de acordo com o método "nome da interface + sufixo Mock"; caso você não queira usar este método de nomenclatura, pode usar o nome totalmente qualificado:
<dubbo:reference id="xmlProviderService" interface="com.wyz.api.XMLProviderService" mock="com.wyz.api.mock.XMLProviderServiceMock"/>
Dicas : O motivo de "repetir" o Mock novamente é que houve um erro no artigo anterior. Escrevi <dubbo:reference>
a configuração que deveria ter sido feita na etiqueta <dubbo:service>
, mas o motivo do erro ainda não está funcionando. Ei, eu realmente cumpriu a frase "o que vem no papel é sempre raso, mas nunca sei que essa matéria tem que ser praticada".
retorno de chamada de parâmetro
O Dubbo oferece suporte à função de retorno de chamada do parâmetro, para que o provedor de serviços possa "reverter" a chamada do consumidor do serviço. Essa função é implementada com base no proxy reverso gerado pelo link longo e o efeito é semelhante a uma chamada assíncrona. Vamos dar um exemplo de pagamento:
Adicione a interface PaymentService ao módulo xml-provider-api do projeto XMLProvider e adicione o PaymentNotifyService para notificar o resultado do PaymentService:
public interface PaymentService {
void payment(String cardNo, PaymentNotifyService paymentNotifyService);
}
public interface PaymentNotifyService {
void paymentNotify(String message);
}
A interface PaymentService é implementada no módulo xml-provider-service do projeto XMLProvider:
public class PaymentServiceImpl implements PaymentService {
@Override
public void payment(String cardNo, PaymentNotifyService paymentNotifyService) {
System.out.println("向卡号[" + cardNo + "]付钱!");
// 业务逻辑
paymentNotifyService.paymentNotify("付款成功");
}
}
Execute PaymentService#payment
o método e chame PaymentNotifyService#paymentNotify
o método para notificar o chamador do serviço sobre o resultado da execução.
Implemente a interface PaymentNotifyService no projeto XMLConsumer:
public class PaymentNotifyServiceImpl implements PaymentNotifyService {
@Override
public void paymentNotify(String message) {
System.out.println("支付结果:" + message);
}
}
Dê uma olhada na estrutura do projeto neste momento:
A seguir vem a configuração do XML. No callback do parâmetro, precisamos atentar para a configuração do módulo xml-provider-service do projeto XMLProvider do provedor de serviço:
<bean id="paymentServiceImpl" class="com.wyz.service.impl.PaymentServiceImpl"/>
<dubbo:service interface="com.wyz.api.PaymentService" ref="paymentServiceImpl" callbacks="10">
<dubbo:method name="payment">
<dubbo:argument index="1" callback="true"/>
</dubbo:method>
</dubbo:service>
<dubbo:argument index="1" callback="true"/>
A configuração é determinada pela linha 4. PaymentService#payment
O segundo parâmetro no método (índice começa em 0) é um parâmetro de retorno de chamada, callbacks limita o número de retornos de chamada no mesmo link longo, não o número total de retornos de chamada.
Dicas : No cenário real de negócios de pagamento, é mais inclinado ao processamento assíncrono. Por exemplo, quando o provedor de serviços recebe o pagamento, ele inicia um novo encadeamento para processar o negócio de pagamento e chama a interface de notificação, e o encadeamento principal retorna isso a solicitação de pagamento foi recebida com sucesso.
chamada assíncrona
As chamadas assíncronas permitem que o provedor de serviços retorne uma resposta imediatamente, enquanto o segundo plano continua realizando o processamento da solicitação.Quando o consumidor do serviço solicita um resultado de resposta, o provedor de serviços retorna o resultado.
DUBbo suporta dois métodos de chamada assíncrona:
- Use a interface CompletableFuture
- Usar RpcContext
Depois do DUbbo 2.7, o DUbbo usa a interface CompletableFuture como base para programação assíncrona.
Usando CompletableFuture para implementar chamadas assíncronas
Vamos primeiro ver como usar CompletableFuture para implementar chamadas assíncronas e declarar a interface CompletableFutureAsyncService:
public interface CompletableFutureAsyncService {
CompletableFuture<String> async(String message);
}
Em seguida, vem a implementação da interface:
public class CompletableFutureAsyncServiceImpl implements CompletableFutureAsyncService {
@Override
public CompletableFuture<String> async(String message) {
return CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + " say : " + message);
try {
TimeUnit.SECONDS.sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return "异步调用成功!";
});
}
}
A configuração XML é a mesma que a configuração comum da interface Dubbo RPC, a configuração do módulo xml-provider-service:
<bean id="completableFutureAsyncServiceImpl" class="com.wyz.service.impl.CompletableFutureAsyncServiceImpl" />
<dubbo:service interface="com.wyz.api.CompletableFutureAsyncService" ref="completableFutureAsyncServiceImpl" />
Configuração do módulo XMLConsumer:
<dubbo:reference id="completableFutureAsyncService" interface="com.wyz.api.CompletableFutureAsyncService"/>
Também é muito simples de usar:
CompletableFuture<String> completableFuture = completableFutureAsyncService.async("Hello");
System.out.println(completableFuture.get());
Dicas :
- Não há diferença entre usar o CompletableFuture no Dubbo e usar o CompletableFuture sozinho~~
- A finalidade de imprimir o nome da interface na implementação de CompletableFutureAsyncServiceImpl é mostrar claramente o efeito de chamadas assíncronas;
CompletableFuture#supplyAsync(Supplier<U> supplier)
Por padrão, useForkJoinPool#commonPool()
;- Os métodos sobrecarregados
CompletableFuture#supplyAsync(Supplier<U> supplier, Executor executor)
permitem o uso de conjuntos de encadeamentos personalizados.
Use AsyncContext para implementar chamadas assíncronas
Além de usar o CompletableFuture, você também pode implementar chamadas assíncronas por meio do AsyncContext definido pelo Dubbo. Vamos escrever a interface e a implementação da interface primeiro:
public interface RpcContextAsyncService {
String async(String message);
}
public class RpcContextAsyncServiceImpl implements RpcContextAsyncService {
@Override
public String async(String message) {
final AsyncContext asyncContext = RpcContext.startAsync();
new Thread(() -> {
asyncContext.signalContextSwitch();
asyncContext.write(Thread.currentThread().getName() + " say : " + message);
}).start();
// 异步调用中,这个返回值完全没有意义
return null;
}
}
A configuração do provedor de serviços é a mesma das outras interfaces do Dubbo:
<bean id="rpcContextAsyncServiceImpl" class="com.wyz.service.impl.RpcContextAsyncServiceImpl"/>
<dubbo:service interface="com.wyz.api.RpcContextAsyncService" ref="rpcContextAsyncServiceImpl"/>
A seguir é feita a configuração do consumidor do serviço, que precisa adicionar o parâmetro async:
<dubbo:reference id="rpcContextAsyncService" interface="com.wyz.api.RpcContextAsyncService" async="true"/>
Por fim, chame a interface RPC no consumidor do serviço:
rpcContextAsyncService.async("Thanks");
Future<String> future = RpcContext.getServiceContext().getFuture();
System.out.println(future.get());
chamada de generalização
A chamada generalizada do Dubbo fornece um método de implementação para invocar serviços sem depender da API do provedor de serviços (SDK). O cenário principal está na implementação da plataforma de gateway, normalmente a implementação do gateway não deve depender da API (SDK) de outros serviços.
O Dubbo fornece oficialmente 3 métodos de chamada de generalização:
- Usando chamadas genéricas por meio da API
- Usando chamadas genéricas via Spring (formulário XML)
- Chamada de generalização de objeto Protobuf
Aqui apresentamos a forma de configurar chamadas genéricas na forma de XML.
Preparação
Primeiro, preparamos um projeto GenericProvider para provisionamento de serviços. A estrutura do projeto é a seguinte:
A interface é definida no projeto, ou seja, as classes de implementação GenericProviderService e GenericProviderServiceImpl, o código é o seguinte:
public interface GenericProviderService {
String say(String message);
}
public class GenericProviderServiceImpl implements GenericProviderService {
@Override
public String say(String message) {
return "GenericProvider say:" + message;
}
}
No generic-dubbo-provider.xml, apenas os serviços fornecidos pelo GenericProvider precisam ser configurados normalmente:
<bean id="genericProviderServiceImpl" class="com.wyz.service.impl.GenericProviderServiceImpl"/>
<dubbo:service interface="com.wyz.service.api.GenericProviderService" ref="genericProviderServiceImpl" generic="true"/>
Não entraremos em detalhes sobre a configuração do arquivo application.yml.
Configuração do consumidor de serviço
De volta ao projeto XMLConsumer, configure primeiro a referência do serviço Dubbo e adicione o seguinte conteúdo a xml-dubbo-consumer.xml:
<dubbo:reference id="genericProviderService" generic="true" interface="com.wyz.service.api.GenericProviderService"/>
O parâmetro generic declara que este é um serviço de chamada genérico. Neste momento, o IDEA interface="com.wyz.service.api.GenericProviderService"
o marcará em vermelho e solicitará "Não é possível resolver a classe 'GenericProviderService'". Não precisamos prestar atenção a isso, porque a interface GenericProviderService não existe no pacote com.wyz.service.api.
Então vamos usar a interface GenericProviderService:
ApplicationContext context = SpringContextUtils.getApplicationContext();
// genericProviderService是XML中定义的服务id
GenericService genericService = (GenericService) context.getBean("genericProviderService");
// $invoke的3个参数分别为:方法名,参数类型,参数
Object result = genericService.$invoke("say", new String[]{"java.lang.String"}, new Object[]{"wyz"});
System.out.println(result);
Dessa forma, podemos obter os serviços fornecidos pela interface GenericProviderService por meio do ApplicationContext.
Dicas : SpringContextUtils é usado para obter ApplicationContext, o código é o seguinte:
@Component
public class SpringContextUtils implements ApplicationContextAware {
private static ApplicationContext applicationContext = null;
public static ApplicationContext getApplicationContext() {
return SpringContextUtils.applicationContext;
}
@Override
public void setApplicationContext(@Nonnull ApplicationContext applicationContext) throws BeansException {
SpringContextUtils.applicationContext = applicationContext;
}
}
epílogo
Bem, até agora, conhecemos e aprendemos sobre a configuração e o uso de recursos comuns no Dubbo. É claro que, após anos de desenvolvimento, o Dubbo oferece muito mais recursos do que isso. Se você quiser aprender mais, pode visualizar o documento " Apache Dubbo Microservice Framework da entrada ao domínio " fornecido pela Alibaba .
No próximo artigo, iniciaremos oficialmente a exploração dos princípios de implementação do Dubbo a partir da parte de registro do serviço.
Se este artigo for útil para você, dê-lhe muitos elogios e apoio. Se houver algum erro no artigo, por favor, critique e corrija. Por fim, todos estão convidados a prestar atenção em Wang Youzhi, um homem . Até a próxima!