DEV Community

Willian Ferreira Moya
Willian Ferreira Moya

Posted on • Originally published at springmasteryhub.com

@PreDestroy and @PostConstruct in Spring

These annotations are called at specific moments in the bean lifecycle.

They allow you to define methods executed after a bean is created and before the beans are destroyed.

Both annotations come from Jakarta EE and can be used in Spring projects.

They are useful for managing resources that are only used in the bean’s life cycle scope.

Let’s see a practical example:

We have a CustomNotificationService bean that uses an ExternalMessageSender

Before sending messages, you need to create a connection to an external API and authenticate.

So our ExternalMessageSender should look like this:

public class ExternalMessageSender {

    public void authenticate(String apiKey, String secret) {
        log.info("Called on bean creation");
    }

    public void sendMessage(String recipient, String content) {
        log.info("Message sent to " + recipient + ": " + content + " when processing the request");
    }

    public void closeConnection() {
        log.info("Called on bean destruction");
    }
}
Enter fullscreen mode Exit fullscreen mode

Now, let's create the CustomNotificationService bean, where the fun happens.

This bean will be request-scoped, so it becomes easier to see the bean lifecycle.

The scope will be requested so the bean will be available only in the It will be created when a request is made, and destroyed after the request is done.

@Service
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class CustomNotificationService {

    private ExternalMessageSender messageSender;

    @PostConstruct
    public void initialize() {
        messageSender = new ExternalMessageSender("<https://api.example.com/messages>");
        messageSender.authenticate("api_key", "secret");
    }

    public void sendNotification(String userId, String message) {
        messageSender.sendMessage(userId, message);
    }

    @PreDestroy
    public void cleanup() {
        messageSender.closeConnection();
    }
}

Enter fullscreen mode Exit fullscreen mode

So we used the initialize() method as @PostConstruct after the bean was created.

We used the cleanup() method will be used before the bean was destroyed.

And we can use the resource we created in Bean in all the other methods.

To exercise this code, we can create this controller:

// NotificationController class
@RestController
public class NotificationController {
    // ... (Autowired notificationService) ...

    @PostMapping("/send-notification")
    public String sendNotification(@RequestBody NotificationRequest request) {
        String userId = request.userId();
        String message = request.message();
        notificationService.sendNotification(userId, message);
        return "Notification sent successfully!";
    }
}

// NotificationRequest record
public record NotificationRequest(
        String userId,
        String message
) {}

Enter fullscreen mode Exit fullscreen mode

Calling the endpoint /send-notification, you'll see the following output in logs, demonstrating the methods being executed at each stage of the bean's lifecycle:

2024-06-27T21:30:48.287-03:00 INFO 14944 --- [nio-8080-exec-3] c.s.m.postandpre.ExternalMessageSender   : Called on bean creation
2024-06-27T21:30:48.287-03:00 INFO 14944 --- [nio-8080-exec-3] c.s.m.postandpre.ExternalMessageSender   : Message sent to 123: Hello world @PostConstruct and @PreDestroy. when processing the request
2024-06-27T21:30:48.289-03:00 INFO 14944 --- [nio-8080-exec-3] c.s.m.postandpre.ExternalMessageSender   : Called on bean destruction

Enter fullscreen mode Exit fullscreen mode

Conclusion

In this blog post, you learned how to leverage the @PostConstruct and @PreDestroy annotations to add custom behavior during the lifecycle of your Spring beans.

If you found this topic interesting, follow me for more insights into Spring annotations and other valuable tips!

Follow me!

Top comments (0)