Implementação de Anotações e Inicialização em Framework RPC

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;
    }
}

Tags: rpc java Spring Anotações inicialização

Publicado em 7-31 02:04