Spring 以 IoC(控制反轉)與 AOP 為核心,本文系統講解基於 XML 與註解的 Bean 裝配、三種實例化方式、作用域、生命周期回調、後置處理器、四種依賴注入方式、集合注入、SpEL 表達式、註解掃描與混合配置最佳實踐。
<dependencies>
<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.3.x</version></dependency>
<dependency><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId><version>1.2</version></dependency>
<dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13</version></dependency>
</dependencies>
<!-- 構造器(默認無參) -->
<bean id="constructBean" class="com.example.ConstructBean"/>
<!-- 靜態工廠方法 -->
<bean id="staticBean" class="com.example.StaticBeanFactory" factory-method="getInstance"/>
<!-- 實例工廠方法 -->
<bean id="beanFactory" class="com.example.InstanceBeanFactory"/>
<bean id="instanceBean" factory-bean="beanFactory" factory-method="getInstance"/>
| scope | 說明 |
|---|---|
| singleton | 容器單例(默認) |
| prototype | 每次 getBean 創建新實例 |
| request/session/globalSession | Web 環境下按請求/會話/全局會話 |
<bean id="protoBean" class="com.example.ProtoBean" scope="prototype"/>
public class LifecycleBean {
public void setUp() { System.out.println("SetUp..."); }
public void tearDown() { System.out.println("TearDown..."); }
}
<bean id="lifeBean" class="com.example.LifecycleBean" init-method="setUp" destroy-method="tearDown"/>
測試關鍵:需使用 ClassPathXmlApplicationContext 並調用 close() 觸發銷毀。
public class PrintBeanProcessor implements BeanPostProcessor {
@Override public Object postProcessBeforeInitialization(Object bean, String name) {
if ("lifeBean".equals(name)) System.out.println("Before init: " + name);
return bean;
}
@Override public Object postProcessAfterInitialization(Object bean, String name) {
System.out.println("After init: " + name);
return bean;
}
}
<bean class="com.example.PrintBeanProcessor"/> <!-- 無需 id -->
應用:AOP 自動代理、Bean 驗證、動態賦值。
| 方式 | XML 示例 | 適用場景 |
|---|---|---|
| 構造器注入 | <constructor-arg index="0" value="foo"/> | 強制依賴、不可變對象 |
| Setter 注入 | <property name="name" value="foo"/> | 可選依賴、JavaBean 慣例 |
| p 命名空間 | <bean p:name="foo" p:age-ref="ageBean"/> | 簡化 Setter 注入(Spring 2.5+) |
| SpEL 表達式 | <property name="name" value="#{car.owner}"/> | 引用 Bean/屬性/方法/運算 |
<property name="list">
<list><value>a</value><value>b</value></list>
</property>
<property name="set">
<set><value>1</value><value>2</value></set>
</property>
<property name="map">
<map><entry key="k1" value="v1"/></map>
</property>
<property name="props">
<props><prop key="k1">v1</prop></props>
</property>
<context:component-scan base-package="com.example"/>
等價於 <context:annotation-config/> + 自動掃描 @Component 衍生註解:
| 註解 | 語義層 |
|---|---|
| @Controller | Web 控制層 |
| @Service | 業務服務層 |
| @Repository | 數據訪問層 |
| @Component | 通用組件 |
@Component
@Scope("prototype")
public class ProtoBean {
@PostConstruct public void init() { ... }
@PreDestroy public void destroy() { ... }
}
| 註解 | 特性 |
|---|---|
| @Value | 基本值/SpEL:@Value("#{car.price * 1.1}") |
| @Autowired | 按類型自動裝配,配合 @Qualifier 指定 Bean 名 |
| @Resource | JSR-250,按名稱裝配(name 屬性),次按類型 |
<context:component-scan> 即可激活註解處理器。| 容器 | 特點 |
|---|---|
| BeanFactory | 核心工廠接口,延遲初始化(getBean 時創建)。 |
| ApplicationContext | BeanFactory 子接口,啟動時預實例化單例,支援國際化、事件發布、多環境 Profile、Web 整合。 |
實際開發中統一使用 ApplicationContext(ClassPathXmlApplicationContext / AnnotationConfigApplicationContext)。