No Spring, @Autowired não deveria ser seu padrão

Em muito projeto Spring, o uso de @Autowired em atributo virou reflexo.

O problema é que isso quase nunca aparece como problema no primeiro dia.

O código compila, a aplicação sobe e a classe parece pronta.

Mas, conforme o sistema cresce, fica mais difícil enxergar do que cada classe depende, escrever testes simples e perceber quando um serviço está assumindo responsabilidades demais.

Funciona, mas cria um problema silencioso: a dependência deixa de aparecer como parte explícita do contrato do objeto.

No Spring atual, na maioria dos casos, @Autowired nem é necessário.


O que muda na prática

Se uma classe tem um único construtor, o Spring já sabe que deve usá-lo para injeção.

Com injeção por construtor, a dependência aparece logo na entrada da classe.

Ela deixa de ser um detalhe escondido em atributo e passa a fazer parte da definição do objeto.

O resultado é simples: o código fica mais claro, o teste fica mais direto e a classe passa a dizer com mais honestidade do que precisa para existir.

Isso não quer dizer que @Autowired desaparece de todo cenário.

Às vezes ele ainda aparece no construtor, especialmente em código antigo ou em classes com mais de um construtor, quando o Spring precisa saber qual caminho usar.

Também pode aparecer em métodos setter, normalmente quando a dependência é opcional ou precisa ser resolvida depois da criação do objeto.

Mas esse é o ponto: esses casos são exceção de desenho, não o padrão mais saudável para dependências obrigatórias.


Um exemplo comparativo

Com @Autowired em campo:

@Service
public class PedidoService {

    @Autowired
    private EmailService emailService;
}

A dependência existe, mas fica escondida no corpo da classe.

Agora com injeção por construtor:

@Service
public class PedidoService {

    private final EmailService emailService;

    public PedidoService(EmailService emailService) {
        this.emailService = emailService;
    }
}

Aqui, se PedidoService precisa de EmailService, isso aparece imediatamente.

Esse formato também força uma leitura melhor da classe.

Se o construtor começar a crescer demais, o problema fica visível rápido.

Isso ajuda a perceber acoplamento excessivo e classes com responsabilidade demais, algo que o uso de @Autowired em campo costuma esconder por mais tempo.


Onde isso encosta em Dependency Injection

Isso conversa com os posts sobre IoC, Bean e DI.

O Spring cria e conecta os objetos, mas a classe ainda precisa declarar com clareza do que depende.

Esse é o ponto central: Dependency Injection não é esconder dependências para o framework resolver depois.

É declarar dependências de forma explícita para que o container possa montar a aplicação com clareza.


O que isso muda no seu código

@Autowired não é o centro da injeção de dependência no Spring.

O centro é a classe declarar corretamente o que precisa.

Quando a dependência entra pelo construtor, o código conversa melhor com o modelo do framework e com quem vai manter a aplicação depois.

Por isso, o ponto que vale fixar é simples: constructor injection não é preciosismo de estilo.

É uma forma mais segura de deixar visível o desenho real da classe.

Quando a dependência fica escondida em atributo, o código continua rodando, mas o contrato fica mais fraco.

Em Spring, clareza de dependência não é detalhe. É parte da qualidade do design.