Solucionado (ver solução)
Solucionado
(ver solução)
6
respostas

@Autowired

O que significa dizer que o Spring esta injetando para mim, quando colocamos um @Autowired?

6 respostas

Aproveitando, qual a diferença do @Bean para o @Autowired?

Já entendi a rsa256, quero entender so o Autowired mesmo, pq ja vi alguns exemplos usando ate em construtor e nao entendi direito. Gerar o token assim estaria correto? precisaria do autowired em cima do construtor?

@Service
public class TokenService {

   private final Algorithm algorithm;

   public TokenService(@Value("${jwt.secret}") String secret) {
      this.algorithm = Algorithm.HMAC256(secret);
   }


   public String gerarToken(Authentication authenticate) {
      return JWT.create()
            .withSubject(authenticate.getName())
            .withIssuer("auth0")
            .sign(algorithm);
   }
}

Bom dia, Luccas! Tudo joia?

  1. sobre o @Autowired

    No Spring Framework, @Autowired é uma anotação usada para permitir a injeção de dependências automaticamente. Quando você usa @Autowired em um campo, método, ou construtor, o Spring automaticamente injeta a dependência necessária no ponto anotado. Isso significa que o Spring cuida da criação e gerenciamento das instâncias dos objetos, garantindo que os componentes necessários estejam disponíveis e corretamente configurados.

  2. Diferença entre @Autowired e @Bean

    • @Autowired:

      • Usada para injeção de dependências.
      • Marca uma dependência que o Spring deve resolver e injetar automaticamente.
      • Pode ser usada em campos, métodos setter, ou construtores.
      • Por exemplo, ao usar @Autowired em um construtor, você está dizendo ao Spring que ele deve injetar as dependências especificadas no construtor quando criar uma instância da classe.
    • @Bean:

      • Usada para definir um bean que será gerenciado pelo Spring.
      • Marca um método em uma classe de configuração que retorna um objeto que deve ser registrado no contexto do Spring.
      • O método anotado com @Bean é chamado pelo Spring para obter uma instância do bean.
      • Por exemplo, você pode usar @Bean para criar e configurar objetos que não são diretamente anotados com @Component, @Service, ou outras anotações de estereótipo do Spring.
  3. Injeção no Construtor

    No exemplo que você forneceu, o Spring está injetando a propriedade jwt.secret no construtor da classe TokenService. A injeção de dependências no construtor é uma prática recomendada, pois torna a classe imutável e facilita o teste.

  4. Gerando um Token JWT

    A geração do token está correta e você não precisa de @Autowired no construtor porque está usando a anotação @Value para injetar a propriedade jwt.secret. No entanto, se você tivesse outras dependências que precisassem ser injetadas pelo Spring, você poderia usar @Autowired no construtor.

    Exemplo atualizado com @Autowired no construtor:

    @Service
    public class TokenService {
    
       private final Algorithm algorithm;
    
       @Autowired
       public TokenService(@Value("${jwt.secret}") String secret) {
          this.algorithm = Algorithm.HMAC256(secret);
       }
    
       public String gerarToken(Authentication authenticate) {
          return JWT.create()
                .withSubject(authenticate.getName())
                .withIssuer("auth0")
                .sign(algorithm);
       }
    }
    

Aqui, @Autowired no construtor é redundante se você já está usando @Value, mas em um cenário onde você tem múltiplas dependências a serem injetadas, ele pode ser útil.

Espero ter conseguido responder todas as suas dúvidas, caso tenha mais, estarei à disposição para ajudá-lo.

Bons estudos!

Caso este post tenha lhe ajudado, por favor, marcar como solucionado ✓.

Muito obrigado professor, entendi sim, desculpa a demora. Perfeita explicação. Aproveitando que vc falou de @Component, @Service. Eu gostaria de saber por exemplo se eu tenho uma classe de service por exemplo UserService. só que eu tenho diferentes tipos de User, onde todos os Users podem fazer a funçao x. O UserA pode fazer x e a, mas nao pode fazer b. Já o UserB pode fazer x e B, mas nao pode fazer A. nesse caso Eu pensei em ter uma abstract class UserService e subclasses UserServiceA e UserServiceB (Claro que nao botei esses nomes, só um exemplo). Aparentemente colocar UserService com @Service seria um má pratica por ela ser abstrata n é isso? porem poderia colocar sei la @component ou configurar um @bean? ou como faria para solucionar o problema visto que em outro service por exemplo TransactionService eu recebo um User Generico e eu nao sei se esse User ele é UserA ou UserB, entao como em UserService tem metodos que sao comuns como por exemplo findbyId, eu queria poder usar esse UserService tambem em alguns casos, e em casos que tem funçoes especificas eu pensei em usar um factory para identificar o tipoUser para devolver o UserService especifico para aquele usuario, porem nao consegui configurar o UserService por uma classe abstrata, como faço nesse caso? ja que nao é uma boa praticar colocar @Service na classe abstrata de service. Segue o codigo link do codigo para ter uma visao melhor. obs: não economizem nas criticas. https://github.com/luccastguimaraes/picpay-mysql

