通常你可以在 xml 配置文件中,聲明一個 bean 或者 component ,然后 Spring 容器會檢查和注冊你的 bean 或 component 。
實際上,Spring 支持自動掃描 bean 或 component ,你可以不必再在 xml 文件中繁瑣的聲明 bean ,Spring 會自動掃描、檢查你指定包的 bean 或 component 。

1.修改 pom.xml 文件,添加 Spring 的部署
<!-- springAuto --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>4.2.0.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.2.0.RELEASE</version> </dependency>
2.手動配置 component
先看一下正常手動配置一個 bean 。 DAO 層,創建 CustomerDao.java
package com.shiyanlou.spring.dao; public class CustomerDao { @Override public String toString() { return "Hello,this is CustomerDao"; } }
Service層,創建 CustomerService.java
package com.shiyanlou.spring.service; import com.shiyanlou.spring.dao.CustomerDao; public class CustomerService { CustomerDao customerDao; public CustomerDao getCustomerDao() { return customerDao; } public void setCustomerDao(CustomerDao customerDao) { this.customerDao = customerDao; } @Override public String toString() { return "CustomerService [customerDao=" + customerDao + "]"; } }
3.創建並配置 SpringCustomer.xml 文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"> <bean id="customerService" class="com.shiyanlou.spring.service.CustomerService"> <property name="customerDao" ref="customerDao" /> </bean> <bean id="customerDao" class="com.shiyanlou.spring.dao.CustomerDao" /> </beans>
4.創建 App.java 文件
package com.shiyanlou.spring.SpringAuto; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.shiyanlou.spring.service.CustomerService; public class App { public static void main( String[] args ) { ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"SpringCustomer.xml"}); CustomerService cust = (CustomerService) context.getBean("customerService"); System.out.println(cust); } }
實驗結果:

