文章目錄
常用的從容器中獲取bean實例使用這樣的方式:
@Test
public void test() {
Persion p = (Persion) ioc.getBean("p1");
System.out.println(p);
}
常用的在容器中配置組件使用這樣的方式:
<bean id="p1" class="com.gql.bean.Persion">
<property name="name" value="張三"></property>
<property name="age" value="18"></property>
<property name="email" value="[email protected]"></property>
<property name="gender" value="男"></property>
</bean>
下面的實驗介紹一些Spring容器中註冊組件對象的其他方法。
實驗1:根據bean的類型從ioc容器中獲取實例
@Test
public void test01() {
Persion p = ioc.getBean(Persion.class);
System.out.println(p);
}
這種方法查找的好處是不需要類型轉換,但是如果ioc容器中要找的bean有多個,使用這種方法查找就會報錯。可以改用下面的方式:
@Test
public void test01() {
Persion p = ioc.getBean("p1", Persion.class);
System.out.println(p);
}
實驗2:通過有參構造器爲bean的屬性賦值
需要提前在bean中添加有參構造器,才能進行下面的測試。
<bean id="p2" class="com.gql.bean.Persion">
<constructor-arg name="name" value="李四"></constructor-arg>
<constructor-arg name="age" value="22"></constructor-arg>
<constructor-arg name="email" value="[email protected]"></constructor-arg>
<constructor-arg name="gender" value="男"></constructor-arg>
</bean>
使用這種有參構造器爲bean的屬性賦值,可以省略name,但是value的順序必須與bean中的順序一致。(若再使用index和type進行索引,可以不按順序)
通過名稱空間爲bean賦值:
添加p命名空間標籤頭:xmlns:p=“http://www.springframework.org/schema/p”
<bean id="p4" class="com.gql.bean.Persion" p:name="小王" p:age="22"
p:gender="男" p:email="[email protected]"></bean>
實驗3:爲各種屬性賦值
- 引用類型、集合類型、級聯類型。
如題,給出一個賦值的Bean對象,爲其在容器中註冊。此時所有複雜的賦值都在property標籤體內。
public class Persion {
private String name;
private String gender;
private Integer age;
private String email;
private Car car;
private List<Book> book;
private Map<String, Object> maps;
private Properties properties;
//省略setter與getter方法
}
普通屬性賦值:
<!-- 普通屬性賦值 -->
<property name="name" value="張三"></property>
<property name="gender" value="男"></property>
<property name="age" value="20"></property>
<property name="email">
<null />
</property>
引用類型賦值:
<bean id="p1" class="com.gql.bean.Persion">
<!-- 引用外部bean -->
<!-- <property name="car" ref="c1"></property> -->
<!-- 引用內部bean(內部bean不能被獲取到) -->
<property name="car">
<bean class="com.gql.bean.Car">
<property name="carName" value="自行車"></property>
<property name="color" value="黑色"></property>
<property name="price" value="400"></property>
</bean>
</property>
</bean>
<bean id="c1" class="com.gql.bean.Car">
<property name="carName" value="寶馬"></property>
<property name="color" value="白色"></property>
<property name="price" value="30000"></property>
</bean>
集合類型賦值:
list
<bean id="p1" class="com.gql.bean.Persion">
<property name="book">
<list>
<bean class="com.gql.bean.Book" p:bookName="西遊記" p:author="吳承恩"></bean>
<ref bean="book01" />
</list>
</property>
</bean>
<bean id="book01" class="com.gql.bean.Book">
<property name="bookName" value="水滸傳"></property>
<property name="author" value="施耐庵"></property>
</bean>
map
<property name="maps">
<map>
<entry key="k01" value="v01"></entry>
<entry key="k02" value="v02"></entry>
<entry key="k03" value-ref="book01"></entry>
<entry key="k04">
<bean class="com.gql.bean.Car">
<property name="carName" value="捷豹"></property>
<property name="color" value="紅色"></property>
<property name="price" value="50000"></property>
</bean>
</entry>
</map>
</property>
properties
<property name="properties">
<props>
<prop key="username">root</prop>
<prop key="password">123456</prop>
</props>
</property>
實驗4:通過繼承實現bean配置信息的重用
下面的代碼中p4繼承了p3,需要改動的屬性在property標籤中修改即可,其餘的全部原樣繼承。
<bean id="p3" class="com.gql.bean.Persion">
<property name="name" value="張三"></property>
<property name="age" value="20"></property>
<property name="gender" value="男"></property>
<property name="email" value="[email protected]"></property>
</bean>
<bean id="p4" parent="p3">
<property name="name" value="李四"></property>
</bean>
實驗5:單實例singleton和多實例prototype
單實例singleton | 多實例prototype |
---|---|
①容器啓動時 創建好對象並保存在容器中 |
①獲取Bean時 纔會創建這個對象 |
②調用初始化方法 | ②調用初始化方法 |
③容器關閉時調用銷燬方法 |
③容器銷燬時不調用銷燬方法 |
任何時間獲取都是獲取之前創建好的那個對象 | 每次獲取都會創建一個新的對象 |
詳情可參照博客:通過工廠創建Bean的三種方式
實驗6:創建帶有生命週期的Bean
ioc容器中註冊的組件:
- 單實例:容器啓動的時候就會創建好,容器關閉也會銷燬創建的bean。
- 多實例:獲取的時候才創建。
可以爲bean自定義一些生命週期方法,spring在創建或銷燬的時候就會調用指定的方法。
(1)單實例Singleton測試
在Book類中創建方法:
package com.gql.bean;
public class Book {
private String bookName;
private String author;
public void myInit() {
System.out.println("Book的初始化方法...");
}
public void myDestory() {
System.out.println("Book的銷燬方法...");
}
public Book() {
super();
// TODO Auto-generated constructor stub
System.out.println("Book創建...");
}
}
在xml中註冊組件:
<bean id="book01" class="com.gql.bean.Book" destroy-method="myDestory" init-method="myInit"></bean>
測試:
- 在ApplicationContext中沒有close方法,需要將容器類型轉換爲ConfigurableApplicationContext 。
public class IoCTest {
ConfigurableApplicationContext ioc = new ClassPathXmlApplicationContext("ApplicationContext.xml");
@Test
public void test10() {
System.out.println("容器關閉了");
ioc.close();
}
}
(2)多實例prototype測試
只需要改變xml中註冊組件爲多實例:
<bean id="book01" class="com.gql.bean.Book" destroy-method="myDestory" init-method="myInit" scope="prototype"></bean>
仍然使用上面的方法進行測試:
可以看到容器的創建銷燬一系列都沒有進行,這是因爲多實例在獲取bean的時候才創建實例。
多實例測試中增加獲取bean:
@Test
public void test10() {
Object bean = ioc.getBean("book01");
System.out.println(bean);
System.out.println("容器關閉了");
ioc.close();
}
測試結果中,成功創建了實例,但是容器關閉並沒有銷燬Bean。
實驗7:測試Bean的後置處理器
後置處理器有一點代理對象的意思,使用後置處理器,Bean的生命週期變成下面的樣子:
容器啓動—>後置處理器Before—>初始化方法—>後置處理器After—>容器關閉(調用銷燬方法)
- 不管有沒有初始化方法,後置處理器都會默認其有,繼續工作。
後置處理器:
package com.gql.bean;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
/**
* 1.編寫後置處理器
* 2.將後置處理器註冊在配置文件
* @author guoqianliang
*
*/
public class MyBeanPostProcessor implements BeanPostProcessor {
/**
* 初始化前調用
*/
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
// TODO Auto-generated method stub
System.out.println("Before:" + beanName + "將要調用初始化方法了..." + bean);
return bean;
}
/**
* 初始化後調用
*/
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
// TODO Auto-generated method stub
System.out.println("After:" + beanName + "初始化方法調用完了" + bean);
return 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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="book01" class="com.gql.bean.Book" destroy-method="myDestory" init-method="myInit" scope="singleton"></bean>
<!-- 後置處理器:可以在bean的初始化前後調用方法 -->
<bean id="beanPostProcessor" class="com.gql.bean.MyBeanPostProcessor"></bean>
</beans>
測試:
@Test
public void test11() {
Object bean = ioc.getBean("book01");
System.out.println("容器關閉了");
ioc.close();
}
實驗8:引用外部文件
在Spring中bean默認都是單實例的,而數據庫作爲單實例是最好不過的,一個項目就是一個連接池,連接池裏面管理很多連接,連接是直接從連接池中拿。可以讓Spring幫我們創建連接池對象,管理連接池。
註冊連接池第一代
在配置中註冊連接池:
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="user" value="root"></property>
<property name="password" value="Hudie"></property>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test"></property>
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
</bean>
測試:
@Test
public void test12() throws SQLException {
// 從容器中拿到連接
// DataSource bean = (DataSource) ioc.getBean("dataSource");
DataSource bean2 = ioc.getBean(DataSource.class);
System.out.println(bean2.getConnection());
}
成功獲取到了這個連接:
註冊連接池第二代
在config包下創建一個dbconfig.properties用來保存數據庫連接信息。
- 爲了防止配置文件中的key與Spring自己的關鍵字衝突。可以爲key加一個前綴,業內通用的做法是使用jabc.xxx
jdbc.username:root
jdbc.password:Hudie
jdbc.jdbcUrl:jdbc:mysql://localhost:3306/test
jdbc.driverClass:com.mysql.jdbc.Driver
註冊數據庫連接池:
<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>
測試:
@Test
public void test12() throws SQLException {
DataSource bean2 = ioc.getBean(DataSource.class);
System.out.println(bean2.getConnection());
}