第二章 IOC
文章目錄
- 第二章 IOC
- 2.1 IOC(Inversion of control)
- 2.1.1 IOC的第一個(gè)HelloWorld
- 2.1.2 在配置文件中為各種屬性賦值
- 1.null(重點(diǎn))
- 2. 基本數(shù)據(jù)類型(重點(diǎn))
- 3. 內(nèi)部的bean或外部的bean(重點(diǎn))
- 4. List,Map等(重點(diǎn))
- 5. 使用util集合空間
- 6. 一個(gè)注意事項(xiàng)
- 7. 級聯(lián)屬性
- 8. 使用繼承實(shí)現(xiàn)配置信息的繼承
- 9. 指定bean是抽象的
- 2.1.3 bean的其他設(shè)置
- 1. 設(shè)置bean的依賴關(guān)系
- 2. 設(shè)置bean是否為單實(shí)例(重點(diǎn))
- 3. 配置通過靜態(tài)工廠方法創(chuàng)建bean、實(shí)例工廠方法創(chuàng)建bean、FactoryBean(重點(diǎn))
- 4. 實(shí)現(xiàn)FactoryBean的工廠(重點(diǎn))
- 5. 創(chuàng)建帶有生命周期方法的bean
- 6. 后置處理器
- 6. 引用外部屬性文件(重點(diǎn))
- 7. 基于xml的自動(dòng)裝配(自定義類型)
- 8. SpEl測試
- 9. 使用注解
- 9.1 使用@Scope()注解
- 10. 使用context:include-filter和context:exclude-filter制定掃描規(guī)則
- 11. @Autowired注解的使用
- 12. 使用@Qualifier()注解
- 13. @Autowired,@Resource,@Inject
- 14. 使用Spring的單元測試
- 15. 測試泛型依賴注入
- 2.1.4 IOC總結(jié)
第二章 IOC
2.1 IOC(Inversion of control)
IOC是控制反轉(zhuǎn),在第一章中我們已經(jīng)做了介紹,IOC的關(guān)鍵就是向容器中注冊組件。
2.1.1 IOC的第一個(gè)HelloWorld
之前都是new對象,現(xiàn)在所有的對象都交給容器創(chuàng)建和管理,所以,我們需要知道如何向容器中注冊組件。
在IDEA中新建一個(gè)空的項(xiàng)目,空的項(xiàng)目創(chuàng)建完成后,在項(xiàng)目中新建一個(gè)maven包,在新建的maven包中的pom.xml配置文件中加入以下的依賴:
<dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.1.10.RELEASE</version></dependency> </dependencies>我們只導(dǎo)入了一個(gè)springframework的依賴,其他的依賴會自動(dòng)幫我們導(dǎo)入
更改后的pom.xml文件內(nèi)容如下:
<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>org.jxd</groupId><artifactId>helloworld</artifactId><version>1.0-SNAPSHOT</version><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><maven.compiler.source>1.8</maven.compiler.source><maven.compiler.target>1.8</maven.compiler.target></properties><dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.1.10.RELEASE</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.11</version><scope>test</scope></dependency><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter</artifactId><version>RELEASE</version><scope>compile</scope></dependency></dependencies><build></build> </project>編寫一個(gè)Person實(shí)體類:
package beans;public class Person {private String name;private Integer age;public Person(String name, Integer age) {this.name = name;this.age = age;}public Person() {}public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +'}';} }在main目錄下新建一個(gè)resources目錄,在這個(gè)目錄中新建一個(gè)名為beans.xml的Spring配置文件,如下:
<?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.xsd"><!-- 向容器中注冊一個(gè)ID為person1的Person對象 --><bean id="person1" class="beans.Person"><!-- 設(shè)置person1的name屬性為張三 --><property name="name" value="張三"></property><!-- 設(shè)置person1的age屬性為12 --><property name="age" value="12"></property></bean></beans>注意:
下面編寫一個(gè)測試類,從容器中獲取注冊的id為person1的Person對象:
package com.jxd.test;import com.jxd.beans.Person; import org.junit.jupiter.api.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;public class Test1 {public static void main(String[] args) {ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");Person tom = (Person) ioc.getBean("person1");System.out.println(tom);}}運(yùn)行結(jié)果:
Person{name='tom', age=12}整個(gè)包的目錄結(jié)構(gòu)如下:
注意:
如果bean.xml不是在類路徑下,我們可以使用FileSystemXmlApplicationContext(“F://bean.xml”)
注意:Eclipse中增加注解可能會報(bào)錯(cuò),右鍵項(xiàng)目,選擇Java Compiler,在右邊的選項(xiàng)中找到Enable project specific settings,將其勾選,找到Compiler compliance setting后面的版本,將其調(diào)高到1.7。
2.1.2 在配置文件中為各種屬性賦值
在上面的例子中,我們使用配置文件的方法向IOC容器中注冊注冊了一個(gè)Person組件(對象)并為它的name、age屬性賦值。但是,name、age的屬性值都是基本的數(shù)據(jù)類型,然而在現(xiàn)實(shí)中,對象的屬性也有可能是對象類型、數(shù)組、Map等一些復(fù)雜的屬性;因此,我們還需要掌握為對象的各種復(fù)雜類型的屬性進(jìn)行賦值。
下面就介紹了如何向容器中注冊的組件的各種屬性賦值。
1.null(重點(diǎn))
<bean id="man1" class="beans.Man"><!-- String類型不賦值就是null,int默認(rèn)是0 --><property name="name"><null/></property> </bean>2. 基本數(shù)據(jù)類型(重點(diǎn))
<bean id="book1" class="beans.Book"><property name="price" value="12"/><property name="name" value="活著"/> </bean>3. 內(nèi)部的bean或外部的bean(重點(diǎn))
<bean id="man1" class="beans.Man"><property name="car"><!-- 相當(dāng)于car = new Car(),它引用內(nèi)部的bean。在當(dāng)前bean之外不能被獲取到,只能內(nèi)部使用--><bean class="beans.Car"><property name="carName" value="自行車"/><property name="price" value="350"/></bean></property> </bean><!-- 在外部創(chuàng)建一個(gè)id為motorbike的Car對象 --> <bean id="motorbike" class="beans.Car"><property name="carName" value="摩托車"/><property name="price" value="3000"/> </bean><bean id="man1" class="beans.Man"><!-- 使用ref屬性直接引用外部的car1 --><property name="car" ref="motorbike"></property> </bean>
4. List,Map等(重點(diǎn))
<bean id="man2" class="beans.Man"><!-- 如何為List賦值 --><property name="booksList" ><list><bean class="beans.Book" p:name="西游記"/><ref bean="book1"/></list></property><!-- 為map賦值 --><property name="map"><!-- new map LinkedHashMap<>() --><map><!-- 一個(gè)entry就代表一個(gè)鍵值對 --><entry key="key01" value="張三"/><entry key="key02" value="14"/><entry key="key03" value-ref="book1"/><entry key="ley04"><bean class="beans.Car"><property name="carName" value="單車"/><property name="price" value="123"/></bean></entry></map></property><!-- 為Properties對象賦值 --><property name="properties"><props><prop key="userName">root</prop><prop key="password">123456</prop></props></property> </bean>5. 使用util集合空間
<!-- util名稱空間創(chuàng)建map類型的bean,方便別人引用--> <util:map id="myMap1"><entry key="key0" value="value0"/><entry key="key1" value="value1"/> </util:map> <bean id="man3" class="beans.Man"><property name="map" ref="myMap1"/> </bean>注意:
使用util名稱空間需要導(dǎo)入響應(yīng)的xml規(guī)范:
<?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:util="http://www.springframework.org/schema/util"xmlns:p="http://www.springframework.org/schema/p"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/utilhttp://www.springframework.org/schema/util/spring-util-4.0.xsd">6. 一個(gè)注意事項(xiàng)
<!-- 注意:下面的標(biāo)簽是賦值的列表是:[[], Man, 12, {}]--> <util:list id="list1"><list/><bean class="beans.Man"/><value>12</value><ref bean="myMap1"/> </util:list>7. 級聯(lián)屬性
級聯(lián)屬性也別稱作為屬性的屬性,比如:Man類有一個(gè)類型為Car的car屬性,而Car對象又有一些自己的屬性,這些屬性就被稱為級聯(lián)屬性。
<bean id="motorbike" class="beans.Car"><property name="carName" value="摩托車"/><property name="price" value="3000"/> </bean><!-- 級聯(lián)屬性(屬性的屬性)--> <bean id="man4" class="beans.Man"><property name="car" ref="motorbike"/><property name="car.price" value="1000000"/> </bean>8. 使用繼承實(shí)現(xiàn)配置信息的繼承
<!-- 通過繼承來實(shí)現(xiàn)bean配置信息的重用 --> <bean id="man5" class="beans.Man"><property name="age" value="23"/> </bean> <!-- parent: 指定bean的配置信息繼承于哪個(gè)bean --> <bean id="man6" class="beans.Man" parent="man5"><property name="name" value="小明"/> </bean>注意:這里的繼承和java中的繼承不同,這里的繼承只是繼承了bean的配置信息,而不代表某個(gè)bean是另一個(gè)bean的父類。
9. 指定bean是抽象的
<!-- 指定一個(gè)bean是抽象的,不能實(shí)例化(也就是不能從容器中獲取),只能被繼承 --> <bean id="man7" class="beans.Man" abstract="true"></bean>2.1.3 bean的其他設(shè)置
1. 設(shè)置bean的依賴關(guān)系
<!-- 默認(rèn)bean是根據(jù)配置的順序來創(chuàng)建bean --> <!-- bean之間的依賴(只能改變創(chuàng)建的順序) --> <bean id="man1" class="beans.Man" depends-on="car1,book1"></bean> <bean id="car1" class="beans.Car"></bean> <bean id="book1" class="beans.Book"></bean>設(shè)置man1依賴于car1和book1后,就會先創(chuàng)建car1,在創(chuàng)建book1,然后才會創(chuàng)建man1。
2. 設(shè)置bean是否為單實(shí)例(重點(diǎn))
<!-- bean的作用域,創(chuàng)建單實(shí)例和多實(shí)例的bean --> <!--prototype:多實(shí)例(常用)singleton:單實(shí)例,默認(rèn)的(常用)request:在web環(huán)境下,同一次請求創(chuàng)建一個(gè)Bean實(shí)例(沒用)session:在web環(huán)境下,同一次會話創(chuàng)建一個(gè)Bean實(shí)例(沒用)--> <bean id="man2" class="beans.Man" scope="prototype"></bean>將bean設(shè)置為多實(shí)例后,每次從容器中獲取該對象都會新創(chuàng)建一個(gè)。
3. 配置通過靜態(tài)工廠方法創(chuàng)建bean、實(shí)例工廠方法創(chuàng)建bean、FactoryBean(重點(diǎn))
bean的創(chuàng)建默認(rèn)就是框架利用反射new出來的實(shí)例。
靜態(tài)工廠:工廠本身不用創(chuàng)建,也就是工廠類中獲取對象的方法是靜態(tài)的,可以直接通過靜態(tài)工廠名.方法名來獲取對象
實(shí)例工廠:工廠本身必須創(chuàng)建,創(chuàng)建后再使用這個(gè)工廠實(shí)例的方法來獲取對象
<!-- 配置通過實(shí)例工廠或靜態(tài)工廠來實(shí)例化bean --><!-- 使用靜態(tài)工廠 --> <!-- BookStaticFactory是我們自己創(chuàng)建的靜態(tài)工廠java類--> <bean id="book2" class="factory.BookStaticFactory"factory-method="getBook"><constructor-arg value="書名1"></constructor-arg> </bean><!-- 實(shí)例工廠 --> <!--1.先創(chuàng)建實(shí)例工廠bean--> <!-- BookFactory也是我們創(chuàng)建的實(shí)例工廠java類 --> <bean id="instanceBookFactory" class="factory.BookFactory"></bean> <!-- 2.再使用factory-bean指定是哪個(gè)靜態(tài)工廠bean,使用factory-method指定靜態(tài)工廠中的方法 --> <bean id="book3" class="factory.BookFactory" factory-bean="instanceBookFactory" factory-method="getBook"><!-- 3.再使用constructor-org 配置工廠方法中的輸入?yún)?shù)--><constructor-arg name="bookName" value="書名2"></constructor-arg> </bean>4. 實(shí)現(xiàn)FactoryBean的工廠(重點(diǎn))
FactoryBean是Spring規(guī)定的一個(gè)接口,一個(gè)類只要是這個(gè)接口的實(shí)現(xiàn)類,Spring都認(rèn)為這個(gè)一個(gè)工廠,且實(shí)現(xiàn)這個(gè)接口的工廠只會在需要的時(shí)候才創(chuàng)建對象。
package factory;import beans.Book; import org.springframework.beans.factory.FactoryBean;public class MyFactoryBeanImpl implements FactoryBean<Book> {/*** 工廠方法,在Spring的配置中注冊這個(gè)工廠bean就會自動(dòng)調(diào)用* getObject()方法,也就是你注冊的是一個(gè)book,不是這個(gè)工廠的bean* @return 返回創(chuàng)建的對象*/@Overridepublic Book getObject() {// Book實(shí)體類請大家自己創(chuàng)建Book book = new Book();book.setName("java從入門到放棄");return book;}/*** 返回創(chuàng)建對象的類型* Spring會自動(dòng)調(diào)用這個(gè)方法來確定我們創(chuàng)建對象的類型* @return 對象的類型*/@Overridepublic Class<?> getObjectType() {return Book.class;}/*** 判斷創(chuàng)建的對象是否是單例* @return 創(chuàng)建的對象是否是單例*/@Overridepublic boolean isSingleton() {return FactoryBean.super.isSingleton();} }將我們繼承了FactoryBean的工廠類注冊到容器中:
<!-- 因?yàn)镸yFactoryImpl是繼承了FactoryBean,也就是Spring認(rèn)識這個(gè)工廠,在注冊這個(gè)工廠的時(shí)候,Spring就自動(dòng)幫你調(diào)用的getObject()方法了,于是注冊這個(gè)工廠就是注冊了一個(gè)這個(gè)工廠類返回的對象,在本例子中就是Book組件,并且Spring不會在Spring啟動(dòng)的時(shí)候就創(chuàng)建對象,而是需要的時(shí)候才創(chuàng)建,且這與對象是否是單實(shí)例無關(guān)。--> <bean id="MyFactoryBeanImpl" class="factory.MyFactoryBeanImpl"></bean>大家可以自己測試一下從ioc容器獲取MyFactoryBeanImpl這個(gè)對象,看看它是不是一個(gè)name屬性為“java從入門到放棄”的Book對象。
5. 創(chuàng)建帶有生命周期方法的bean
bean的生命周期包括創(chuàng)建和銷毀,我們可以為bean自定義一些生命周期方法,Spring在創(chuàng)建或銷毀bean的時(shí)候就會調(diào)用我們指定的方法。
<bean id="book" class="Book" init-method="myInit" destroy-method="myDestroy"></bean>6. 后置處理器
Spring中有一個(gè)后置處理器接口BeanPostProcessor,可以在bean初始化前后調(diào)用相關(guān)的方法。
創(chuàng)建一個(gè)Book類:
public class Book {private String name;private Integer price;public void myInit(){System.out.println("生命周期方法myInit執(zhí)行了!");}public void myDestroy(){System.out.println("生命周期方法myDestroy執(zhí)行了!");}public Book() {}public Book(String name, Integer price) {this.name = name;this.price = price;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getPrice() {return price;}public void setPrice(Integer price) {this.price = price;} }創(chuàng)建一個(gè)實(shí)現(xiàn)了BeanPostProcessor這個(gè)接口的方法MyBeanPostProcessor:
import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor;public class MyBeanPostProcessor implements BeanPostProcessor {/*** 對象初始化之前調(diào)用* @param bean* @param beanName* @return* @throws BeansException*/@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {System.out.println("["+beanName+"]"+"調(diào)用初始化之前執(zhí)行的方法了!");return bean;}/*** 對象初始化之后調(diào)用* @param bean* @param beanName* @return* @throws BeansException*/@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {System.out.println("["+beanName+"]"+"調(diào)用初始化之后執(zhí)行的方法了!");return bean;} }applicationContext.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.xsd"><bean id="book" class="Book" init-method="myInit" destroy-method="myDestroy"></bean><bean id="beanPostProcessor" class="MyBeanPostProcessor"></bean> </beans>編寫一個(gè)測試類:
import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;public class TestJ {@Testpublic void test1(){ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");Book book = (Book) applicationContext.getBean("book");System.out.println(book);} }運(yùn)行結(jié)果:
[book]調(diào)用初始化之前執(zhí)行的方法了! 生命周期方法myInit執(zhí)行了! [book]調(diào)用初始化之后執(zhí)行的方法了! Book@51e696596. 引用外部屬性文件(重點(diǎn))
數(shù)據(jù)庫連接池作為一個(gè)單實(shí)例是最好的,一個(gè)項(xiàng)目一個(gè)連接池,而一個(gè)連接池中管理多個(gè)連接。可以讓Spring幫我們創(chuàng)建連接池對象,也就是注冊連接池組件。
因?yàn)槲覀儎?chuàng)建的是maven包,所以也需要在pom.xml配置文件中引入c3p0所需的依賴:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>org.example</groupId><artifactId>Spring-03-newTest</artifactId><version>1.0-SNAPSHOT</version><dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.1.10.RELEASE</version></dependency><!-- https://mvnrepository.com/artifact/com.mchange/c3p0 --><dependency><groupId>com.mchange</groupId><artifactId>c3p0</artifactId><version>0.9.5.2</version></dependency><!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.16</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>RELEASE</version><scope>test</scope></dependency></dependencies><properties><maven.compiler.source>11</maven.compiler.source><maven.compiler.target>11</maven.compiler.target></properties></project>注意:同時(shí)需要mysql-connector-java和c3p0這兩個(gè)依賴
在applicationContext.xml文件中注冊連接池對象:
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"><property name="user" value="root"></property><property name="password" value="123456"></property><property name="driverClass" value="com.mysql.cj.jdbc.Driver"></property><property name="jdbcUrl" value="jdbc:mysql://localhost:3307/books?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC"></property></bean>編寫測試類從容器中獲取連接池對象并獲取一個(gè)數(shù)據(jù)庫連接:
import com.mchange.v2.c3p0.ComboPooledDataSource; import org.junit.Test; import org.springframework.context.support.ClassPathXmlApplicationContext;import java.sql.Connection; import java.sql.SQLException;public class TestJ {@Testpublic void test1() throws SQLException {ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");ComboPooledDataSource dataSource = (ComboPooledDataSource) applicationContext.getBean("dataSource");Connection connection = dataSource.getConnection();System.out.println(connection);}}我們習(xí)慣于將c3p0的配置抽取成一個(gè)配置文件,現(xiàn)在我們就將c3p0的配置文件抽取成一個(gè)c3p0Config.properties文件,我們在resources文件夾下創(chuàng)建一個(gè)名為c3p0Config.properties文件:
jdbc.user=root jdbc.password=123456 jdbc.driverClass=com.mysql.cj.jdbc.Driver jdbc.jdbcUrl=jdbc:mysql://localhost:3307/books?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC更改applicationContext.xml文件的內(nèi)容為:
<?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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-4.2.xsd" > <!-- <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">--> <!-- <property name="user" value="root"></property>--> <!-- <property name="password" value="123456"></property>--> <!-- <property name="driverClass" value="com.mysql.cj.jdbc.Driver"></property>--> <!-- <property name="jdbcUrl" value="jdbc:mysql://localhost:3307/books?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC"></property>--> <!-- </bean>--><!-- 引用外部配置文件 --><!--1. 需要引入context名稱空間 --><!--2. 使用context:property-placeholder的location屬性引入配置文件路徑 --><context:property-placeholder location="classpath:c3p0Config.properties"></context:property-placeholder><bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"><property name="user" value="${jdbc.user}"></property><property name="password" value="${jdbc.password}"></property><property name="driverClass" value="${jdbc.driverClass}"></property><property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property></bean></beans>再次測試,我們發(fā)現(xiàn)同樣也成功了!
注意:由于username等其他單詞是spring中的個(gè)關(guān)鍵字,為了避免沖突,所以上面的properties配置文件中的字段都帶了jdbc.這個(gè)前綴
7. 基于xml的自動(dòng)裝配(自定義類型)
如果自定義類型的bean的屬性是bean,且這個(gè)bean在容器中存在,就可以使用自動(dòng)裝配。
注意:自動(dòng)裝配只能對自定義類型起作用
<?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.xsd"><bean id="car" class="Car"><property name="carName" value="自行車"></property><property name="price" value="123"></property></bean><!-- 原來為bean的屬性對象賦值 --><bean id="man1" class="Man"><property name="car" ref="car"></property></bean><!-- 自動(dòng)轉(zhuǎn)配,也就是創(chuàng)建對象時(shí)就為其屬性對象賦值 --><!-- autowire:default/no:不自動(dòng)裝配byName:根據(jù)屬性名來尋找ID,來自動(dòng)裝配,類似于ioc.getBean(id:"car"),如果找不到就裝配為nullbyType:通過類型來裝配,相當(dāng)于ioc.getBean(class:"Car.class"),如果有多個(gè),就會報(bào)錯(cuò),如果沒有找到,就裝配nullconstructor:按照構(gòu)造器來裝配1.先按照有參構(gòu)造器參數(shù)類型在ioc中尋找對象,如果有,就裝配,沒有,就直接裝配為null2.如果按照類型找到了多個(gè),參數(shù)名作為id繼續(xù)匹配,找到就轉(zhuǎn)配,找不到,就裝配為null3.不會報(bào)錯(cuò)--><bean id="man2" class="Man" autowire="byName"></bean> </beans>8. SpEl測試
SpEl是Spring Expression language的縮寫,Spring的表達(dá)式語言,支持運(yùn)行時(shí)查詢并且可以操作對象。
基本語法
SpEL使用#{}作為定界符,所有在#{}中的字符串都可以認(rèn)為是SpEl表達(dá)式
使用字面量
- 整數(shù):<property name="count" value="#{12}"/>
- 小數(shù):<property name="weight" value="#{23.32}"/>
- 科學(xué)計(jì)數(shù)法:<property name="count" value="#{12e3}"/>
- 字符串:<property name="name" value="#{'Tom'}"/>或<property name="name" value='#{"Tom"}'/>
- boolean值:<property name="married" value="false"/>
9. 使用注解
通過給bean添加一些注解就可以快速的將bean注冊到容器中。
@Controller:控制器,推薦給控制器層(servlet)加這個(gè)
@Service:業(yè)務(wù)邏輯,推薦給業(yè)務(wù)邏輯層加這個(gè)
@Repository:給持久化層(數(shù)據(jù)庫層,dao層)的組件加這個(gè)
@Componet:給不屬于以上幾個(gè)的添加
使用注解的步驟:
-
根據(jù)組件的類型,給要掃描的組件標(biāo)上對應(yīng)的注解
-
告訴Spring,自動(dòng)掃描加了注解的組件,也就是配置掃描路徑,依賴context名稱空間
依賴aop包
-
加了注解的類的id默認(rèn)是類名首字母小寫,使用注解加入到容器中的組件和通過配置加入到容器中的組件的行為和屬性都是一樣的
通過@Service這個(gè)注解,我們就將BookService這個(gè)組件注冊到了容器中;同時(shí),我們也可以在注解后加上括號,在括號中寫入自定義的ID名來修改這個(gè)組件的ID名。
注意:使用注解來注冊的組件的ID名默認(rèn)為將類名第一個(gè)字母小寫后的字符串,不要因?yàn)橥诉@個(gè)導(dǎo)致 No bean named ‘XXXXX’
9.1 使用@Scope()注解
使用注解注冊的組件默認(rèn)是單實(shí)例的,可以通過@Scope()注解來更改組件是否為單實(shí)例:
@Scope(value=“prototype”) 設(shè)置為多實(shí)例
@Scope(value=“singleton”) 設(shè)置為單實(shí)例
10. 使用context:include-filter和context:exclude-filter制定掃描規(guī)則
<?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/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><context:component-scan base-package="com.jxd"><!-- 掃描時(shí)排除的組件 --><!-- type="annotation"用于指定排除規(guī)則,標(biāo)注了指定注解的組件不要expression: 注解的全類名type="assignable": 指定排除某個(gè)具體的類,按照類排除expression: 類的全類名--><context:exclude-filter type="assignable" expression="com.jxd.service.BookService"/></context:component-scan><!-- 先禁用原來的掃描方式(一定要禁用才有用!) --><context:component-scan base-package="com.jxd" use-default-filters="false"><!-- 只掃描哪些組件,默認(rèn)是全部都掃描 --><!--type和expression的用法和exclude一樣--><context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/></context:component-scan></beans>11. @Autowired注解的使用
使用@Autowired注解可以讓容器將我們依賴的對象自動(dòng)注入:
package com.jxd.service;import com.jxd.dao.BookDao; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service;@Service("bookService") public class BookService {@Autowiredprivate BookDao bookDao;public void saveBook(){System.out.println("正在調(diào)用BookDao的saveToDB方法");bookDao.saveToDB();} }使用@Autowired(required=false)可以指定如果找不到就裝配null。
常見的自動(dòng)注入失敗原因:
@Autowired自動(dòng)裝配的步驟:
- 第一步:按照類型再容器中找到對應(yīng)的組件,
- 找到一個(gè):裝配
- 未找到:異常
- 找到多個(gè):
- 按照變量名作為Id繼續(xù)匹配
- 匹配上:裝配
- 沒有匹配上:異常
- 按照變量名作為Id繼續(xù)匹配
在方法上使用@Autowired注解:
如果在一個(gè)方法上使用了@Autowired注解,這個(gè)方法會在該bean創(chuàng)建的時(shí)候自動(dòng)運(yùn)行,且這個(gè)方法的每一個(gè)參數(shù)都會自動(dòng)注入
12. 使用@Qualifier()注解
@Qualified()注解可以指定自動(dòng)裝配時(shí)采用@Qualified("ID名")指定的ID來查找,如果通過@Qualified注解指定的ID來查找還是未找到,就會產(chǎn)生異常。
在方法的形參位置使用@Qualifier注解:
指定這個(gè)形參自動(dòng)注入依據(jù)的ID名
13. @Autowired,@Resource,@Inject
它們都是自動(dòng)裝配的注解,但是,@Autowired的功能是最強(qiáng)大的。
- @Autowired:最強(qiáng)大,Spring自己的注解
- @Resource:j2ee的標(biāo)準(zhǔn),擴(kuò)展性更強(qiáng)
- @Inject:是JSR330 (Dependency Injection for Java)中的規(guī)范
14. 使用Spring的單元測試
提示:需要依賴Spring的單元測試的jar包
例子:
package com.jxd.test;import com.jxd.service.BookService; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;@ContextConfiguration(locations = "classpath:applicationConfig.xml") @RunWith(SpringJUnit4ClassRunner.class) public class TestJ1 {@AutowiredBookService bookService;@Testpublic void test1(){bookService.saveBook();} }@ContextConfiguration(location=“ ”):用來指定Spring的配置文件的位置
@RunWith( ):指定用那種驅(qū)動(dòng)進(jìn)行單元測試,默認(rèn)是junit
15. 測試泛型依賴注入
泛型依賴注入,注入一個(gè)組件的時(shí)候,它的泛型也是參考標(biāo)準(zhǔn)。
Spring中可以使用帶泛型的父類類型來確定子類的類型。
2.1.4 IOC總結(jié)
IOC(Inversion of control)是一個(gè)容器,它可以幫我們管理注冊到容器中的組件(類)。容器啟動(dòng),會創(chuàng)建所有的單實(shí)例bean,autowired自動(dòng)裝配的時(shí)候,是從容器中找到符合要求的bean,ioc.getBean(“ ”)也是從容器中找到指定的bean。這個(gè)容器其實(shí)是一個(gè)map,這個(gè)map保存了所有創(chuàng)建好的bean,并提供相應(yīng)的功能。
感謝你的閱讀!
總結(jié)
- 上一篇: 为什么fm1支持DDR3内存条?揭秘性能
- 下一篇: 对爬虫爬取到的数据进行存储