2 自動掃描組件
用注釋 @Component 來表示這個 Class 是一個自動掃描組件。
Customer.java類
package com.shiyanlou.spring.dao; import org.springframework.stereotype.Component; @Component public class CustomerDao { @Override public String toString() { return "Hello,this is CustomerDao"; } }
CustomerService.java類
package com.shiyanlou.spring.service; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import com.shiyanlou.spring.dao.CustomerDao; @Component public class CustomerService { @Autowired CustomerDao customerDao; public CustomerDao getCustomerDao() { return customerDao; } public void setCustomerDao(CustomerDao customerDao) { this.customerDao = customerDao; } @Override public String toString() { return "CustomerService [customerDao=" + customerDao + "]"; } }
3.SpringApplication.xml文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <context:component-scan base-package="com.shiyanlou.spring" /> </beans> <!-- 注意:以上 xml 文件中,加入了 context:component-scan 標簽, 中也加入了標簽, 這樣就將 Spring 的自動掃描特性引入, base-package 表示組件的存放位置, Spring 將掃描對應文件夾下的 bean(用 @Component 注釋過的),將這些 bean 注冊到容器中。 -->
4.App.java與手動時一致(略)
實驗結果:
與手動配置時一致
3 自定義掃描組件名稱
上例中,默認情況下,Spring 將把組件 Class 的第一個字母變成小寫,來作為自動掃描組件的名稱,例如將 CustomerService 轉變為 customerservice ,你可以用 customerService 這個名字調用組件,如下:
CustomerService cust = (CustomerService)context.getBean("customerService");
也可以像下面這樣,創建自定義的組件名稱:
@Service("AAA")
public class CustomerService
...
可以調用自己定義的組件了,如下:
CustomerService cust = (CustomerService)context.getBean("AAA");
4 自動掃描組件的注釋類型
有 4 種注釋類型,分別是:
- @Component ——表示一個自動掃描 component
- @Repository ——表示持久化層的 DAO component
- @Service ——表示業務邏輯層的 Service component
- @Controller ——表示表示層的 Controller component
在項目中,我們可以將所有自動掃描組件都用 @Component 注釋,Spring 將會掃描所有用 @Component 注釋過得組件。 實際上,@Repository 、 @Service 、 @Controller 三種注釋是為了加強代碼的閱讀性而創造的,可以在不同的應用層中,用不同的注釋,我們可以在上一個項目的基礎上改一下注釋,如下
DAO 層:
package com.shiyanlou.spring.dao; import org.springframework.stereotype.Repository; @Repository public class CustomerDAO { @Override public String toString() { return "Hello , This is CustomerDAO"; } }
Service 層:
package com.shiyanlou.spring.services; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.shiyanlou.spring.dao.CustomerDAO; @Service public class CustomerService { @Autowired CustomerDAO customerDAO; @Override public String toString() { return "CustomerService [customerDAO=" + customerDAO + "]"; } }
5 自動掃描中過濾組件
1 Filter Component - include
下例演示了用“ filter ”自動掃描注冊組件,這些組件只要匹配定義的“ regex ”的命名規則,Class 前就不需要用 @Component 進行注釋。 DAO 層,CustomerDAO.java 如下:
package com.shiyanlou.spring.dao; public class CustomerDAO { @Override public String toString() { return "Hello , This is CustomerDAO"; } }
Service 層,CustomerService.java如下:
package com.shiyanlou.spring.services; import org.springframework.beans.factory.annotation.Autowired; import com.shiyanlou.spring.dao.CustomerDAO; public class CustomerService { @Autowired CustomerDAO customerDAO; @Override public String toString() { return "CustomerService [customerDAO=" + customerDAO + "]"; } }
SpringFiltering.xml 配置如下:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <context:component-scan base-package="com.shiyanlou.spring" > <context:include-filter type="regex" expression="com.shiyanlou.spring.dao.*DAO.*" /> <context:include-filter type="regex" expression="com.shiyanlou.spring.services.*Service.*" /> </context:component-scan> </beans>
以上 xml 文件中,所有文件名字,只要包含 DAO 和 Service( DAO.,Service. )關鍵字的,都將被檢查注冊到 Spring 容器中
創建App.java並運行如下:
package com.shiyanlou.spring.common; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.lei.customer.services.CustomerService; public class App { public static void main( String[] args ) { ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"Spring-AutoScan.xml"}); CustomerService cust = (CustomerService)context.getBean("customerService"); System.out.println(cust); } }
運行結果與之前相同。
2 Filter Component——exclude
也可以用 exclude ,制定組件避免被 Spring 發現並被注冊到容器中。以下配置排除用 @Service 注釋過的組件:
<context:component-scan base-package="com.shiyanlou.spring" > <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service" /> </context:component-scan>
以下配置排除包含 DAO 關鍵字的組件:
<context:component-scan base-package="com.lei" > <context:exclude-filter type="regex" expression="com.shiyanlou.spring.dao.*DAO.*" /> </context:component-scan>
三、 自動裝配 Bean
所謂自動裝配,就是將一個 Bean 注入到其他 Bean 的 Property 中,類似於以下:
<bean id="customer" class="com.lei.common.Customer" autowire="byName" />
Spring 支持 5 種自動裝配模式,如下:
- no —— 默認情況下,不自動裝配,通過
refattribute手動設定。 - buName —— 根據 Property 的 Name 自動裝配,如果一個 bean 的 name ,和另一個 bean 中的 Property 的 name 相同,則自動裝配這個 bean 到 Property 中。
- byType —— 根據 Property 的數據類型( Type )自動裝配,如果一個 bean 的數據類型,兼容另一個 bean 中 Property 的數據類型,則自動裝配。
- constructor —— 根據構造函數參數的數據類型,進行 byType 模式的自動裝配。
- autodetect —— 如果發現默認的構造函數,用 constructor 模式,否則,用 byType 模式。
下例中演示自動裝配,Customer.java 如下:
package com.shiyanlou.spring.autowire.common; public class Customer { private Person person; public Customer(Person person) { this.person = person; } public void setPerson(Person person) { this.person = person; } //... }
Person.java 如下
package com.shiyanlou.spring.autowire.common; public class Person { //... }
1 Auto-Wiring no
默認情況下,需要通過 ref 來裝配 bean ,如下:
<bean id="customer" class="com.shiyanlou.spring.autowire.common.Customer"> <property name="person" ref="person" /> </bean> <bean id="person" class="com.shiyanlou.spring.autowire.common.Person" />
Auto-Wiring byName
根據屬性 Property 的名字裝配 bean ,這種情況,Customer 設置了 autowire="byName" ,Spring 會自動尋找與屬性名字 person 相同的 bean ,找到后,通過調用 setPerson(Person person) 將其注入屬性。
<bean id="customer" class="com.shiyanlou.spring.autowire.common.Customer" autowire="byName" /> <bean id="person" class="com.shiyanlou.spring.autowire.common.Person" />
如果根據 Property name 找不到對應的 bean 配置,如下
<bean id="customer" class="com.shiyanlou.spring.autowire.common.Customer" autowire="byName" /> <bean id="person_another" class="com.shiyanlou.spring.autowire.common.Person" />
Customer 中 Property 名字是 person ,但是配置文件中找不到 person ,只有 person_another ,這時就會裝配失敗,運行后,Customer 中 person=null 。
3 Auto-Wiring byType
根據屬性 Property 的數據類型自動裝配,這種情況,Customer 設置了 autowire="byType" ,Spring 會自動尋找與屬性類型相同的 bean ,找到后,通過調用 setPerson(Person person) 將其注入。
<bean id="customer" class="com.shiyanlou.spring.autowire.common.Customer" autowire="byType" /> <bean id="person" class="com.shiyanlou.spring.autowire.common.Person" />
如果配置文件中有兩個類型相同的 bean 會怎樣呢?如下:
<bean id="customer" class="com.shiyanlou.spring.autowire.common.Customer" autowire="byType" /> <bean id="person" class="com.shiyanlou.spring.autowire.common.Person" /> <bean id="person_another" class="com.shiyanlou.spring.autowire.common.Person" />
一旦配置如上,有兩種相同數據類型的 bean 被配置,將拋出 UnsatisfiedDependencyException 異常,見以下: Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: 所以,一旦選擇了 byType 類型的自動裝配,請確認你的配置文件中每個數據類型定義一個唯一的 bean 。
4 Auto-Wiring constructor
這種情況下,Spring 會尋找與參數數據類型相同的 bean ,通過構造函數 public Customer(Person person) 將其注入。
<bean id="customer" class="com.shiyanlou.spring.autowire.common.Customer" autowire="constructor" /> <bean id="person" class="com.shiyanlou.spring.autowire.common.Person" />
注意:項目中 autowire 結合 dependency-check 一起使用是一種很好的方法,這樣能夠確保屬性總是可以成功注入。如下:
<bean id="customer" class="com.shiyanlou.spring.autowire.common.Customer" autowire="autodetect" dependency-check="objects" /> <bean id="person" class="com.shiyanlou.spring.autowire.common.Person" />
