首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Spring Java Config 全攻略:@Configuration、@Bean、組件掃描與 Web 整合

     編輯:Java 相關知識

為什麼選擇 Java Config?

  • 類型安全:編譯期檢查 Bean 依賴,重構時 IDE 自動重命名
  • IDE 友好:跳轉到定義、查找引用、代碼補全全支援
  • 重構安全:重命名方法/類自動同步,不像 XML 字符串易出錯
  • 邏輯復用:配置類即 Java 類,可繼承、組合、條件化
  • 零 XML:純代碼定義,版本控制 diff 更清晰

核心註解:@Configuration 與 @Bean

最簡配置類

@Configuration
public class AppConfig {
    
    @Bean
    public MyService myService() {
        return new MyServiceImpl();
    }
    
    @Bean
    public DataSource dataSource() {
        HikariDataSource ds = new HikariDataSource();
        ds.setJdbcUrl("jdbc:mysql://localhost:3306/mydb");
        ds.setUsername("root");
        ds.setPassword("secret");
        return ds;
    }
}

等價 XML 對比

<beans>
    <bean id="myService" class="com.example.MyServiceImpl"/>
    <bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource">
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/mydb"/>
        <property name="username" value="root"/>
        <property name="password" value="secret"/>
    </bean>
</beans>

依賴注入:Bean 方法互調

@Configuration
public class AppConfig {
    
    @Bean
    public DataSource dataSource() { ... }
    
    @Bean
    public JdbcTemplate jdbcTemplate() {
        // 直接調用同配置類的 @Bean 方法
        // Spring 會攔截調用,返回單例 Bean (而非新建對象)
        return new JdbcTemplate(dataSource());
    }
    
    @Bean
    public UserRepository userRepository() {
        return new JdbcUserRepository(jdbcTemplate());
    }
}

關鍵機制:@Configuration 類被 CGLIB 代理,@Bean 方法調用會先檢查容器中是否已有實例,保證單例語義。

組件掃描:@ComponentScan

@Configuration
@ComponentScan(
    basePackages = "com.example.service, com.example.dao",
    basePackageClasses = {ServiceMarker.class, DaoMarker.class}, // 類型安全指定包
    includeFilters = @Filter(type = FilterType.ANNOTATION, classes = {Service.class, Repository.class}),
    excludeFilters = @Filter(type = FilterType.REGEX, pattern = ".*\\.test\\..*")
)
public class AppConfig { }

掃描策略最佳實踐

  • 分層掃描:Web 層掃描 @Controller、Service 層掃描 @Service/@Repository
  • 標記接口/類:創建空接口 ServiceLayer、DaoLayer 作為 basePackageClasses,重構時自動追踪包變化
  • 排除測試/配置類:防止測試代碼污染生產上下文

容器啟動:AnnotationConfigApplicationContext

獨立應用啟動

public class Main {
    public static void main(String[] args) {
        // 1. 接受配置類
        ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
        
        // 2. 接受包路徑 (自動掃描 @Configuration)
        // ApplicationContext ctx = new AnnotationConfigApplicationContext("com.example.config");
        
        // 3. 程序化註冊
        // AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
        // ctx.register(AppConfig.class, OtherConfig.class);
        // ctx.refresh();
        
        MyService service = ctx.getBean(MyService.class);
        service.doBusiness();
        
        // 關閉容器觸發 @PreDestroy
        ((ConfigurableApplicationContext) ctx).close();
    }
}

Web 應用整合 (Servlet 3.0+ 無 web.xml)

1. 根上下文配置 (Service/DAO/數據源)

public class RootConfig implements WebApplicationInitializer {
    @Override
    public void onStartup(ServletContext servletContext) {
        // 創建根上下文
        AnnotationConfigWebApplicationContext rootCtx = 
            new AnnotationConfigWebApplicationContext();
        rootCtx.register(RootConfig.class); // 或 scan("com.example.service")
        
        // 註冊 ContextLoaderListener
        servletContext.addListener(new ContextLoaderListener(rootCtx));
    }
}

2. DispatcherServlet 配置 (Web MVC)

