基於 Spring 3.2+ 版本,系統講解 IOC 容器的四大核心能力:多類型屬性注入、註解驅動組件掃描、Bean 作用域與生命周期控制、以及向註解配置遷移的最佳實踐。
<bean id="messageBean" class="com.example.MessageBean">
<property name="moduleName" value="測試基本屬性注入"/>
<property name="pageSize" value="5"/>
<property name="username" value="#{jdbcProperties.username}"/> <!-- SpEL 表達式 -->
<property name="password"><null/></property> <!-- 顯式注入 null -->
</bean>
<property name="someList">
<list><value>北京</value><value>上海</value><value>廣州</value></list>
</property>
<property name="someSet">
<set><value>James Gosling</value><value>Martin Fowler</value></set>
</property>
<property name="someMap">
<map>
<entry key="1001" value="Java基礎"/>
<entry key="1002" value="Java Web"/>
</map>
</property>
<property name="someProps">
<props>
<prop key="username">root</prop>
<prop key="password">1234</prop>
</props>
</property>
<util:list id="commonList"><value>A</value><value>B</value></util:list>
<util:set id="commonSet"><value>X</value></util:set>
<util:map id="commonMap"><entry key="k1" value="v1"/></util:map>
<util:properties id="commonProps"><prop key="k1">v1</prop></util:properties>
<bean id="anotherBean" class="com.example.MessageBean">
<property name="someList" ref="commonList"/>
<property name="someSet" ref="commonSet"/>
<property name="someMap" ref="commonMap"/>
<property name="someProps" ref="commonProps"/>
</bean>
<util:properties id="jdbcProperties" location="classpath:db.properties"/>
<property name="username" value="#{jdbcProperties.username}"/>
<context:component-scan base-package="com.example"/>
| 註解 | 語義層級 | 掃描優先級 |
|---|---|---|
@Component | 通用組件 | 基礎 |
@Repository | 持久層(DAO) | 高(自動異常轉換) |
@Service | 業務層 | 高(事務邊界標識) |
@Controller | 控制層 | 高(Spring MVC 識別) |
@Component("exampleBean") // 默認 bean 名為 exampleBean
public class ExampleBean {
public ExampleBean() { System.out.println("實例化 ExampleBean"); }
public void execute() { System.out.println("執行業務邏輯"); }
}
@Component
@Scope("prototype") // 或 singleton(默認)、request、session、application
public class PrototypeBean { ... }
驗證:
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
PrototypeBean b1 = ctx.getBean(PrototypeBean.class);
PrototypeBean b2 = ctx.getBean(PrototypeBean.class);
System.out.println(b1 == b2); // prototype: false | singleton: true
@Component
@Scope("singleton")
public class LifecycleBean {
@PostConstruct
public void init() { System.out.println("初始化回調:資源獲取、連接池預熱"); }
@PreDestroy
public void destroy() { System.out.println("銷毀回調:資源釋放、連接關閉"); }
}
容器關閉觸發銷毀:
AbstractApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
// ... 業務邏輯
ctx.close(); // 必須調用 close() 觸發 @PreDestroy,Web 環境由 ContextLoaderListener 自動管理
@Configuration
@ComponentScan("com.example")
@PropertySource("classpath:db.properties")
public class AppConfig {
@Bean
public DataSource dataSource(@Value("${jdbc.url}") String url,
@Value("${jdbc.user}") String user,
@Value("${jdbc.password}") String pwd) {
HikariDataSource ds = new HikariDataSource();
ds.setJdbcUrl(url); ds.setUsername(user); ds.setPassword(pwd);
return ds;
}
}
// 替換 ClassPathXmlApplicationContext
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
@ComponentScan 基礎包配置正確,無遺漏子包util: 命名空間,避免內聯定義重複@Lookup 或 ObjectFactory 避免單例污染ctx.close() 觸發銷毀回調#{...} 僅用於動態計算,靜態值直用 valueSpring IOC 的精髓在於聲明式配置與運行時元數據驅動。掌握全類型注入、組件掃描語義、作用域與生命周期控制,是從「會用 Spring」進階到「精通容器原理」的分水嶺。