22‐Bean Scopes - JulianeMaran32/Java-with-Spring-Boot GitHub Wiki

52. Bean Scopes - Visão Geral

  • Escopo define o ciclo de vida de um bean:
    • Por quanto tempo o bean permanece na memória?
    • Quantas instâncias são criadas?
    • Como essas instâncias são compartilhadas na aplicação?

Escopo Padrão

  • O escopo padrão no Spring é o singleton.
  • Por padrão, o Spring cria uma única instância (singleton) de cada bean.
  • Essa instância é armazenada em memória e reutilizada sempre que o bean for necessário.
  • Todas as injeções de dependência usarão essa mesma instância.

O que é Singleton?

  • O container do Spring cria apenas uma instância do bean por padrão.
  • Essa única instância é armazenada em cache e todas as injeções de dependência referenciam o mesmo objeto.

Exemplo:

@RestController
public class DemoController {

    private Coach myCoach;
    private Coach anotherCoach;

    @Autowired
    public DemoController(@Qualifier("cricketCoach") Coach theCoach,
                          @Qualifier("cricketCoach") Coach theAnotherCoach) {
        this.myCoach = theCoach;
        this.anotherCoach = theAnotherCoach;
    }
    // ...
}
  • Nesse exemplo, como ambos os campos injetados usam o mesmo qualificador ("cricketCoach"), eles apontam para a mesma instância.

Especificando o Escopo do Bean de Forma Explícita

Você pode declarar explicitamente o escopo usando a anotação @Scope:


@Component
@Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
public class CricketCoach implements Coach {
    // ...
}

Outros Escopos Disponíveis no Spring

Escopo Descrição
singleton Apenas uma instância do bean é criada e compartilhada. (Padrão)
prototype Uma nova instância é criada cada vez que o bean é solicitado.
request Uma instância por requisição HTTP (aplicável apenas em web apps).
session Uma instância por sessão HTTP (apenas para web apps).
application Uma instância para o contexto de uma aplicação web (ServletContext).
websocket Uma instância por conexão de websocket (aplicável para web apps com websockets).

Exemplo: Escopo Prototype

No escopo prototype, uma nova instância é criada para cada injeção.


@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class CricketCoach implements Coach {
    // ...
}

Com o seguinte controlador:

@RestController
public class DemoController {

    private Coach myCoach;
    private Coach anotherCoach;

    @Autowired
    public DemoController(@Qualifier("cricketCoach") Coach theCoach,
                          @Qualifier("cricketCoach") Coach theAnotherCoach) {
        this.myCoach = theCoach;
        this.anotherCoach = theAnotherCoach;
    }

    @GetMapping("/check")
    public String check() {
        return "Comparing beans: myCoach == anotherCoach, " + (myCoach == anotherCoach);
    }
}
  • Se o bean estiver em escopo singleton, a comparação (myCoach == anotherCoach) retornará true.
  • Se estiver no escopo prototype, a comparação retornará false.

53. Bean Scopes - Codificação

Passos Realizados:

  1. Housekeeping:

    • Parar todas as aplicações.
    • Fechar todas as janelas.
    • Fazer uma cópia da pasta do projeto, renomeando, por exemplo, de 06-lazy-initialization para 07-beans-scopes.
  2. Limpeza de Configurações:

    • Remover a anotação @Lazy.
    • Remover a configuração global spring.main.lazy-initialization=true do arquivo application.properties.

Código do DemoController (para testar o escopo):


@RestController
public class DemoController {

    private Coach myCoach;
    private Coach anotherCoach;

    @Autowired
    public DemoController(@Qualifier("cricketCoach") Coach theCoach,
                          @Qualifier("cricketCoach") Coach theAnotherCoach) {
        this.myCoach = theCoach;
        this.anotherCoach = theAnotherCoach;
    }

    @GetMapping("/dailyworkout")
    public String getDailyWorkout() {
        return myCoach.getDailyWorkout();
    }

    @GetMapping("/check")
    public String check() {
        return "Comparing beans: myCoach == anotherCoach, " + (myCoach == anotherCoach);
    }
}
  • Resultado Esperado com Escopo Singleton:
    Ao acessar o endpoint /check, o retorno será:

    Comparing beans: myCoach == anotherCoach, true
    
  • Isso ocorre porque, no escopo singleton, todas as injeções referenciam a mesma instância.

Alterando para Escopo Prototype

Basta modificar a classe do bean para o escopo prototype:


@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) // Nova instância para cada injeção
public class CricketCoach implements Coach {

    public CricketCoach() {
        System.out.println("In constructor: " + getClass().getSimpleName());
    }

    @Override
    public String getDailyWorkout() {
        return "Practice fast bowling for 15 minutes";
    }
}
  • Resultado Esperado com Escopo Prototype:
    Ao acessar o endpoint /check, o retorno será:

    Comparing beans: myCoach == anotherCoach, false
    
  • Ou seja, cada injeção cria uma nova instância, e as referências são diferentes.

Conclusão

  • O escopo singleton (padrão) cria uma única instância compartilhada em toda a aplicação.
  • O escopo prototype cria uma nova instância para cada injeção ou solicitação.
  • Você pode verificar o comportamento do escopo comparando as instâncias injetadas através de uma rota (por exemplo, /check).