No caminho para aprofundar o desenvolvimento em Java, as anotações (Annotations) são uma "ferramenta mágica" para aumentar a eficiência. Elas não são tão intuitivas quanto a lógica de negócios, mas simplificam silenciosamente as configurações, normalizam o código e reduzem o acoplamento, nos libertando de configurações XML complexas e código repetitivo.
No entanto, existem muitos tipos de anotações, e muitos iniciantes ficam no dilema de "aprender e esquecer por não usar". Hoje, focaremos nas anotações que aparecem com **alta frequência no desenvolvimento real**, categorizadas em cinco grandes cenários: "Spring Core, Desenvolvimento Web, Camada de Persistência de Dados, Ferramentas de Código e Básico do JDK", combinando com exemplos de negócios reais para explicar o uso em profundidade. Você pode copiar diretamente para o seu projeto após a leitura!
I. Anotações Core do Spring: A Base da Inversão de Controle e Injeção de Dependência
O núcleo do framework Spring é a IOC (Inversão de Controle) e AOP (Programação Orientada a Aspectos), e as anotações são justamente o veículo central para realizar essas características. No desenvolvimento diário, quase toda classe que você escreve pode usá-las.
1. @Component e Suas Derivações: Entregar a Classe para o Gerenciamento do Spring
Função: Marcar uma classe como um "Bean gerenciado pelo Spring", permitindo que o Spring crie automaticamente a instância e a coloque no contêiner, sem precisar criar objetos manualmente com new. Este é o pré-requisito para a injeção de dependência.
Anotações Derivadas (semântica mais clara, mesma funcionalidade):
- @Controller: Usado na camada Controller (receber requisições, retornar respostas), deixando claro que a responsabilidade da classe é tratar requisições do front-end.
- @Service: Usado na camada Service (processamento da lógica de negócios), identificando que esta é a classe de negócios central, facilitando o aprimoramento posterior do aspecto AOP (como transações, logs).
- @Repository: Usado na camada Dao (acesso a dados), originalmente em combinação com Spring Data, agora mais frequentemente substituído pelo @Mapper do MyBatis, mas semanticamente ainda é recomendado mantê-lo.
Exemplo Prático:
// Camada Controller: Recebe a requisição do usuário
@Controller
@RequestMapping("/customer")
public class CustomerController {
// Injeção de dependência do objeto da camada Service
@Autowired
private CustomerService customerService;
// Trata a requisição para buscar um cliente
@GetMapping("/{identifier}")
@ResponseBody
public Customer retrieveCustomer(@PathVariable Long identifier) {
return customerService.fetchCustomerById(identifier);
}
}
// Camada Service: Lida com a lógica de negócios
@Service
public class CustomerServiceImpl implements CustomerService {
@Autowired
private CustomerRepository customerRepository;
// Anotação de transação: Garante a atomicidade do negócio
@Transactional
@Override
public Customer fetchCustomerById(Long identifier) {
// Lógica de negócios
return customerRepository.findById(identifier);
}
}
2. @Autowired e @Resource: O "Duo" da Injeção de Dependência
Função: Obter um Bean do contêiner do Spring e injetá-lo na classe atual, evitando chamar getBean() manualmente. É a chave para o desacoplamento.
Diferença Core (essencial distinguir no desenvolvimento):
- @Autowired: Anotação nativa do Spring, injeta por "tipo (byType)". Se houver múltiplos Beans do mesmo tipo, é necessário usar
@Qualifierpara especificar o nome do Bean. - @Resource: Anotação nativa do JDK (javax.annotation.Resource), por padrão injeta por "nome (byName)". Se o nome não corresponder, então casa por tipo, sem necessidade de anotações adicionais.
Exemplo Prático de Atenção:
@Service
public class CheckoutService {
// Cenário 1: Apenas um Bean do mesmo tipo, usa @Autowired diretamente
@Autowired
private OrderProcessor orderProcessor;
// Cenário 2: Múltiplos Beans do mesmo tipo (ex: duas implementações de PaymentGateway), é necessário especificar o nome
@Autowired
@Qualifier("stripeGateway") // Corresponde ao nome do Bean (padrão: nome da classe com a primeira letra minúscula)
private PaymentGateway creditCardGateway;
// Cenário 3: Usar @Resource é mais conciso, especificando o nome diretamente
@Resource(name = "paypalGateway")
private PaymentGateway digitalWalletGateway;
}
3. @Transacitonal: Gerencie Transações com Uma Única Linha de Código
Função: Adicionar suporte de transação a um método, garantindo o princípio de "tudo ou nada". É a anotação core para resolver problemas de consistência de dados (por exemplo, a criação de um pedido e a dedução do estoque devem ser concluídas com sucesso juntas).
Atributos Chave (comumente usados no desenvolvimento):
- rollbackFor: Especifica quais exceções desencadeiam um rollback (por padrão, apenas exceções de runtime fazem rollback). Deve ser configurado, caso contrário, exceções não-runtime (como IOException) não causarão rollback.
- propagation: Comportamento de propagação da transação, como REQUIRED (padrão, cria uma nova se não houver transação, junta se houver), REQUIRES_NEW (força a criação de uma nova transação).
Exemplo Prático:
@Service
public class CheckoutServiceImpl implements CheckoutService {
@Autowired
private OrderDao orderDao;
@Autowired
private InventoryDao inventoryDao;
// Negócio core: Criar pedido + deduzir estoque, deve ser atômico
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
@Override
public void placeOrder(Order order) {
// 1. Criar o pedido
orderDao.insert(order);
// 2. Deduzir o estoque (se uma exceção for lançada aqui, a criação do pedido fará rollback)
inventoryDao.reduceStock(order.getProductId(), order.getQuantity());
}
}
II. Anotações de Desenvolvimento Web: "Atalhos" para o Desenvolvimento de APIs
Seja com Spring MVC ou Spring Boot, o desenvolvimento de APIs não pode prescindir dessas anotações. Elas definem o método da requisição, o mapeamento de parâmetros e o formato da resposta, sendo a ponte de interação entre front-end e back-end.
1. @RequestMapping e Suas Derivações: Localizando o Endereço da API
Função: Mapear requisições HTTP para métodos do Controller, especificando o caminho de acesso e o método da requisição da API.
Anotações Derivadas (substituem @RequestMapping, mais concisas):
- @GetMapping: Corresponde a requisições GET, usado para buscar dados (ex: buscar usuário, buscar pedidos).
- @PostMapping: Corresponde a requisições POST, usado para submeter dados (ex: criar usuário, fazer pedido).
- @PutMapping: Corresponde a requisições PUT, usado para atualizar dados (atualização completa).
- @DeleteMapping: Corresponde a requisições DELETE, usado para deletar dados.
Exemplo Prático:
@RestController // = @Controller + @ResponseBody, retorna formato JSON
@RequestMapping("/items") // Prefixo de caminho a nível de classe
public class ItemController {
// Busca um item: GET /items/123
@GetMapping("/{itemId}")
public Item getItem(@PathVariable Long itemId) {
// Lógica de negócios
}
// Adiciona um item: POST /items
@PostMapping
public Result createItem(@RequestBody Item item) { // @RequestBody recebe parâmetros JSON
// Lógica de negócios
return Result.success();
}
// Atualiza um item: PUT /items/123
@PutMapping("/{itemId}")
public Result modifyItem(@PathVariable Long itemId, @RequestBody Item item) {
// Lógica de negócios
return Result.success();
}
// Deleta um item: DELETE /items/123
@DeleteMapping("/{itemId}")
public Result removeItem(@PathVariable Long itemId) {
// Lógica de negócios
return Result.success();
}
}
2. Anotações de Mapeamento de Parâmetros: @PathVariable, @RequestBody, @RequestParam
Função: "Pegar" os parâmetros da requisição HTTP e vinculá-los aos parâmetros formais do método, sendo o core para as APIs receberem dados.
- @PathVariable: Obtém parâmetros do caminho da URL (ex: o
idem/order/{id}), comumente usado em APIs RESTful. - @RequestBody: Obtém dados JSON do corpo da requisição, usado para receber objetos complexos (como a combinação de username, senha, telefone ao criar um novo usuário).
- @RequestParam: Obtém parâmetros de consulta da URL (ex:
/order?status=1&page=1), pode especificar se é obrigatório ou o valor padrão.
Exemplo Prático:
@GetMapping("/orders")
// Consulta paginada de pedidos: /orders?state=active&pageNum=1&pageSize=20
public PageResult<order> fetchOrders(
@RequestParam(required = true) String state, // Parâmetro obrigatório
@RequestParam(defaultValue = "1") Integer pageNum, // Não obrigatório, valor padrão 1
@RequestParam(defaultValue = "20") Integer pageSize) { // Não obrigatório, valor padrão 20
return orderService.getOrders(state, pageNum, pageSize);
}</order>
III. Anotações da Camada de Persistência: "Simplificadores" da Interação com o Banco de Dados
Seja MyBatis ou Spring Data JPA, essas anotações podem substituir configurações XML complexas, tornando as operações de banco de dados mais concisas.
1. Anotações Core do MyBatis: @Mapper, @Select, @Insert, etc.
Função: Desenvolvimento baseado em anotações do MyBatis, sem a necessidade de escrever arquivos Mapper.xml, definindo consultas SQL diretamente nos métodos da interface.
Anotações Comuns:
- @Mapper: Marca a interface Dao para que o MyBatis escaneie e gere um objeto proxy, sem precisar adicionar
@MapperScanna classe principal. - @Select/@Insert/@Update/@Delete: Escreve instruções SQL diretamente na anotação, adequado para consultas simples.
- @Param: Especifica um apelido para o parâmetro do método, facilitando sua referência na consulta SQL (deve ser usado quando houver mais de um parâmetro).
Exemplo Prático:
// Interface Dao
@Mapper
public interface UserRepository {
// Consulta simples: busca usuário por ID
@Select("SELECT id, name, email FROM users WHERE id = #{userId}")
User findById(Long userId);
// Consulta com múltiplos parâmetros: busca por nome e email
@Select("SELECT id, name, email FROM users WHERE name = #{userName} AND email = #{userEmail}")
User findByNameAndEmail(@Param("userName") String name, @Param("userEmail") String email);
// Inserir um novo usuário
@Insert("INSERT INTO users(name, email, registration_date) VALUES(#{name}, #{email}, NOW())")
@Options(useGeneratedKeys = true, keyProperty = "id") // Retorna a chave primária auto-incrementada
void insert(User user);
}
2. Anotações do Spring Data JPA: @Entity, @Id, @Column
Função: JPA é uma especificação de framework ORM. Através de anotações, mapeia a relação entre classes Java e tabelas do banco de dados, permitindo o desenvolvimento com "zero SQL".
Anotações Core:
- @Entity: Marca uma classe como "classe de entidade", correspondendo a uma tabela no banco de dados.
- @Id: Especifica o campo de chave primária da classe, correspondendo à chave primária da tabela.
- @GeneratedValue: Especifica a estratégia de geração da chave primária (ex: auto-incremento, UUID).
- @Column: Especifica a relação de mapeamento entre o campo e a coluna da tabela (ex: nome da coluna, comprimento, se pode ser nulo).
Exemplo Prático:
// Classe de entidade: corresponde à tabela 'accounts' do banco de dados
@Entity
@Table(name = "accounts") // Pode ser omitido se o nome da classe for igual ao nome da tabela
public class Account {
// Chave primária: estratégia de auto-incremento
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
// Nome de usuário: coluna 'username', não nulo, comprimento 100
@Column(name = "username", nullable = false, length = 100)
private String username;
// Email: coluna 'email', único
@Column(unique = true)
private String email;
// Data de criação: coluna 'created_at', timestamp gerado automaticamente
@Column(name = "created_at")
private LocalDateTime createdAt;
// getters/setters
}
IV. Anotações de Ferramentas de Código: "Assistentes" para Melhorar a Qualidade do Código
Essas anotações não envolvem lógica de negócios, mas podem normalizar o código e reduzir código repetitivo, sendo um "entendimento tácito" no desenvolvimento em equipe.
1. Anotações do Lombok: Eliminando o "Código de Modelo"
Função: Lombok é uma "ferramenta mágica" no desenvolvimento Java. Através de anotações, gera automaticamente getters/setters, métodos construtores, toString e outro código repetitivo, tornando as classes mais concisas.
Anotações de Alta Frequência:
- @Data: Anotação composta, inclui @Getter, @Setter, @ToString, @EqualsAndHashCode, @RequiredArgsConstructor, a mais usada no desenvolvimento.
- @NoArgsConstructor: Gera um método construtor sem parâmetros (obrigatório para JPA).
- @AllArgsConstructor: Gera um método construtor com todos os parâmetros.
- @Slf4j: Gera automaticamente o objeto de log
log, sem precisar declarar manualmenteprivate static final Logger log = LoggerFactory.getLogger(XXX.class);.
Exemplo Prático:
// Com as anotações do Lombok, não é necessário escrever getters/setters, toString, etc.
@Data
@NoArgsConstructor
@AllArgsConstructor
@Slf4j
public class Invoice {
private Long invoiceId;
private String referenceNumber;
private Long clientId;
private BigDecimal totalAmount;
public void processInvoice() {
// Usa o objeto 'log' diretamente para registrar informações
log.info("Iniciando processamento para a fatura {}", referenceNumber);
// Lógica de negócios
}
}
2. Anotações de Validação: @NotNull, @NotBlank, @Valid
Função: Validação de parâmetros (ex: nome de usuário não pode ser vindo vazio do front-end, formato do telefone está correto), substituindo julgamentos manuais if-else, melhorando a legibilidade do código.
Anotações Comuns (pacote javax.validation.constraints):
- @NotBlank: A string não pode ser nula e não pode ser composta apenas por espaços (aplicável para username, senha).
- @NotNull: O objeto não pode ser nulo (aplicável para tipos numéricos, como idade, id).
- @Pattern: A string corresponde a uma expressão regular (ex: telefone, email).
- @Valid: Dispara a validação do parâmetro, colocado antes do parâmetro do método.
Exemplo Prático:
// DTO para receber parâmetros do front-end
@Data
public class NewUserDTO {
@NotBlank(message = "O nome de usuário não pode estar em branco")
private String username;
@NotBlank(message = "A senha não pode estar em branco")
@Size(min = 8, max = 24, message = "A senha deve ter entre 8 e 24 caracteres")
private String password;
@Pattern(regexp = "^\\+?[0-9]{7,15}$", message = "Formato de telefone inválido")
private String phone;
@NotNull(message = "A idade não pode ser nula")
@Min(value = 18, message = "A idade mínima é 18 anos")
private Integer age;
}
// Camada Controller: Dispara a validação
@PostMapping("/register")
public Result registerUser(@Valid @RequestBody NewUserDTO newUserDTO, Errors validationErrors) {
// Falha na validação, retorna a mensagem de erro
if (validationErrors.hasErrors()) {
String errorMessage = validationErrors.getFieldError().getDefaultMessage();
return Result.fail(errorMessage);
}
// Validação passou, executa a lógica de negócios
userService.createAccount(newUserDTO);
return Result.success();
}
V. Anotações Básicas do JDK: "Ferramentas Pequenas" Nativas do Java
Essas são anotações nativas do Java. Embora simples, aparecem com frequência no desenvolvimento, especialmente em cenários de manutenção de código e serialização.
- @Override: Marca que um método sobrescreve um método da classe pai. Se houver erro no nome do método (ex: escrever
toStrem vez detoString), o compilador lançará um erro, evitando erros de nível baixo. - @Deprecated: Marca um método ou classe como obsoleto, alertando os desenvolvedores para não utilizá-lo, e pode sugerir a alternativa através da documentação
@deprecated. - @SuppressWarnings: Suprime avisos do compilador (ex: "variável não usada", avisos "unchecked"). Use com cautela, para evitar mascarar problemas reais.
Exemplo Prático:
public class ConverterUtils {
// Sobrescreve o método da classe pai, @Override garante a correção
@Override
public String toString() {
return "Classe de utilitários Converter";
}
// Marca o método como obsoleto, recomenda usar o método 'formatModern'
@Deprecated
public static String convert(String input) {
return input.toUpperCase();
}
// Novo método de formatação
public static String formatModern(String input) {
// Lógica otimizada
return "[" + input.trim() + "]";
}
// Suprime o aviso unchecked (ex: usar ArrayList sem especificar o tipo genérico)
@SuppressWarnings("unchecked")
public static List getRawList() {
return new ArrayList();
}
}