實例12:引用外部屬性文件
舉例應用場景:對於數據庫連接池,只需要創建一個連接池即可,從中獲取連接對象。因此可以用IOC容器進行配置組件。
>數據庫連接池的配置文件(dbconfig.properties)
jdbc.username=root
jdbc.password=root
jdbc.jdbcUrl=jdbc:mysql://localhost:3306/customersdb
jdbc.driverClass=com.mysql.jdbc.Driver
>在IOC容器中引入Context名稱空間
>通過 <context:property-placeholder/> 引入配置文件,其中classpath:固定用法表示引用類路徑下的配置文件
<context:property-placeholder location="classpath:dbconfig.properties"/>
>通過 ${ } 來動態獲取配置文件中的value值,並且需要注意的是,爲了防止username和Spring中自帶的username發生衝突,因此在配置
文件中應該在所有key值前加前綴,來避免衝突
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="user" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
<property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
<property name="driverClass" value="${jdbc.driverClass}"></property>
</bean>
>最後在類文件中獲取IOC容器,並在方法中通過getBean方法獲取數據連接池對象,並調用其方法獲得連接對象
public class IOCTest {
ConfigurableApplicationContext ioc = new ClassPathXmlApplicationContext("applicationContext02.xml");
@Test
public void test02() throws SQLException {
// DataSource bean = (DataSource)ioc.getBean("dataSource");
//按照類型獲取組件,可以獲取到這個類型下的所有實現類子類等
DataSource bean = ioc.getBean(DataSource.class);
System.out.println(bean.getConnection());
}
}
>需要注意的是,剛纔在編碼過程中,出現了java.lang.NoClassDefFoundError: com/mchange/v2/ser/Indirector的錯誤,出現錯誤原因是沒有導入mchange-commons-java-0.2.11.jar。
實例13:基於XML的自動裝配
舉例應用場景:自動裝配應用於自定義類型屬性。假如一個類中的屬性爲自定義類,在Bean中配置時,可以通過<property name=" " ref=" IOC容器中的Bean"></property>進行手動裝配。
自動裝配:根據指定的裝配規則,不需要明確指定,就可以讓Spring自動將匹配的屬性值注入Bean中。
裝配模式:①<bean id=" " class=" " autowire="default"></bean>:不自動裝配
②<bean id=" " class=" " autowire="byName"></bean>:根據屬性名稱,在IOC容器中尋找id和該屬性名稱相同的Bean,注入到Bean中
③<bean id=" " class=" " autowire="byType"></bean>:根據屬性類型,在IOC容器中尋找類型相同的Bean,注入到Bean中
④<bean id=" " class=" " autowire="constructor"></bean>:根據構造器中的參數,注入到Bean中。但是當一個Bean中存在多個構造器時就會很複雜,因此不建議使用。
♥大多時候會使用註解方式來實現自動裝配,在XML文檔中進行的自動裝配會顯得不方便,實際項目中更多使用註解的方式實現。
♥當一個類中的屬性時自定義類型的集合時,當自動裝配時,會將所有符合autowire條件的Bean都裝入該集合中。
實例14:SpEL(Spring Expression Language)測試
SpEL的語法符號爲:#{...}
>使用字面量進行賦值
<property name="count" value="#{5*12}"/>
>引用其他Bean的某個屬性值
<bean id="emp05" class="com.parent.bean.Employee">
<property name="empId" value="1003"/>
<property name="empName" value="Kate"/>
<property name="age" value="21"/>
<property name="deptName" value="#{dept.deptName}"/>
</bean>
>引用其他Bean,(不需要ref=""來引用其他Bean)
<bean id="emp04" class="com.parent.bean.Employee">
<property name="empId" value="1003"/>
<property name="empName" value="Kate"/>
<property name="age" value="21"/>
<property name="detp" value="#{dept}"/>
</bean>
>調用靜態方法:#{T(全類名).靜態方法名(參數)}
<bean id="employee" class="com.spel.bean.Employee">
<!-- 在SpEL表達式中調用類的靜態方法 -->
<property name="circle" value="#{T(java.lang.Math).PI*20}"/>
</bean>
>調用非靜態方法:#{對象.方法名}
<!-- 創建一個對象,在SpEL表達式中調用這個對象的方法 -->
<bean id="salaryGenerator" class="com.spel.bean.SalaryGenerator"/>
<bean id="employee" class="com.spel.bean.Employee">
<!-- 通過對象方法的返回值爲屬性賦值 -->
<property name="salayOfYear" value="#{salaryGenerator.getSalaryOfYear(5000)}"/>
</bean>
※實例15:通過註解分別創建Dao、Service、Controller
<!-- 實例15:通過註解分別創建Dao、Service、Controller(控制器:控制網站跳轉邏輯Servlet) -->
<!-- 通過給Bean上添加某些註解,可以快速的將Bean加入到IOC容器中
某個類上添加任何一個註解都能快速的將這個組件加入到IOC容器的管理中
Spring中有四個註解
@Controller:控制器:推薦給控制器層的組件添加該註解(Servlet包下)
@Service
@Rspository:給數據庫層(持久化層,Dao層)的組件添加該註解
@Componet:WebUtils:給不屬於以上基層的組件添加該註解
使用註解將組件快速加入容器中需要以下幾步
1>給要添加的組件上標四個註解中的任一個
2>告訴Spring自動掃描加了註解的組件:依賴context名稱空間
3>一定要導入AOP包,支持加註解模式的
-->
<!-- context:component-scan:自動組件掃描 -->
<context:component-scan base-package="com.cuco"></context:component-scan>
@Controller
public class BookServlet {
}
public class IOCTest {
ApplicationContext ioc = new ClassPathXmlApplicationContext("applicationContext.xml");
/*
* 使用註解加入到容器中的組件,和使用配置加入到容器中的組件行爲默認都是一樣的;
* 1.組件的id,默認就是組件的類名首字母小寫
* 2.組件的作用域,默認都是單例的
* >也可以新寫組件的新名字通過()
* >也可以將組件的作用域改爲多實例,@Scope(value="prototype")
* */
@Test
public void test() {
Object bean = ioc.getBean("bookDao");
Object bean1 = ioc.getBean("bookDao");
System.out.println(bean == bean1);
}
}
實例16:使用context:include-filter指定掃描包時要包含的類
實例17:使用context:include-filter指定掃描包時不包含的類
<!-- context:component-scan:自動組件掃描 -->
<context:component-scan base-package="com.cuco"></context:component-scan>
<!-- 實例17:使用context:include-filter指定掃描包時不包含的類 -->
<context:component-scan base-package="com.cuco">
<!-- 掃描時可以排除一些不要的組件
type="annotation":指定排除規則:按照註解進行排除,標註了指定註解的組件不要
expression="":註解的全類名
type="assignable":指定排除某個具體的類,按照類排除
expression="":類的全類名
-->
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/>
<context:exclude-filter type="assignable" expression="com.cuco.service.BookService"/>
</context:component-scan>
<!-- use-default-filters設置爲false:不掃描所有組件 -->
<context:component-scan base-package="com.cuco" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/>
</context:component-scan>
※實例18:使用@Autowired註解實現根據類型實現自動裝配
/*
* @Autowired:Spring會自動的爲這個屬性賦值;
* 一定會去容器中找到這個屬性對應的組件
* */
@Controller
public class BookServlet {
//自動裝配,自動的爲這個屬性賦值,不需要new一個對象
@Autowired
private BookService bookService;
}
@Autowired註解
[1]根據類型實現自動裝配。
[2]構造器、普通字段(即使是非public)、一切具有參數的方法都可以應用@Autowired註解
[3]默認情況下,所有使用@Autowired註解的屬性都需要被設置。當Spring找不到匹配的bean裝配屬性時,會拋出異常。
[4]若某一屬性允許不被設置,可以設置@Autowired註解的required屬性爲 false
[5]默認情況下,當IOC容器裏存在多個類型兼容的bean時,Spring會嘗試匹配bean的id值是否與變量名相同,如果相同則進行裝配。如果bean的id值不相同,通過類型的自動裝配將無法工作。此時可以在@Qualifier註解裏提供bean的名稱。Spring甚至允許在方法的形參上標註@Qualifiter註解以指定注入bean的名稱。
[6]@Autowired註解也可以應用在數組類型的屬性上,此時Spring將會把所有匹配的bean進行自動裝配。
[7]@Autowired註解也可以應用在集合屬性上,此時Spring讀取該集合的類型信息,然後自動裝配所有與之兼容的bean。
[8]@Autowired註解用在java.util.Map上時,若該Map的鍵值爲String,那麼 Spring將自動裝配與值類型兼容的bean作爲值,並以bean的id值作爲鍵。
※實例19:如果資源類型的bean不止一個,默認根據@Autowired註解標記的成員變量名作爲id查找bean,進行裝配
※實例20:如果根據成員變量名作爲id還是找不到bean, 可以使用@Qualifier註解明確指定目標bean的id
public class BookServlet {
//自動裝配,自動的爲這個屬性賦值,不需要new一個對象
//@Qualifier:指定一個名字作爲該組件的id,讓Spring不要使用變量名作爲id
@Qualifier("bookService")
@Autowired
private BookService bookServiceExt2;
}
※實例21:@Autowired註解的required屬性指定某個屬性允許不被設置:@Autowired(required="false")
總結@Autowired流程:
1>按照所註解的類型去Spring容器中尋找對應的組件:BookService bookService = ioc.getBean(BookService.class)
(1)如果找到一個對應的組件,則賦值給變量bookService;
(2)如果沒找到,則拋出異常
(3)如果找到多個(例如會將bookService所有的子類找出)
①根據變量名作爲id繼續匹配:
如果匹配上,則裝配;匹配不上,則報錯。
如果想要根據變量名作爲id繼續匹配,可以使用@Qualifier("")指定一個新id
@Autowired和@Resource的區別
@Autowired:是Spring自己的註解,相比較來說功能強大一些,但如果離開Spring框架就不能使用
@Resource:是Java中的註解,擴展性強,如果換一個不是Spring的容器框架(例如EJB),該註解依然可以使用
使用Spring的單元測試
好處:不需要自己通過getBean方法獲取組件,直接通過註解就可以讓Spring自動裝配
/*
* 使用Spring的單元測試
* 1.導包:導入Spring單元測試包 spring-test-4.0.0.RELEASE.jar
* 2.@ContextConfiguration(LOCATION="")使用它來指定Spring的配置文件的位置
* 3.@RunWith指定用那種驅動進行單元測試,默認是junit
* @RunWith(org.springframework.test.context.junit4.SpringJUnit4ClassRunner.class)
* 使用Spring的單元測試模塊來執行標了@Test註解的測試方法
* 以前@Test註解只是由junit執行,現在Spring中的單元測試模塊會根據指定的配置文件自動幫你創建ioc容器
* */
@ContextConfiguration(locations="classpath:applicationContext.xml")
@RunWith(org.springframework.test.context.junit4.SpringJUnit4ClassRunner.class)
public class IOCTest {
//ApplicationContext ioc = new ClassPathXmlApplicationContext("applicationContext.xml");
ApplicationContext ioc = null;
@Autowired
BookServlet bookServlet;
@Test
public void test() {
System.out.println(bookServlet);
}
}
✳實例23:測試泛型依賴注入
Spring 4.x中可以爲子類注入子類對應的泛型類型的成員變量的引用。