@Async, @ControllerAdvice Global Exception Handling, MockMvc, Cors configuration, AOP Logging
✅ 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, whilesendEmailcontinues 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
StringID intoUserobject 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);
}
}
