Spring Boot独立应用中@Autowired的正确使用方法咨询
Hey Martin, let's work through how to make your Spring dependency injection cleaner and more effective in this standalone desktop-style app. Your current approach with constructor injection is actually on the right track—let's tweak things to avoid that "manual pass-through" feeling and fix the @PostConstruct issue you ran into.
First, Why Your Current Setup Feels Clunky
You're right that manually passing every injected service to your module constructors defeats some of Spring's DI magic. The root issue here is that your modules aren't being managed by Spring—you're instantiating them manually, so Spring can't auto-inject their dependencies for you. Also, the @PostConstruct null issue happens because that annotation only works on beans that Spring creates and manages; if you new up a module yourself, Spring has no way to trigger that lifecycle method.
Solution 1: Let Spring Manage Your Modules (Best Practice)
If your modules are long-lived (or even if you need to restart them), make them Spring beans too. Here's how:
- Mark each module class with
@Component(or@Serviceif it's business-focused):
@Component @Scope("prototype") // Add this if you need a fresh instance each time you restart the module public class YourModule implements Runnable { private final GlobalParamService globalParamService; private final LogEntryService logEntryService; // Constructor injection for the module's own dependencies public YourModule(GlobalParamService globalParamService, LogEntryService logEntryService) { this.globalParamService = globalParamService; this.logEntryService = logEntryService; } @Override public void run() { // Module logic here } // Use @PostConstruct safely now—Spring will call it after injecting dependencies @PostConstruct private void initModule() { // Initialization logic here } }
- Inject these modules directly into your main
MDHIS_Serviceclass instead of instantiating them manually:
@Component public class MDHIS_Service extends JFrame { private final GlobalParamService globalParamService; private final LogEntryService logEntryService; private final ApplicationContext ctx; private YourModule currentModule; // Constructor injection for main class dependencies @Autowired public MDHIS_Service(GlobalParamService globalParamService, LogEntryService logentryService, ApplicationContext ctx) { this.globalParamService = globalParamService; this.logEntryService = logentryService; this.ctx = ctx; initInitialModule(); } private void initInitialModule() { // Get a fresh module instance from Spring currentModule = ctx.getBean(YourModule.class); new Thread(currentModule).start(); } // Button click handler for restarting the module public void restartModule() { // Stop existing thread first (add logic for this) currentModule = ctx.getBean(YourModule.class); new Thread(currentModule).start(); } }
This way, Spring handles all dependency injection for your modules—no more manual parameter passing! The @Scope("prototype") ensures you get a fresh instance every time you call getBean(), which is perfect for restarting modules.
Solution 2: Simplify Manual Injection (If Modules Can't Be Spring Beans)
If you absolutely need to instantiate modules manually (e.g., dynamic thread creation per restart), you can still clean up your code:
- Use Lombok's
@RequiredArgsConstructoron yourMDHIS_Serviceclass to eliminate the boilerplate constructor code. This auto-generates a constructor for allfinalfields:
@Component @RequiredArgsConstructor public class MDHIS_Service extends JFrame { private final GlobalParamService globalParamService; private final LogEntryService logEntryService; // ... all your other final service fields ... // No need to write the huge constructor—Lombok does it for you! // Button click handler for restarting the module public void restartModule() { // When you need to create a new module instance, just pass the injected services YourModule newModule = new YourModule(globalParamService, logEntryService); new Thread(newModule).start(); } }
- This keeps your main class clean, and since your services are injected via constructor (and marked
final), you know they'll never be null when you use them to instantiate modules.
Why @PostConstruct Was Giving You Nulls
When you tried using @PostConstruct on your manually created modules, Spring had no idea those objects existed—so it never called the @PostConstruct method. That's why your services were null. If you switch to Solution 1 (Spring-managed modules), you can safely use @PostConstruct in your modules to run initialization logic after Spring injects their dependencies.
Quick Note on Your Main Method
Your current main method setup is perfectly fine—you're correctly bootstrapping Spring and retrieving your main frame bean from the context. Just make sure MDHIS_Service is marked with @Component so Spring picks it up.
内容的提问来源于stack exchange,提问作者Martin

