Skip to main content

Annotations

Annotations are Spring’s way of letting you tag your code with instructions like "Hey Spring, manage this class!" or "Inject that dependency here!" They replaced XML’s wall-of-text configuration with code-friendly metadata.

Why Annotations?

  • Before annotations, you had to repeat class names, dependencies, and configurations in a separate file. One typo and the project doesn't start.

    beans.xml
    <bean id="userService" class="com.example.UserService">
    <property name="userRepository" ref="userRepository"/>
    </bean>
  • With annotations, Spring reads them to autoconfigure your app.

    @Service
    @RequiredArgConstructor
    public class UserService {
    private final UserRepository userRepository;
    }

The Essential Annotation Toolkit

Bean Definition

AnnotationMeaningUse Case
@Component"Spring, manage this class!"Generic beans
@Service"Business logic here!"Service-layer classes
@Repository"Database interactions here!"DAOs/DB classes (adds exception translation)
@RestController"API endpoint!" (Combines @Controller + @ResponseBody)REST APIs

Dependency Injection

AnnotationMeaningExample
@Autowired"Inject a bean here!"Constructor/field/setter
@Primary"Choose me first!"Resolve ambiguous bean conflicts
@Qualifier"Inject THIS specific bean"@Qualifier("mysqlDb")

Configuration

AnnotationMeaningExample
@Configuration"This class configures beans!"Setup database/3rd-party libs
@Bean"Here’s a bean to manage!"Methods returning complex objects
@Value"Inject a property value!"@Value("${api.key}")

Web/REST

AnnotationMeaningExample
@RequestMapping"Map requests to this method"@RequestMapping("/users")
@GetMapping"Handle GET requests"@GetMapping("/{id}")
@PostMapping"Handle POST requests"@PostMapping("/create")
@RequestBody"Convert JSON → Java object"createUser(@RequestBody User user)
@PathVariable"Get URL parameters"@PathVariable Long id

Lombok

AnnotationPurposeExample
@Getter / @SetterAuto-generate getters/setters@Getter @Setter private String username;
@ToStringAuto-generate toString()@ToString(exclude = "password")
@EqualsAndHashCodeAuto-generate equals() and hashCode()@EqualsAndHashCode(callSuper = true)
@NoArgsConstructorGenerate no-arg constructor@NoArgsConstructor
@AllArgsConstructorGenerate constructor with all args@AllArgsConstructor
@RequiredArgsConstructorGenerate constructor with final/@NonNull fields@RequiredArgsConstructor
@DataAll-in-one (@Getter, @Setter, @ToString, @EqualsAndHashCode, @RequiredArgsConstructor)@Data public class User { ... }
@BuilderImplement Builder patternUser.builder().name("Alice").build();
@Slf4jInject logger (Logger log)log.info("User created: {}", username);

Tips

  1. Prefer constructor injection (private final + Lombok @RequiredArgsConstructor) over field injection (@Autowired).

  2. Layer your annotations.

    @Repository  // Data layer
    public class UserRepository { ... }

    @Service // Business logic
    public class UserService { ... }

    @RestController // API layer
    public class UserController { ... }
  3. Use @Configuration + @Bean to wire complex dependencies.

    @Configuration
    public class SecurityConfig {
    @Bean
    public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
    }
    }
  4. Environment-specific beans: Use @Profile for dev/staging/prod setups.

    @Profile("dev")
    @Service
    public class MockPaymentService implements PaymentService { ... }
  5. Avoid annotation soup: Stick to one role-specific annotation.

    @Component @Service  // Redundant!
    public class UserService { ... }