acabei de fazer por meio do factory, ficou assim: se vai funcionar? n sei. acredito que deve aparecer algum problema em relação a cast de User a qlqr momento...

@Component
public class UserServiceFactory {

   @Autowired
   private  UserRepository repository;
   @Autowired
   private CommonUserService commonUserService;
   @Autowired
   private MerchantUserService merchantUserService;


   public UserServiceFactory(UserRepository repository, CommonUserService commonUserService, MerchantUserService merchantUserService) {
   }


   public UserService getUserService(Long id){
      User user = repository.findById(id).orElseThrow(() -> new EntityNotFoundException("CommonUser not found with ID: " + id));

      if ("COMMON".equalsIgnoreCase(user.getUserType().toString())){
         return this.commonUserService;
      } else if ("MERCHANT".equalsIgnoreCase(user.getUserType().toString())) {
         return this.merchantUserService;
      } else {
         throw new IllegalArgumentException("Tipo de usuário não suportado: " + user.getUserType());
      }
   }
}
@Configuration
public class AppConfig {
   @Bean
   public RestTemplate restTemplate() {
      return new RestTemplate();
   }

   @Bean
   public CommonUserService commonUserService(UserRepository repository) {
      return new CommonUserService(repository);
   }

   @Bean
   public MerchantUserService merchantUserService(UserRepository repository) {
      return new MerchantUserService(repository);
   }

   @Bean
   public UserServiceFactory userServiceFactory(UserRepository repository){
      return new UserServiceFactory(repository, commonUserService(repository), merchantUserService(repository));
   }
}
solução!

Boa tarde, Luccas!

Seu código parece bem estruturado. No entanto, existem algumas melhorias e ajustes que podem ser feitos para garantir que funcione corretamente e para evitar possíveis problemas com o casting de User. Aqui estão algumas sugestões:

Ajustes na UserServiceFactory

  1. Remova a Injeção de Dependência Duplicada no Construtor: A injeção de dependência pelo construtor é redundante quando você já está usando a anotação @Autowired.

  2. Use @Autowired para Injetar Dependências: Use a anotação @Autowired no construtor para garantir que as dependências sejam injetadas corretamente.

Ajustes na Configuração

  1. Configure o UserServiceFactory: Certifique-se de que a fábrica de serviços de usuário está configurada corretamente.

Segue como ficará a implementação assim que for ajustada:

UserServiceFactory:

@Component
public class UserServiceFactory {

   private final UserRepository repository;
   private final CommonUserService commonUserService;
   private final MerchantUserService merchantUserService;

   @Autowired
   public UserServiceFactory(UserRepository repository, CommonUserService commonUserService, MerchantUserService merchantUserService) {
       this.repository = repository;
       this.commonUserService = commonUserService;
       this.merchantUserService = merchantUserService;
   }

   public UserService getUserService(Long id){
      User user = repository.findById(id).orElseThrow(() -> new EntityNotFoundException("CommonUser not found with ID: " + id));

      if ("COMMON".equalsIgnoreCase(user.getUserType().toString())){
         return this.commonUserService;
      } else if ("MERCHANT".equalsIgnoreCase(user.getUserType().toString())) {
         return this.merchantUserService;
      } else {
         throw new IllegalArgumentException("Tipo de usuário não suportado: " + user.getUserType());
      }
   }
}

AppConfig:

@Configuration
public class AppConfig {

   @Bean
   public RestTemplate restTemplate() {
      return new RestTemplate();
   }

   @Bean
   public CommonUserService commonUserService(UserRepository repository) {
      return new CommonUserService(repository);
   }

   @Bean
   public MerchantUserService merchantUserService(UserRepository repository) {
      return new MerchantUserService(repository);
   }

   @Bean
   public UserServiceFactory userServiceFactory(UserRepository repository, CommonUserService commonUserService, MerchantUserService merchantUserService){
      return new UserServiceFactory(repository, commonUserService, merchantUserService);
   }
}

Com esses ajustes, sua factory deve funcionar corretamente, evitando problema de casting e garantindo que o serviço correto seja retornado com base no tipo de usuário.

No mais, boa sorte no projeto!