β 1. @Async β Asynchronous Execution
πΉ Code:
@Configuration
@EnableAsync
public class AppConfig {}
πΈ Explanation:
@Configuration
: Tells Spring this class defines beans.@EnableAsync
: Enables Spring’s ability to run methods asynchronously using@Async
.
πΉ Service:
@Service
public class EmailService {
@Async
public void sendEmail(String to) {
System.out.println("Sending email to: " + to);
try {
Thread.sleep(3000); // simulate delay
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Email sent to: " + to);
}
}
πΈ Explanation:
@Service
: Makes this a Spring-managed bean.@Async
: RunssendEmail()
in a new thread (non-blocking).Thread.sleep(3000)
: Simulates a 3-second delay as if sending an email.
πΉ Controller:
@RestController
public class NotificationController {
@Autowired
private EmailService emailService;
@GetMapping("/notify")
public String notifyUser() {
emailService.sendEmail("[email protected]");
return "Notification triggered!";
}
}
πΈ Explanation:
- When you access
/notify
, Spring immediately responds, whilesendEmail
continues to run in the background thread.
β 2. @ControllerAdvice β Global Exception Handling
πΉ Code:
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(IllegalArgumentException.class)
public ResponseEntity<String> handleIllegalArg(IllegalArgumentException ex) {
return new ResponseEntity<>("Invalid input: " + ex.getMessage(), HttpStatus.BAD_REQUEST);
}
@ExceptionHandler(Exception.class)
public ResponseEntity<String> handleAll(Exception ex) {
return new ResponseEntity<>("Server Error: " + ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
}
}
πΈ Explanation:
@ControllerAdvice
: Applies to all controllers.@ExceptionHandler
: Specifies which exception this method handles.ResponseEntity
: Allows you to return custom status and message.
πΉ Controller:
@RestController
public class TestController {
@GetMapping("/error")
public String throwError() {
throw new IllegalArgumentException("Bad ID");
}
}
πΈ Result:
Visiting /error
returns 400 Bad Request
with "Invalid input: Bad ID"
β 3. MockMvc β Controller Testing
πΉ Code:
@RunWith(SpringRunner.class)
@WebMvcTest(HelloController.class)
public class HelloControllerTest {
@Autowired
private MockMvc mockMvc;
@Test
public void testHelloEndpoint() throws Exception {
mockMvc.perform(get("/hello"))
.andExpect(status().isOk())
.andExpect(content().string("Hello Spring"));
}
}
πΈ Explanation:
@WebMvcTest
: Loads only web layer (not full context).MockMvc
: Used to simulate HTTP requests to test controllers.get("/hello")
: Sends a fake GET request to/hello
.
πΉ Controller:
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() {
return "Hello Spring";
}
}
β 4. CORS Configuration
πΉ Code:
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins("http://localhost:3000")
.allowedMethods("GET", "POST");
}
}
πΈ Explanation:
- Allows JavaScript frontend (e.g., React on port 3000) to call Spring backend.
/api/**
matches any endpoint starting with/api
.
β 5. Custom Converter β String to User
πΉ Converter:
@Component
public class StringToUserConverter implements Converter<String, User> {
@Autowired
private UserRepository userRepository;
@Override
public User convert(String id) {
return userRepository.findById(id).orElse(null);
}
}
πΈ Explanation:
- Converts
String
ID intoUser
object using repository. - Spring auto-uses this in
@RequestParam
,@PathVariable
, or form binding.
πΉ Usage:
@GetMapping("/user")
public String getUser(User user) {
return "User: " + user.getName();
}
β 6. Static Resources
πΉ Example Directory:
src/main/resources/static/js/script.js
πΉ Access in Browser:
http://localhost:8080/js/script.js
πΈ Explanation:
- Spring Boot automatically maps
/static/**
to serve static files.
β 7. Custom Annotation + AOP Logging
πΉ Annotation:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LogExecutionTime {}
πΉ Aspect:
@Aspect
@Component
public class LoggingAspect {
@Around("@annotation(LogExecutionTime)")
public Object logTime(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.currentTimeMillis();
Object result = joinPoint.proceed(); // Execute method
long end = System.currentTimeMillis();
System.out.println("Execution Time: " + (end - start) + " ms");
return result;
}
}
πΉ Service:
@Service
public class MyService {
@LogExecutionTime
public void process() throws InterruptedException {
Thread.sleep(2000);
}
}