- Definir a interafce do serviço
- Proporcionar implementações da interface (com suporte a múltiplas variantes)
- Registrar as implementações (configurando em
META-INF/services) - Carregar serviços usando
ServiceLoader
Demonstração Prática
1. Especificação da Interface
// Caminho do arquivo: src/main/java/br/exemplo/ServicoRegistro.java
package br.exemplo;
public interface ServicoRegistro {
void registrarMensagem(String texto);
}
2. Criação de Implementações (duas versões distintas)
// Caminho do arquivo: src/main/java/br/exemplo/RegistroConsole.java
package br.exemplo;
public class RegistroConsole implements ServicoRegistro {
@Override
public void registrarMensagem(String texto) {
System.out.println("[Console] " + texto);
}
}
// Caminho do arquivo: src/main/java/br/exemplo/RegistroArquivo.java
package br.exemplo;
public class RegistroArquivo implements ServicoRegistro {
@Override
public void registrarMensagem(String texto) {
System.out.println("[Arquivo] Registro gravado: " + texto); // Simulação de escrita em arquivo
}
}
3. Declaração dos Serviços
No diretório de recursos, crie o arquivo:
src/main/resources/META-INF/services/br.exemplo.ServicoRegistro
Inclua os nomes completos das classes implementadoras:
br.exemplo.RegistroConsole
br.exemplo.RegistroArquivo
4. Utilização dos Serviços
// Caminho do arquivo: src/main/java/br/exemplo/AplicacaoPrincipal.java
package br.exemplo;
import java.util.ServiceLoader;
public class AplicacaoPrincipal {
public static void main(String[] argumentos) {
// Carrega todas as implementações de ServicoRegistro
ServiceLoader<ServicoRegistro> provedores = ServiceLoader.load(ServicoRegistro.class);
// Itera e executa cada serviço
for (ServicoRegistro provedor : provedores) {
provedor.registrarMensagem("Olá via SPI!");
}
}
}
Saída Esperada
[Console] Olá via SPI!
[Arquivo] Registro gravado: Olá via SPI!
Aspectos Fundamentais
- Localização do arquivo de registro
META-INF/services/nome.completo.da.interface(sem extensão) - Formato do conteúdo
Cada linha contém o nome completo de uma classe implementadora (separadas por linhas para múltiplas opções) - Funcionamento do carregamento
OServiceLoaderbusca registros emMETA-INF/servicesusando o carregador de classes do contexto da thread - Cenários de aplicação
- Carregamento de drivers JDBC (via
DriverManager) - Fachada de logging como SLF4J
- Configuração automática no Spring Boot
- Carregamento de drivers JDBC (via
Comparação com Chamada Direta de Interface
| Aspecto | Mecanismo SPI | Chamada Direta de Interface |
|---|---|---|
| Acoplamento | Implementações podem ser estendidas de forma independente, com desacoplamento total | Exige dependência explícita de uma implementação específica |
| Adição de novas implementações | Basta adicionar um JAR com as classes, e elas são reconhecidas automaticamente | Necessita modificar o código do consumidor |
| Relações de dependência | O consumidor depende apenas da interface | O consumidor depende da interface e de uma implementação concreta |
No ecossistema Spring Boot, a estrutura spring.factories é uma evolução do SPI, com princípios semelhentes mas suporte a cenários de configuração automática mais complexos.