{"id":577488,"date":"2025-06-25T08:22:11","date_gmt":"2025-06-25T07:22:11","guid":{"rendered":"https:\/\/blog.jetbrains.com\/?post_type=idea&#038;p=577488"},"modified":"2025-09-15T09:02:39","modified_gmt":"2025-09-15T08:02:39","slug":"demystifying-spring-boot-with-spring-debugger","status":"publish","type":"idea","link":"https:\/\/blog.jetbrains.com\/en\/idea\/2025\/06\/demystifying-spring-boot-with-spring-debugger","title":{"rendered":"Demystifying Spring Boot With Spring Debugger"},"content":{"rendered":"\n<p>Spring Boot is a marvel of developer productivity. It hides the plumbing and gets you up and running fast. Components are &#8220;miraculously\u201d autowired, properties are \u201cmagically\u201d resolved, and database connections materialize seemingly without explicit configuration.<\/p>\n\n\n\n<p>But when something goes wrong, the magic becomes a mystery, and debugging becomes a deep dive into the framework&#8217;s internal mechanics.<\/p>\n\n\n\n<p>Regular debuggers handle plain Java classes and objects, lacking framework-specific context. To inspect a property, track a bean, or examine an entity state, you need to dig into the internals of Spring Boot. (Remember how to access the application context from the debugger evaluator? Neither do we.)<br><br>The rabbit was always in the hat \u2013 you just had to know where to look. IntelliJ IDEA has long allowed you to inspect loaded beans or trace the source of a property value using the debugger, but doing so wasn\u2019t exactly straightforward. Our goal is to change that \u2013 to make debugging Spring applications as comfortable and productive as the rest of your development experience in IntelliJ IDEA. The first step was an additional <a href=\"https:\/\/blog.jetbrains.com\/idea\/2024\/11\/from-code-to-clarity-with-the-redesigned-structure-tool-window\/\">structure view<\/a>, and now we\u2019re going further.&nbsp;<\/p>\n\n\n\n<p>Let\u2019s pull back the curtain on the Spring Boot magic and see how the <a href=\"https:\/\/plugins.jetbrains.com\/plugin\/25302-spring-debugger\" target=\"_blank\" rel=\"noopener\">Spring Debugger<\/a> plugin makes the invisible visible.&nbsp;<\/p>\n\n\n\n<p>If you prefer watching and listening, have a look at Marco Behler&#8217;s recent session on Spring Debugger.<\/p>\n\n\n\n<figure class=\"wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"Troubleshooting Spring Boot Applications with the Spring Debugger\" width=\"500\" height=\"281\" src=\"https:\/\/www.youtube.com\/embed\/XWoivKnqsyo?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe>\n<\/div><figcaption class=\"wp-element-caption\">Debug Spring like a Pro<\/figcaption><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>The bean that wasn\u2019t there<\/strong><\/h2>\n\n\n\n<p>Spring Debugger is built with a focus on real-world tasks, helping you uncover what&#8217;s really happening inside your Spring application.&nbsp;<\/p>\n\n\n\n<p>You\u2019ve written the class. You\u2019ve annotated it as a bean. But it\u2019s not doing anything.&nbsp;<\/p>\n\n\n\n<p>Maybe it\u2019s not in the right package. Maybe it\u2019s excluded by a conditional. Maybe it\u2019s overridden in a test.&nbsp;<\/p>\n\n\n\n<p>Spring Debugger exposes the full bean landscape:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"alignright size-full is-resized\"><img decoding=\"async\" loading=\"lazy\" width=\"1474\" height=\"680\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/09\/unnamed-2.png\" alt=\"\" class=\"wp-image-599989\" style=\"aspect-ratio:2.1676470588235293;width:409px;height:auto\"\/><\/figure><\/div>\n\n\n<ul>\n<li>You can see all Spring-managed beans directly in the <em>Project<\/em> view.<\/li>\n\n\n\n<li>Grayed-out entries tell you which ones were scanned but not instantiated.<\/li>\n\n\n\n<li>Using Mockito in tests? All mocked beans are clearly marked in orange.<\/li>\n<\/ul>\n\n\n\n<p>And it goes deeper.&nbsp;<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" width=\"2580\" height=\"1922\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/06\/5_1.png\" alt=\"\" class=\"wp-image-577489\"\/><\/figure>\n\n\n\n<p>While stepping through the code, you can inspect a bean\u2019s metadata, including the scope, profile, context, and even originating factory method. No more guesswork \u2013 bean definitions are now first-class citizens in your debugging workflow.&nbsp;<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>The property maze<\/strong><\/h2>\n\n\n\n<p>You set a property in <code>application.properties<\/code>, but your app uses a different value. Why?<\/p>\n\n\n\n<p>Spring Boot\u2019s property resolution is layered: file values, profiles, environment variables, system properties, command-line args, post-processors&#8230; It\u2019s a maze. Even professional developers need additional tools to get through.<\/p>\n\n\n\n<p>Spring Debugger flattens the hierarchy:<\/p>\n\n\n\n<ul>\n<li>It shows the effective runtime value inline in <code>.properties<\/code> and <code>.yaml<\/code> files.<\/li>\n\n\n\n<li>It highlights overridden values and source locations.<\/li>\n\n\n\n<li>For environment-based or external values, the evaluator reveals the origin clearly.<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" width=\"1600\" height=\"725\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/09\/unnamed-3.png\" alt=\"\" class=\"wp-image-600002\"\/><\/figure>\n\n\n\n<p>For values from environment variables or external sources, it still shows where they came from in the debugger evaluator. Since you no longer need to trace values back manually, you save time and reduce the number of misconfigurations.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>The missing transaction<\/strong><\/h2>\n\n\n\n<p>You annotated your method with <code>@Transactional<\/code>, but it is not committing. Even worse, you&#8217;re getting a <code>LazyInitializationException<\/code>. What happened?<\/p>\n\n\n\n<p>Spring Debugger helps you understand what\u2019s going on:<\/p>\n\n\n\n<ul>\n<li>It shows inline indicators for methods executing inside active transactions.<\/li>\n\n\n\n<li>It displays full transaction details, including isolation, propagation, and the method that started it all.<\/li>\n\n\n\n<li>A visual hierarchy for nested transactions helps you understand call chains and propagation effects.<\/li>\n\n\n\n<li>For JPA, it shows the L1 cache state and updates it in real time.<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" width=\"1600\" height=\"1073\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/09\/unnamed-4.png\" alt=\"\" class=\"wp-image-600014\"\/><\/figure>\n\n\n\n<p>Now you know whether your method is inside the transaction you expected \u2013 and where it actually began.&nbsp;<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>The database client that configured itself<\/strong><\/h2>\n\n\n\n<p>Your app connects to a database \u2013 but how? From which config? Which JDBC URL is used? In tests, is it using a Testcontainer? Or is it perhaps an in-memory database like H2?<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"alignright size-full is-resized\"><img decoding=\"async\" loading=\"lazy\" width=\"1008\" height=\"1434\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/09\/unnamed-5.png\" alt=\"\" class=\"wp-image-600026\" style=\"aspect-ratio:0.702928870292887;width:310px;height:auto\"\/><\/figure><\/div>\n\n\n<p>Spring Debugger makes all of this explicit:<\/p>\n\n\n\n<ul>\n<li>It detects all active <code>DataSource<\/code> connections automatically.<\/li>\n\n\n\n<li>It groups them under their corresponding run\/debug configurations.<\/li>\n\n\n\n<li>It integrates with IntelliJ IDEA\u2019s <em>Database <\/em>tool window for inspection.<\/li>\n<\/ul>\n\n\n\n<p>No need to manually register database connections or dig through logs. You can see every live DataSource and explore it interactively.<\/p>\n\n\n\n<p>? In-memory databases are currently shown, but browsing data is not supported.<\/p>\n\n\n\n<p>Learn more about using Spring Debugger with Test\u0441ontainers in this <a href=\"https:\/\/blog.jetbrains.com\/idea\/2025\/07\/spring-debugger-working-with-dynamic-database-connections-just-got-simpler\/\">blog post<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Reading beans from thin air<\/strong><\/h2>\n\n\n\n<p>The debugger is paused. You want to trigger a service, add test data, or inspect a Spring bean. Can you do this the normal way? No.<\/p>\n\n\n\n<p>Spring Debugger changes that by letting you:<\/p>\n\n\n\n<ul>\n<li>Auto-complete all loaded beans in the expression evaluator.<\/li>\n\n\n\n<li>Invoke any method on any bean on the fly.<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" width=\"1600\" height=\"542\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/09\/unnamed-6.png\" alt=\"\" class=\"wp-image-600038\"\/><\/figure>\n\n\n\n<p>The process of bean evaluation is getting better: We can evaluate any configuration property value right in the debugger. All we need to do is select the evaluator on the right side.&nbsp;<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" width=\"1600\" height=\"382\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/09\/unnamed-7.png\" alt=\"\" class=\"wp-image-600050\"\/><\/figure>\n\n\n\n<p>It\u2019s like a REPL for your Spring context. You can poke, prod, simulate, and confirm behavior without restarting the app or adding test code.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>For curious developers: How it works internally&nbsp;<\/strong><\/h2>\n\n\n\n<p>Spring Debugger doesn\u2019t require Spring Boot Actuator or any additional runtime agent. All data is analyzed locally without any network calls, data sharing, or risks of leakage, ensuring full privacy. Under the hood, the plugin uses non-suspending <a href=\"https:\/\/www.jetbrains.com\/help\/idea\/using-breakpoints.html#suspend_policy\" target=\"_blank\" rel=\"noopener\">breakpoints<\/a> set inside the Spring Boot framework libraries. During application startup, after the context is loaded, Spring Debugger gathers information from the debug session, memory heap, and stack trace. This lets it access \u201craw\u201d internal application data without relying on external libraries.<\/p>\n\n\n\n<p>Thanks to the IntelliJ IDEA Debugger API, we were able to invoke required methods from Spring Boot libraries, build an application runtime model, and display it in the IDE.<\/p>\n\n\n\n<p>The Spring Debugger project also led to an extension of the debugger\u2019s evaluator API, allowing us to add property evaluators alongside the standard Java one. In the future, we may extend this further to evaluate not just properties but also SpEL, SQL, or similar expressions.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Summary<\/strong><\/h2>\n\n\n\n<p>Spring Boot is powerful, but its abstractions can be hard to debug. Spring Debugger turns IntelliJ IDEA into a lens that sees through those layers. It\u2019s designed to keep you productive, improve code quality, and clarify real-world problems, all while offering ultimate comfort in your daily workflow.<\/p>\n\n\n\n<ul>\n<li>Beans, configs, and contexts \u2013 visually decoded.<\/li>\n\n\n\n<li>Transactions \u2013 made traceable.<\/li>\n\n\n\n<li>Properties \u2013 unmasked and source-mapped.<\/li>\n\n\n\n<li>Databases \u2013 auto-detected and accessible.<\/li>\n\n\n\n<li>Evaluator \u2013 context-aware and interactive.<\/li>\n<\/ul>\n\n\n\n<p>The debugger doesn\u2019t undermine the \u201cmagic\u201d of the Spring. It lets you understand and control it. Simply run your app in debug mode and see what\u2019s really happening.<\/p>\n\n\n\n<p>Try it now! <a href=\"https:\/\/plugins.jetbrains.com\/plugin\/25302-spring-debugger\" target=\"_blank\" rel=\"noopener\">Install Spring Debugger<\/a> and make Spring internals visible. <a href=\"https:\/\/www.jetbrains.com\/help\/idea\/spring-debugger.html\" target=\"_blank\" rel=\"noopener\">Documentation<\/a> is available to help you get started.&nbsp;<\/p>\n\n\n\n<p>We value your feedback!&nbsp; Feel free to share your thoughts via plugin reviews or in the comments.&nbsp;<\/p>\n\n\n\n<p>Happy coding!<\/p>\n","protected":false},"author":1511,"featured_media":577508,"comment_status":"closed","ping_status":"closed","template":"","categories":[2347],"tags":[632,40,3211,8826],"cross-post-tag":[],"acf":[],"_links":{"self":[{"href":"https:\/\/blog.jetbrains.com\/en\/wp-json\/wp\/v2\/idea\/577488"}],"collection":[{"href":"https:\/\/blog.jetbrains.com\/en\/wp-json\/wp\/v2\/idea"}],"about":[{"href":"https:\/\/blog.jetbrains.com\/en\/wp-json\/wp\/v2\/types\/idea"}],"author":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/en\/wp-json\/wp\/v2\/users\/1511"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/en\/wp-json\/wp\/v2\/comments?post=577488"}],"version-history":[{"count":9,"href":"https:\/\/blog.jetbrains.com\/en\/wp-json\/wp\/v2\/idea\/577488\/revisions"}],"predecessor-version":[{"id":600062,"href":"https:\/\/blog.jetbrains.com\/en\/wp-json\/wp\/v2\/idea\/577488\/revisions\/600062"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/en\/wp-json\/wp\/v2\/media\/577508"}],"wp:attachment":[{"href":"https:\/\/blog.jetbrains.com\/en\/wp-json\/wp\/v2\/media?parent=577488"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/en\/wp-json\/wp\/v2\/categories?post=577488"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/en\/wp-json\/wp\/v2\/tags?post=577488"},{"taxonomy":"cross-post-tag","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/en\/wp-json\/wp\/v2\/cross-post-tag?post=577488"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}