Nos artigos anteriores, foram construídos os módulos básicos de um framework RPC, incluindo centro de registro, serializador e desserializador, balanceador de carga, conversor de tipos de mensagens e proecssador de requisições TCP. Neste artigo, abordaremos itens de inicialização e exemplos práticos.
Definimos a anotação @RpcReference para gerar automaticamente objetos proxy e realizar injeção:
Ver código
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface RpcReference {
Class<?> interfaceClass() default void.class;
String versaoServico() default ConstantesRPC.VERSAO_PADRAO;
String balanceador() default ChavesBalanceador.ROUND_ROBIN;
String estrategiaRepeticao() default ChavesEstrategiaRepeticao.NENHUMA;
String estrategiaTolerancia() default ChavesEstrategiaTolerancia.FALHA_RAPIDA;
boolean simulacao() default false;
}
Criamos a classe de inicialização para serviços RPC:
Ver código
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import({InicializadorRpc.class, ProvedorRpcBoot.class, ConsumidorRpcBoot.class})
public @interface HabilitarRpc {
boolean iniciarServidor() default true;
}
Implementamos a anotação para registro de serviços:
Ver código
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Component
public @interface ServicoRpc {
Class<?> interfaceClass() default void.class;
String versaoServico() default ConstantesRPC.VERSAO_PADRAO;
}
Utilizamos o mecanimso BeanPostProcessor do Spring para injetar dinamicamente objetos proxy em campos anotados com @RpcReference:
Ver código
public class ConsumidorRpcBoot implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String nomeBean) {
Class<?> classeBean = bean.getClass();
for (Field campo : classeBean.getDeclaredFields()) {
RpcReference referencia = campo.getAnnotation(RpcReference.class);
if (referencia != null) {
Class<?> interfaceAlvo = referencia.interfaceClass();
if (interfaceAlvo == void.class) {
interfaceAlvo = campo.getType();
}
campo.setAccessible(true);
Object proxy = FabricaProxyServico.criarProxy(interfaceAlvo);
try {
campo.set(bean, proxy);
} catch (IllegalAccessException e) {
throw new RuntimeException("Falha na injeção do proxy", e);
} finally {
campo.setAccessible(false);
}
}
}
return bean;
}
}
Configuramos a inicialização automática para registrar serviços anotados com @ServicoRpc no centro de registro durente o startup:
Ver código
public class ProvedorRpcBoot implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String nomeBean) {
Class<?> classeBean = bean.getClass();
ServicoRpc servico = classeBean.getAnnotation(ServicoRpc.class);
if (servico != null) {
Class<?> interfaceServico = servico.interfaceClass();
if (interfaceServico == void.class) {
interfaceServico = classeBean.getInterfaces()[0];
}
String nomeServico = interfaceServico.getName();
String versao = servico.versaoServico();
RegistroLocal.registrar(nomeServico, classeBean);
ConfiguracaoRpc config = AplicacaoRpc.getConfiguracao();
ConfiguracaoRegistro configRegistro = config.getConfiguracaoRegistro();
Registro registro = FabricaRegistro.obterInstancia(configRegistro.getTipo());
MetadadosServico metadados = new MetadadosServico();
metadados.setNome(nomeServico);
metadados.setVersao(versao);
metadados.setHost(config.getHostServidor());
metadados.setPorta(config.getPortaServidor());
try {
registro.registrar(metadados);
} catch (Exception e) {
throw new RuntimeException("Falha no registro: " + nomeServico, e);
}
}
return bean;
}
}