Spring IOC容器
<?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>com.llxazy</groupId> <artifactId>spring_demo</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <!-- https://mvnrepository.com/artifact/org.springframework/spring-context--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.3.RELEASE</version> </dependency> </dependencies> </project>
2、編寫實體類
Person.java
package com.llxazy.bean; public class Person { private int id; private String name; private int age; private String gender; //此處省略構造方法、get、set方法、toString方法 }
3、註冊物件
ioc.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"> <!--註冊一個物件,spring會自動建立這個物件--> <!-- 一個bean標籤就表示一個物件 id:這個物件的唯一標識 class:註冊物件的完全限定名 --> <bean id="person" class="com.llxazy.bean.Person"> <!--使用property標籤給物件的屬性賦值 name:表示屬性的名稱 value:表示屬性的值 --> <property name="id" value="1001"></property> <property name="name" value="李四"></property> <property name="age" value="28"></property> <property name="gender" value="男"></property> </bean> </beans>
4、測試
SpringTest.java
import com.llxazy.bean.Person; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class SpringTest { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("ioc.xml"); Person person = (Person) context.getBean("person"); System.out.println(person); } }
總結:
1、ApplicationContext就是IOC容器的介面,可以通過此物件獲取容器中建立的物件;
2、物件在Spring容器中預設是在建立完成的時候就已經建立完成,不是需要用的時候才建立,此種情況滿足的是單例模式;
3、物件在IOC容器中儲存的時候預設都是單例的,如果需要多例需要修改屬性;
4、建立物件給屬性賦值的時候是通過setter方法實現的;
5、物件的屬性是由setter/getter方法決定的,而不是定義的成員屬性。
一、spring物件的獲取及屬性賦值方式:
1、
<!--給person類新增構造方法--> <bean id="person2" class="com.llxazy.bean.Person"> <constructor-arg name="id" value="1"></constructor-arg> <constructor-arg name="name" value="lisi"></constructor-arg> <constructor-arg name="age" value="20"></constructor-arg> <constructor-arg name="gender" value="女"></constructor-arg> </bean> <!--在使用構造器賦值的時候可以省略name屬性,但是此時就要求必須嚴格按照構造器引數的順序來填寫了--> <bean id="person3" class="com.llxazy.bean.Person"> <constructor-arg value="1"></constructor-arg> <constructor-arg value="lisi"></constructor-arg> <constructor-arg value="20"></constructor-arg> <constructor-arg value="女"></constructor-arg> </bean> <!--如果想不按照順序來新增引數值,那麼可以搭配index屬性來使用--> <bean id="person4" class="com.llxazy.bean.Person"> <constructor-arg value="lisi" index="1"></constructor-arg> <constructor-arg value="1" index="0"></constructor-arg> <constructor-arg value="女" index="3"></constructor-arg> <constructor-arg value="20" index="2"></constructor-arg> </bean> <!--當有多個引數個數相同,不同型別的構造器的時候,可以通過type來強制型別--> 將person的age型別設定為Integer型別 public Person(int id, String name, Integer age) { this.id = id; this.name = name; this.age = age; System.out.println("Age"); } public Person(int id, String name, String gender) { this.id = id; this.name = name; this.gender = gender; System.out.println("gender"); } <bean id="person5" class="com.llxazy.bean.Person"> <constructor-arg value="1"></constructor-arg> <constructor-arg value="lisi"></constructor-arg> <constructor-arg value="20" type="java.lang.Integer"></constructor-arg> </bean> <!--如果不修改為integer型別,那麼需要type跟index組合使用--> <bean id="person5" class="com.llxazy.bean.Person"> <constructor-arg value="1"></constructor-arg> <constructor-arg value="lisi"></constructor-arg> <constructor-arg value="20" type="int" index="2"></constructor-arg> </bean>
4、通過名稱空間為bean賦值,簡化配置檔案中屬性宣告的寫法
匯入名稱空間
<?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:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
新增配置
<bean id="person6" class="com.mashibing.bean.Person" p:id="3" p:name="wangwu" p:age="22" p:gender="男"></bean>
5、為複雜型別進行賦值操作
給複雜型別賦值,如集合、陣列、其他物件等。
實體類:
public class Person { private int id; private String name="李四"; private int age; private String gender; private Address address; private String[] hobbies; private List<Book> books; private Set<Integer> sets; private Map<String,Object> maps; private Properties properties; //此處省略構造方法、get、set方法、toString方法 } public class Book { private String name; private String author; private double price; //此處省略構造方法、get、set方法、toString方法 } public class Address { private String province; private String city; private String town; //此處省略構造方法、get、set方法、toString方法 }
ioc.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:p="http://www.springframework.org/schema/p" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd" > <!--給複雜型別的賦值都在property標籤內進行--> <bean id="person" class="com.llxazy.bean.Person"> <property name="name"> <!--賦空值--> <null></null> </property> <!--通過ref引用其他物件,引用外部bean--> <property name="address" ref="address"></property> <!--引用內部bean--> <!-- <property name="address"> <bean class="com.llxazy.bean.Address"> <property name="province" value="北京"></property> <property name="city" value="北京"></property> <property name="town" value="西城區"></property> </bean> </property>--> <!--為list賦值--> <property name="books"> <list> <!--內部bean--> <bean id="book1" class="com.llxazy.bean.Book"> <property name="name" value="水滸傳"></property> <property name="author" value="施耐庵"></property> <property name="price" value="100"></property> </bean> <!--外部bean--> <ref bean="book2"></ref> </list> </property> <!--給map賦值--> <property name="maps" ref="myMap"></property> <!--給property賦值--> <property name="properties"> <props> <prop key="aaa">aaa</prop> <prop key="bbb">222</prop> </props> </property> <!--給陣列賦值--> <property name="hobbies"> <array> <value>book</value> <value>movie</value> <value>game</value> </array> </property> <!--給set賦值--> <property name="sets"> <set> <value>111</value> <value>222</value> <value>222</value> </set> </property> </bean> <bean id="address" class="com.llxazy.bean.Address"> <property name="province" value="河北"></property> <property name="city" value="邯鄲"></property> <property name="town" value="武安"></property> </bean> <bean id="book2" class="com.llxazy.bean.Book"> <property name="name" value="西遊記"></property> <property name="author" value="吳承恩"></property> <property name="price" value="200"></property> </bean> <!--級聯屬性--> <bean id="person2" class="com.llxazy.bean.Person"> <property name="address" ref="address"></property> <property name="address.province" value="北京"></property> </bean> <!--util名稱空間建立集合型別的bean--> <util:map id="myMap"> <entry key="key1" value="value1"></entry> <entry key="key2" value-ref="book2"></entry> <entry key="key03"> <bean class="com.llxazy.bean.Book"> <property name="name" value="西遊記" ></property> <property name="author" value="吳承恩" ></property> <property name="price" value="100" ></property> </bean> </entry> </util:map> </beans>
6、繼承關係bean的配置
ioc.xml
<bean id="person" class="com.llxazy.bean.Person"> <property name="id" value="1"></property> <property name="name" value="zhangsan"></property> <property name="age" value="21"></property> <property name="gender" value="男"></property> </bean> <!--parent:指定bean的配置資訊繼承於哪個bean--> <bean id="person2" class="com.llxazy.bean.Person" parent="person"> <property name="name" value="lisi"></property>
</bean>
如果想實現Java檔案的抽象類,不需要將當前bean例項化的話,可以使用abstract屬性
<bean id="person" class="com.llxazy.bean.Person" abstract="true"> <property name="id" value="1"></property> <property name="name" value="zhangsan"></property> <property name="age" value="21"></property> <property name="gender" value="男"></property> </bean> <!--parent:指定bean的配置資訊繼承於哪個bean--> <bean id="person2" class="com.llxazy.bean.Person" parent="person"> <property name="name" value="lisi"></property> </bean>
7、bean物件建立的依賴關係
bean物件在建立的時候是按照bean在配置檔案的順序決定的,也可以使用depend-on標籤來決定順序
<bean id="book" class="com.llxazy.bean.Book" depends-on="person,address"></bean> <bean id="address" class="com.llxazy.bean.Address"></bean> <bean id="person" class="com.llxazy.bean.Person"></bean>
<!-- bean的作用域:singleton、prototype、request、session 通過scope屬性可以指定當前bean的作用域 預設情況下是單例的 prototype:多例項的 容器啟動的時候不會建立多例項bean,只有在獲取物件的時候才會建立該物件 每次建立都是一個新的物件 singleton:預設的單例物件 在容器啟動完成之前就已經建立好物件 獲取的所有物件都是同一個 在Spring4.x版本中還包含另外兩個作用域 request:每次傳送請求都會有一個新的物件 session:每一次會話都會有一個新的物件 注意: 如果是singleton作用域的話,每次在建立IOC容器之前此物件已經建立完成 如果是prototype作用域的話,每次是在需要用到此物件的時候才會建立 --> <bean id="person4" class="com.llxazy.bean.Person" scope="prototype"></bean>
9、利用工廠模式建立bean物件
在利用工廠模式建立bean例項的時候有兩種方式,分別是靜態工廠和例項工廠。
靜態工廠:工廠本身不需要建立物件,但是可以通過靜態方法呼叫,物件=工廠類.靜態工廠方法名();
例項工廠:工廠本身需要建立物件,工廠類 工廠物件=new 工廠類;工廠物件.get物件名();
靜態工廠:
public class PersonStaticFactory { public static Person getPerson(String name){ Person person = new Person(); person.setId(1); person.setName(name); return person; } } <!-- 靜態工廠的使用: class:指定靜態工廠類 factory-method:指定哪個方法是工廠方法 --> <bean id="person5" class="com.llxazy.factory.PersonStaticFactory" factory-method="getPerson"> <!--constructor-arg:可以為方法指定引數--> <constructor-arg value="lisi"></constructor-arg> </bean>
動態工廠:
public class PersonInstanceFactory { public Person getPerson(String name){ Person person = new Person(); person.setId(1); person.setName(name); return person; } } <!--例項工廠使用--> <!--建立例項工廠類--> <bean id="personInstanceFactory" class="com.llxazy.factory.PersonInstanceFactory"></bean> <!-- factory-bean:指定使用哪個工廠例項 factory-method:指定使用哪個工廠例項的方法 --> <bean id="person6" class="com.llxazy.bean.Person" factory-bean="personInstanceFactory" factory-method="getPerson"> <constructor-arg value="wangwu"></constructor-arg> </bean>
/** * 實現了FactoryBean介面的類是Spring中可以識別的工廠類,spring會自動呼叫工廠方法建立例項 * 此方式是Spring建立bean方式的一種補充,使用者可以按照需求建立物件,建立的物件交由spring IOC容器 * 進行管理,無論是否是單例,都是在用到的時候才會建立該物件,不用該物件則不會建立 */ public class MyFactoryBean implements FactoryBean<Person> { /** * 工廠方法,返回需要建立的物件 * @return * @throws Exception */ @Override public Person getObject() throws Exception { Person person = new Person(); person.setName("maliu"); return person; } /** * 返回建立物件的型別,spring會自動呼叫該方法返回物件的型別 * @return */ @Override public Class<?> getObjectType() { return Person.class; } /** * 建立的物件是否是單例物件 * @return */ @Override public boolean isSingleton() { return false; } } ioc.xml <bean id="myfactorybean" class="com.llxazy.factory.MyFactoryBean"></bean>
11、bean物件的初始化和銷燬方法
<!--spring容器在建立物件時可以指定具體的初始化和銷燬方法 init-method:在物件建立完成之後會呼叫初始化方法 destory-method:在容器關閉的時候會呼叫銷燬方法 bean生命週期表示bean的建立到銷燬 如果bean是單例,容器在啟動的時候會建立好,關閉的時候會銷燬建立的bean 如果bean是多例,獲取的時候建立物件,銷燬的時候不會有任何的呼叫 --> <bean id="address" class="com.llxazy.bean.Address" init-method="init" destroy-method="destory"></bean> //測試類 public class MyTest { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("ioc2.xml"); Address address = context.getBean("address", Address.class); System.out.println(address); //applicationContext沒有close方法,需要使用具體的子類 ((ClassPathXmlApplicationContext)context).close(); } }
12、配置bean物件初始化方法的前後處理方法
spring中包含一個BeanPostProcessor的介面,可以在bean的初始化方法的前後呼叫該方法,如果配置了初始化方法的前置和後置處理器,無論是否包含初始化方法,都會進行呼叫
public class MyBeanPostProcessor implements BeanPostProcessor { /** * 在初始化方法呼叫之前執行 * @param bean 初始化的bean物件 * @param beanName xml配置檔案中的bean的id屬性 * @return * @throws BeansException */ @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("postProcessBeforeInitialization:"+beanName+"呼叫初始化前置方法"); return bean; } /** * 在初始化方法呼叫之後執行 * @param bean * @param beanName * @return * @throws BeansException */ @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("postProcessAfterInitialization:"+beanName+"呼叫初始化字尾方法"); return bean; } } //ioc.xml <bean id="myBeanPostProcessor" class="com.llxazy.bean.MyBeanPostProcessor"></bean>
二、
<!-- https://mvnrepository.com/artifact/com.alibaba/druid --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.21</version> </dependency> <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency>
2、編寫配置檔案
<?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="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="username" value="root"></property> <property name="password" value="root"></property> <property name="url" value="jdbc:mysql://localhost:3306/demo"></property> <property name="driverClassName" value="com.mysql.jdbc.Driver"></property> </bean> </beans>
三、spring引用外部配置檔案
1、在resource中新增dbconfig.properties
username=root
password=root
url=jdbc:mysql://localhost:3306/demo
driverClassName=com.mysql.jdbc.Driver
2、ioc.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/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名稱空間 --> <context:property-placeholder location="classpath:dbconfig.properties"/> <!--在配置檔案編寫屬性的時候需要注意: spring容器在進行啟動時,會讀取當前系統的某些環境變數的配置 當前系統的使用者名稱是用username表示的,所以最好的方式是新增字首來區分--> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="username" value="${username}"></property> <property name="password" value="${password}"></property> <property name="url" value="${url}"></property> <property name="driverClassName" value="${driverClassName}"></property> </bean> </beans>
四、spring基於xml檔案的自動裝配
當一個物件中需要引用另外一個物件的時候,在之前的配置中我們都是通過property標籤來進行手動配置的,其實在spring中還提供了一個非常強大的功能就是自動裝配(autowire),可以按照我們指定的規則進行配置,配置的方式有以下幾種:
default/no:不自動裝配
byName:按照名字進行裝配,以屬性名作為id去容器中查詢元件,進行賦值,如果找不到則裝配null
byType:按照型別進行裝配,以屬性的型別作為查詢依據去容器中找到這個元件,如果有多個型別相同的bean物件,那麼會報異常,如果找不到則裝配null
constructor:按照構造器進行裝配,先按照有參構造器引數的型別進行裝配,沒有就直接裝配null;如果按照型別找到了多個,那麼就使用引數名作為id繼續匹配,找到就裝配,找不到就裝配null
<?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="address" class="com.llxazy.bean.Address"> <property name="province" value="陝西"></property> <property name="city" value="西安"></property> <property name="town" value="藍田"></property> </bean> <bean id="person" class="com.llxazy.bean.Person" autowire="byName"></bean> <bean id="person2" class="com.llxazy.bean.Person" autowire="byType"></bean> <bean id="person3" class="com.llxazy.bean.Person" autowire="constructor"></bean> </beans>
五、SpEL的使用
SpEL:Spring Expression Language,spring的表示式語言,支援執行時查詢操作物件
使用#{...}作為語法規則,所有的大括號中的字元都認為是SpEL.
<bean id="person4" class="com.llxazy.bean.Person"> <!--支援任何運算子--> <property name="age" value="#{12*2}"></property> <!--可以引用其他bean的某個屬性值--> <property name="name" value="#{address.province}"></property> <!--引用其他bean--> <property name="address" value="#{address}"></property> <!--呼叫靜態方法--> <property name="hobbies" value="#{T(java.util.UUID).randomUUID().toString().substring(0,4)}"></property> <!--呼叫非靜態方法--> <property name="gender" value="#{address.getCity()}"></property> </bean>