Spring框架——關於IOC容器和註解的36個小實驗
實驗1:通過IOC容器創建對象,並為屬性賦值★
<bean id="page" class="com.neuedu.Bean.Page"> <property name="fontSize" value="大寫"></property> <property name="fontNum" value="12"></property> </bean> ApplicationContext iocContainer = new ClassPathXmlApplicationContext("applicationContext.xml"); Page bean2 = (Page)iocContainer.getBean("page");
實驗2:根據bean的類型從IOC容器中獲取bean的實例★
<bean id="page" class="com.neuedu.Bean.Page"> <property name="fontSize" value="大寫"></property> <property name="fontNum" value="12"></property> </bean> ApplicationContext iocContainer = new ClassPathXmlApplicationContext("applicationContext.xml"); Page bean2 = iocContainer.getBean(Page.class);
實驗3:通過構造器為bean的屬性賦值
<bean id="Book" class="com.neuedu.Bean.Book"> <!-- 以下為給帶參構造器傳送參數 --> <constructor-arg value="123" ></constructor-arg> <constructor-arg value="456" ></constructor-arg> <constructor-arg value="789" ></constructor-arg> </bean>
實驗4:通過index屬性指定參數的位置
<bean id="Book" class="com.neuedu.Bean.Book"> <property name="num" value="123"></property> <constructor-arg value="123" index="0"></constructor-arg> <constructor-arg value="123" index="1"></constructor-arg> <constructor-arg value="123" index="2"></constructor-arg> </bean>
實驗5:通過類型不同區分重載的構造器
<bean id="page" class="com.neuedu.Bean.Page"> <constructor-arg value="123" type="int"></constructor-arg> <constructor-arg value="456" type="String"></constructor-arg> </bean>
實驗6:通過p名稱空間為bean賦值
<bean id="Book2" parent="Book" p:num="254" />
實驗14:給bean的級聯屬性賦值
<bean id="page" class="com.neuedu.Bean.Page"> <constructor-arg value="123" type="int"></constructor-arg> <constructor-arg value="456" type="String"></constructor-arg> </bean> <bean id="Book" class="com.neuedu.Bean.Book"> <property name="page" ref="page"></property> </bean>
實驗21:測試bean的作用域,分別創建單實例和多實例的bean★
<bean id="page" scope="prototype" class="com.neuedu.Bean.Page"> <constructor-arg value="123" type="int"></constructor-arg> <constructor-arg value="456" type="String"></constructor-arg> </bean>
Scope屬性:
Prototype:每次從容器中調用Bean時,都返回一個新的實例,即每次調用getBean()時,相當於執行new XxxBean()的操作
Request:每次Http請求都會創建一個新的Bean, 僅適用於WebApplication環境
Session:每次創建一個session,創建對象,同一個Http Session共享一個Bean,不同的HttpSession使用不同的Bean。僅適用於WebApplication環境
Singleton:在Spring容器中僅存在一個Bean實例,Bean以單例的方式存在
實驗22:創建帶有生命周期方法的bean
<bean id="page" scope="singleton" class="com.neuedu.Bean.Page" init-method="int" destroy-method="destroy"> <constructor-arg value="123" type="int"></constructor-arg> <constructor-arg value="456" type="String"></constructor-arg> </bean>
實驗20:bean之間的依賴 depends-on="order"被依賴的對象會先創建
<bean id="page" scope="singleton" class="com.neuedu.Bean.Page" depends-on="font"> <constructor-arg value="123" type="int"></constructor-arg> <constructor-arg value="456" type="String"></constructor-arg> </bean> <bean id="font" class="com.neuedu.Bean.Font"></bean>
實驗18:通過繼承實現bean配置信息的重用
<bean id="Book" class="com.neuedu.Bean.Book" p:name="四大名著" p:num="258" /> <bean id="Book2" parent="Book" p:num="254" />
實驗19:通過abstract屬性創建一個模板bean
<bean id="Book" abstract="true" class="com.neuedu.Bean.Book" p:name="四大名著" p:num="258" /> <bean id="Book2" parent="Book" p:num="254" />
實驗7:測試使用null值
<bean id="page" scope="singleton" class="com.neuedu.Bean.Page" > <property name="fontSize"> <null/> </property> </bean>
null只有包裝類和引用類型可以用
實驗8:引用其他bean★
<bean id="Book" class="com.neuedu.Bean.Book"> <property name="page" ref="page"></property> </bean>
實驗9:引用內部bean
<bean id="Book" class="com.neuedu.Bean.Book"> <property name="page" > <bean id="page" scope="singleton" class="com.neuedu.Bean.Page" > <property name="fontSize" value="123"></property> </bean> </property> </bean>
實驗10:使用List類型的集合屬性
<bean id="pets" class="com.xgj.ioc.inject.construct.utilSchema.Pets"> <property name="petList" ref="petList" /> </bean> <util:list id="petList" list-class="java.util.ArrayList" value-type="java.lang.String"> <value>DOG</value> <value>CAT</value> <value>BIRD</value> </util:list>
實驗11:使用Map類型的集合屬性
<!-- 第一種寫法 ,通過ref引用,此時需要在 uitl-map中聲明id 推薦這種寫法 <bean id="pets" class="com.xgj.ioc.inject.construct.utilSchema.Pets"> <property name="petMap" ref="petMap" /> </bean> <util:map id="petMap" map-class="java.util.HashMap"> <entry key="101" value="dog" /> <entry key="103" value="wolf" /> <entry key="105" value="bird" /> </util:map> --> <!-- 第二種寫法,嵌入內部 --> <bean id="pets" class="com.xgj.ioc.inject.construct.utilSchema.Pets"> <property name="petMap"> <util:map map-class="java.util.HashMap"> <!-- 可以通過map-class顯示指定Map的實現類 --> <entry key="101" value="dog" /> <entry key="103" value="wolf" /> <entry key="105" value="bird" /> </util:map> </property> </bean>
實驗12:使用prop子元素為Properties類型的屬性賦值
<bean id="pets" class="com.xgj.ioc.inject.construct.utilSchema.Pets"> <property name="petProperties" ref="petProperties" /> </bean> <util:properties id="petProperties"> <prop key="151">PIG</prop> <prop key="153">PINGUIN</prop> </util:properties>
實驗15:配置通過靜態工廠方法創建的bean[通過靜態方法提供實例對象,工廠類本身不需要實例化!]
<bean id="staticFactory" class="com.neuedu.spring.bean.StaticFactory" factory-method="getBook"> <constructor-arg value="book01"></constructor-arg> </bean>
實驗16:配置通過實例工廠方法創建的bean[通過實例方法提供實例對象,工廠類本身需要先創建對象!]
<bean id="instanceFactory" class="com.neuedu.spring.bean.InstanceFactory"></bean> <bean id="bookFromInstanceFactory" factory-bean="instanceFactory" factory-method="getBook"> <constructor-arg value="book02"></constructor-arg> </bean>
實驗17:配置FactoryBean★
public class MyFactoryBean implements FactoryBean<Book> { @Override public Book getObject() throws Exception { return new Book(22, "無字天書", "好啊", 22.5); } @Override public Class<?> getObjectType() { return Book.class; } @Override public boolean isSingleton() { return false; } }
實驗22[補充]:測試bean的後置處理器
①在bean的初始化方法調用前後執行操作的專門的對象
②自定義後置處理器實現該接口:org.springframework.beans.factory.config.BeanPostProcessor
③在springmvc中配置一下該bean對象.
<bean class="com.neuedu.spring.bean.Book" init-method="init"></bean> <bean id="myBeanPostProcessor" class="com.neuedu.spring.bean.MyBeanPostProcessor"></bean>
數據庫連接池:
6) 數據庫連接池
> 數據庫連接池就是存放數據庫連接(Connection)的集合
> 我們獲取一個數據庫連接是一個相對很麻煩的過程,
如果我們獲取一個數據庫連接,使用一次以後就給它關閉了
下一次再去使用的時候就要重新創建一個新的數據庫連接。
> 所以我們提出了一個數據庫連接池的概念,數據庫連接池放的都是數據庫連接(Connection)
我們在去使用數據庫連接時候,不用再去重新創建數據庫連接,而是直接從池中獲取,
使用完的數據庫連接,也不是直接銷毀,而是要放回到連接池。
>
數據庫連接池的常見的屬性:
初始連接數量:數據連接池創建以後,保存數據庫連接的數量[50]
最小空閑連接數:數據庫連接池最少得未使用的數據庫連接的數量[10]
最大空閑連接數:數據庫連接池最大閑置連接數,當閑置連接數滿了以後,將不會有其他連接進入池
每次增加連接數:當數據庫連接都被占用以後,一次性增加的數據庫連接的個數[20]
最大連接數:數據庫連接池的最大容量,當最大連接數飽和了,則不再創建新的數據庫連接[100]
最大等待時間:當數據庫連接池飽和以後,等待獲取數據庫連接的時間
> 常見的數據庫連接池
- 所有的數據庫連接池都需要實現DataSource,當使用數據庫連接池是,我們便不再需要使用DriverManger獲取數據庫連接
而是使用DataSource。
- Connection getConnection()
- 從數據庫連接池中獲取數據庫連接對象
1.DBCP
- DBCP是Apache出品的一款數據庫連接
- DBCP依賴於commons-pool
- 使用DBCP需要導入兩個jar包:
commons-dbcp-1.4.jar
commons-pool-1.5.5.jar
- 當我們通過數據庫連接池獲取數據庫連接以後,我們所獲取到數據庫連接已經不是我們熟悉的那個Connection
數據庫連接池對Connection對象進行了包裝,它修改Connection的close()方法,
再去調用close()數據庫連接將不會真的關閉,而是要放回到數據庫連接池中,供其他線程使用。
- 核心類:
BasicDataSourceFactory
2.C3P0(重點)
- C3P0使用的是XML作為配置文件
- 使用c3p0需要導入一個jar包:
c3p0-0.9.1.2.jar
- 導入c3p0的配置文件:
1.配置文件的名字:c3p0-cofig.xml
2.配置文件要求放到類路徑下(src)
- 核心類:
ComboPooledDataSource
- 註意:
DataSource就相當於池子,我們的數據庫連接都是從DataSource中獲取的,
如果程序中有多個DataSource的實例,那麽我們說你還不如不用數據庫連接池。
所以我們的DataSource在項目中應該只有一個實例。
實驗23:引用外部屬性文件★
jdbc.properties文件:
jdbc.user=root
jdbc.passowrd=123456
jdbc.url=jdbc:mysql://localhost:3306/test
jdbc.driver=com.mysql.jdbc.Driver
<context:property-placeholder location="classpath:jdbc.properties"/>
1.在目標屬性上加@Value註解
@Value("${jdbc.user}")
private String username;
2.
<!-- 根據外部屬性文件中的信息配置數據源 --> <bean id="comboPooledDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="user" value="${jdbc.user}"></property> <property name="password" value="${jdbc.passowrd}"></property> <property name="jdbcUrl" value="${jdbc.url}"></property> <property name="driverClass" value="${jdbc.driver}"></property> </bean> ComboPooledDataSource bean = ioc.getBean(ComboPooledDataSource.class); Connection connection = bean.getConnection(); System.out.println(connection); Statement st = connection.createStatement(); ResultSet rs = st.executeQuery("select * from stu"); while(rs.next()){ String string = rs.getString("name"); String string2 = rs.getString("school"); System.out.println(string+"==="+string2); }
實驗24:基於XML的屬性裝配
①手動裝配
<!-- 屬性的裝配:手動裝配 --> <bean id="userService" class="com.neuedu.spring.bean.UserService"></bean> <bean id="userAction" class="com.neuedu.spring.bean.UserAction"> <property name="userService" ref="userService"></property> </bean>
②自動裝配
<!-- 1.按類型裝配:byType --> <!-- 首先檢測當前bean中需要裝配的屬性的類型 --> <!-- 然後在IOC容器中查找匹配這個類型的bean --> <!-- 如果類型匹配的bean是唯一的,那麽就將這個匹配的bean註入到userAction中 --> <bean id="userService" class="com.neuedu.spring.bean.UserService"></bean> <bean id="userAction" autowire="byType" class="com.neuedu.spring.bean.UserAction"></bean> <!-- 2.按bean的id值裝配:byName --> <!-- 首先檢測當前bean中需要裝配的屬性的屬性名,屬性名是將setXxx()方法去掉set,首字母小寫得到的 --> <!-- 然後根據屬性名作為id的值,在IOC容器中查找對應的bean --> <!-- 如果能夠找到,則將找到bean註入進去 -->
6。SpEL簡介【見WORLD文檔---了解】
Spring Expression Language,Spring表達式語言,簡稱SpEL。支持運行時查詢並可以操作對象圖。
和JSP頁面上的EL表達式、Struts2中用到的OGNL表達式一樣,SpEL根據JavaBean風格的getXxx()、setXxx()方法定義的屬性訪問對象圖,完全符合我們熟悉的操作習慣。
6.1 基本語法
SpEL使用#{…}作為定界符,所有在大框號中的字符都將被認為是SpEL表達式。
6.2 使用字面量
●整數:<property name="count" value="#{5}"/>
●小數:<property name="frequency" value="#{89.7}"/>
●科學計數法:<property name="capacity" value="#{1e4}"/>
●String類型的字面量可以使用單引號或者雙引號作為字符串的定界符號
<property name=“name” value="#{‘Chuck‘}"/>
<property name=‘name‘ value=‘#{"Chuck"}‘/>
●Boolean:<property name="enabled" value="#{false}"/>
實驗25:[SpEL測試I]在SpEL中使用字面量
實驗26:[SpEL測試II]在SpEL中引用其他bean
實驗27:[SpEL測試III]在SpEL中引用其他bean的某個屬性值
實驗28:[SpEL測試IV]在SpEL中調用非靜態方法
實驗29:[SpEL測試V]在SpEL中調用靜態方法
實驗30:[SpEL測試VI]在SpEL中使用運算符
8.使用註解配置bean
①聲明bean的註解
@Component 將當前類聲明為IOC容器中的一個普通的組件
@Controller 將當前類聲明為IOC容器中的一個控制器組件
@Service 將當前類聲明為IOC容器中的業務邏輯層組件
@Repository 將當前類聲明為IOC容器中的一個持久化層組件
@ControllerAdvice
Spring根據上述註解其實並不能分辨當前類是否真的是一個控制器或Dao,即使標記的類和註解不對應也沒有語法錯誤。
但在實際工作中,肯定要將專門的註解標記在對應的類上面。
②使用基於註解的bean的配置,需要額外導入一個jar包:spring-aop-4.0.0.RELEASE.jar
③需要設置自動掃描的包
< context:component-scan base-package ="com.neuedu.ioc.bean"/>
④使用註解後,默認按照類名首字母小寫作為id的值,也可以使用value屬性指定id,value屬性名也可以省略註解
註解 | id值 |
@Component public class CommonComponent { } |
commonComponent |
@Controller(value="neueduBookAction" ) public class BookAction {
} |
neueduBookAction |
@Service("happyService" ) public class BookService {
} |
happyService |
實驗31:通過註解分別創建Dao、Service、Controller★
實驗32:使用context:include-filter指定掃描包時要包含的類
實驗33:使用context:exclude-filter指定掃描包時不包含的類
< context:component-scan base-package ="com.neuedu.ioc.bean"/>
[1]base-package屬性指定一個需要掃描的基類包,Spring容器將會掃描這個基類包及其子包中的所有類。
[2]當需要掃描多個包時可以使用逗號分隔,
[3]如果僅希望掃描特定的類而非基包下的所有類,可使用resource-pattern屬性過濾特定的類,示例:
<context:component-scan base-package="com.neuedu.component" resource-pattern="autowire/*.class"/>
[4]包含與排除
●<context:include-filter>子節點表示要包含的目標類
註意:通常需要與use-default-filters屬性配合使用才能夠達到“僅包含某些組件”這樣的效果。
即:通過將use-default-filters屬性設置為false,禁用默認過濾器,然後掃描的就只是include-filter中的規則
指定的組件了。
●<context:exclude-filter>子節點表示要排除在外的目標類
●component-scan下可以擁有若幹個include-filtejr和exclude-filter子節
⑤使用註解進行自動裝配:@Autowired註解[好處就是:連get、set方法都不用寫!]
[1]首先檢測標記了@Autowired註解的屬性的類型
[2]根據類型進行裝配
[3]如果指定類型的bean不止一個,那麽根據需要被裝配的屬性的屬性名做id的值,查找bean
[4]如果根據id值還是沒有找到bean,可以使用@Qualifier註解手動指定要裝配的bean的id.
實驗34:使用@Autowired註解實現根據類型實現自動裝配★
實驗34[補充1]:如果資源類型的bean不止一個,默認根據@Autowired註解標記的成員變量名作為id查找bean,進行裝配★
實驗34[補充2]:如果根據成員變量名作為id還是找不到bean,可以使用@Qualifier註解明確指定目標bean的id★
實驗36:Autowired註解的required屬性指定某個屬性允許不被設置.
實驗37:在類上使用註解@Scope可以指定對象是單實例還是多實例的!
Spring框架——關於IOC容器和註解的36個小實驗