public class WebConfig implements WebApplicationInitializer {
    @Override
    public void onStartup(ServletContext servletContext) {
        // 創建 Servlet 上下文
        AnnotationConfigWebApplicationContext servletCtx = 
            new AnnotationConfigWebApplicationContext();
        servletCtx.register(WebMvcConfig.class);
        
        // 註冊 DispatcherServlet
        ServletRegistration.Dynamic dispatcher = 
            servletContext.addServlet("dispatcher", new DispatcherServlet(servletCtx));
        dispatcher.setLoadOnStartup(1);
        dispatcher.addMapping("/api/*"); // 或 "/"
        
        // 可選:設置初始化參數
        dispatcher.setInitParameter("contextClass", 
            AnnotationConfigWebApplicationContext.class.getName());
        dispatcher.setInitParameter("contextConfigLocation", "com.example.web.WebMvcConfig");
    }
}

3. 合併式寫法 (單類實現 WebApplicationInitializer)

public class AppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
    // 根配置類
    @Override
    protected Class[] getRootConfigClasses() {
        return new Class[]{RootConfig.class, SecurityConfig.class};
    }
    
    // Servlet 配置類
    @Override
    protected Class[] getServletConfigClasses() {
        return new Class[]{WebMvcConfig.class};
    }
    
    // 映射路徑
    @Override
    protected String[] getServletMappings() {
        return new String[]{"/api/*"};
    }
    
    // 自定義 DispatcherServlet (可選)
    @Override
    protected FrameworkServlet createDispatcherServlet(WebApplicationContext servletAppContext) {
        return new DispatcherServlet(servletAppContext);
    }
}

進階特性

1. @Profile 環境隔離

@Configuration
@Profile("dev")
public class DevDataSourceConfig {
    @Bean
    public DataSource dataSource() { return new EmbeddedDatabaseBuilder().build(); }
}

@Configuration
@Profile("prod")
public class ProdDataSourceConfig {
    @Bean
    public DataSource dataSource() { return new HikariDataSource(...); }
}

// 啟動時指定: -Dspring.profiles.active=prod
// 或 Web: context-param spring.profiles.active=prod

2. @PropertySource 外部化配置

@Configuration
@PropertySource("classpath:jdbc.properties")
@PropertySource(value = "file:${user.home}/app-secret.properties", ignoreResourceNotFound = true)
public class DataSourceConfig {
    @Autowired Environment env;
    
    @Bean
    public DataSource dataSource() {
        HikariDataSource ds = new HikariDataSource();
        ds.setJdbcUrl(env.getRequiredProperty("jdbc.url"));
        ds.setUsername(env.getRequiredProperty("jdbc.username"));
        ds.setPassword(env.getRequiredProperty("jdbc.password"));
        return ds;
    }
}

3. @Import 組合配置

@Configuration
@Import({DataSourceConfig.class, RedisConfig.class, SecurityConfig.class})
public class RootConfig { }

// 或動態導入
@Configuration
@Import(MyImportSelector.class) // 實現 selectImports 返回類名數組
public class DynamicConfig { }

遷移 XML 到 Java Config 清單

XML 元素Java Config 對應
<bean id="x" class="X"/>@Bean public X x() { return new X(); }
<property name="a" ref="b"/>x().setA(b()) 或構造器注入 new X(b())
<constructor-arg ref="b"/>new X(b())
<context:component-scan/>@ComponentScan
<context:property-placeholder/>@PropertySource + Environment
<import resource="..."/>@Import(Config.class)
<aop:config/>@EnableAspectJAutoProxy + @Aspect 類
<tx:annotation-driven/>@EnableTransactionManagement
<mvc:annotation-driven/>@EnableWebMvc (WebMvcConfigurer)
<task:annotation-driven/>@EnableScheduling + @EnableAsync

總結

Java Config 是 Spring 現代化的基石。掌握 @Configuration + @Bean + @ComponentScan + @Enable* 組合,即可構建類型安全、易重構、零 XML 的企業級應用。遷移建議:新項目全 Java Config,舊項目增量遷移 (新功能用 Java Config,舊 XML 共存),Spring 完美支援混合模式。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved