@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;
}
}
<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>
@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 方法調用會先檢查容器中是否已有實例,保證單例語義。
@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 { }
ServiceLayer、DaoLayer 作為 basePackageClasses,重構時自動追踪包變化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();
}
}
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));
}
}
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");
}
}
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);
}
}
@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
@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;
}
}
@Configuration
@Import({DataSourceConfig.class, RedisConfig.class, SecurityConfig.class})
public class RootConfig { }
// 或動態導入
@Configuration
@Import(MyImportSelector.class) // 實現 selectImports 返回類名數組
public class DynamicConfig { }
| 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 完美支援混合模式。