一.概念
1.輕量級(jí)開(kāi)源框架;
2.簡(jiǎn)化企業(yè)級(jí)應(yīng)用而生;
3.是一個(gè)IOC(DI)依賴(lài)注入
和AOP(面向切面編程
)容器框架;
4.在IOC和AOP基礎(chǔ)上可以整合各種企業(yè)應(yīng)用的開(kāi)源框架和優(yōu)秀的第三方類(lèi)庫(kù)
二.配置eclipse
以下是不同的eclipse對(duì)應(yīng)的sts版本,請(qǐng)查看好自己的eclipse下載對(duì)應(yīng)的版本
eclipse-kepler.4.3.1–>springsource-tool-suite-RELEASE-e4.3.1-updatesite.zip
eclipse-Mars.4.5.1–>springsource-tool-suite-3.7.2RELEASE-e4.5.1-updatesite.zip
eclipse-Mars.4.5.2–>springsource-tool-suite-3.7.3RELEASE-e4.5.2-updatesite.zip
eclipse-neno.4.6–>springsource-tool-suite-3.7.3RELEASE-e4.6-updatesite.zip
我的版本是eclipse-Mars.4.5.2安裝完畢后,welcome頁(yè)面顯示Spring tool,但是在window->properties中卻沒(méi)有spring選項(xiàng),而且安裝完畢后在properties中連maven選項(xiàng)也不見(jiàn)了,這個(gè)問(wèn)題整整折騰了我半天時(shí)間,卸了裝,裝了卸還是不行,最后問(wèn)同事用的是eclipse-neno.4.6.3發(fā)行版,下載eclipse-neno.4.6.3
下載后打開(kāi),提示JDK環(huán)境必須是JDK1.8以上,于是從JDK1.7升級(jí)到JDK1.8,
安裝步驟如下:我用的是(springsource-tool-suite-3.8.4.RELEASE-e4.6.3-updatesite.zip
)下載地址:https://spring.io/tools/sts/all
安裝完畢后在window->Preperences中就可以看到spring選項(xiàng)了;
到此為止eclipse中spring插件配置結(jié)束,這個(gè)汗....
三.第一個(gè)helloWorld
下載spring最新穩(wěn)定版本,下載方式請(qǐng)查看:
http://www.cnblogs.com/yy3b2007com/p/6783699.html新建java下過(guò)目,spring-1
-
加載jar包(以下橙色背景的四個(gè)核心jar包必須加載)
spring-6.jpg 自己下載commons-logging.jar包并加載進(jìn)去
-
目錄結(jié)構(gòu):
spring-7.jpg HelloWorld內(nèi)容:
package com.lxf.spring.bean;
public class HelloWorld {
private String name;
public void setName(String name)
{
System.out.println("setName:"+name);
this.name = name;
}
public void hello()
{
System.out.println("hello: "+this.name);
}
public HelloWorld()
{
System.out.println("init HelloWorld...");
}
}
- Spring Bean Configuration File內(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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">
<!-- 配置bean -->
<bean id="helloWorld" class="com.lxf.spring.bean.HelloWorld">
<property name="name" value="zhangsan"></property>
</bean>
</beans>
- Main.java內(nèi)容
package com.lxf.spring.bean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args)
{
/*
HelloWorld helloworld = new HelloWorld();
helloworld.setName("liangxifeng");
*/
//1.創(chuàng)建spring的IOC容器對(duì)象
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//2.從IOC容器中獲取Bean實(shí)例
//HelloWorld helloworld = (HelloWorld)ctx.getBean("helloWorld");
//helloworld.setName("aaa");
//3.調(diào)用hello方法
// helloworld.hello();
}
}
四.IOC(inversion of Control)和 DI(Dependency Injection)
- IOC概念:
- 思想是
反轉(zhuǎn)資源獲取的方向
- 傳統(tǒng)的資源查找方式要求組件向容器發(fā)起請(qǐng)求查找資源.作為回應(yīng),容器實(shí)時(shí)的返回資源;
- 應(yīng)用了IOC之后,則是容器主動(dòng)地就將資源推送給它所管理的組件
- 組件所要做的只是選擇一種合適的方式來(lái)接收資源;(也稱(chēng)查找的被動(dòng)形式)
- DI概念
- IOC的另一種表達(dá)方式:即組件以一些預(yù)定義好的方式(例如:setter方法)接收來(lái)自容器的資源注入,相對(duì)IOC而言,這種表述更直接;
五.IOC的前生
ReprotService要想生成報(bào)表需要依賴(lài)三個(gè)類(lèi),
耦合度很高
.
使用工廠模式ReprotService要想生成報(bào)表需要依賴(lài)兩個(gè)類(lèi),
耦合度降低
.
使用反轉(zhuǎn)控制ReprotService要想生成報(bào)表需要依賴(lài)一個(gè)類(lèi),
耦合度最低
.
六.spring容器
在Spring IOC容器讀取Bean配置之前,自身要先實(shí)例化;
Spring提供了兩種類(lèi)型的IOC容器實(shí)現(xiàn);
(1). BeanFactory:IOC容器的基本實(shí)現(xiàn)(BeanFactory是spring框架的基礎(chǔ)設(shè)施,面向Spring本身)
(2). ApplicationContext 是BeanFactory的子接口,提供了更豐富的功能;(ApplicationContext 面向Spring框架的開(kāi)發(fā)者,幾乎所有應(yīng)用場(chǎng)合都直接使用ApplicationContext而非底層的BeanFactory)-
ApplicationContext有兩個(gè)實(shí)現(xiàn)類(lèi)
Paste_Image.png 屬性的注入方式一(setter方法)
<!--
配置bean
class:bean全類(lèi)名,通過(guò)反射的方式在IOC容器中創(chuàng)建Bean,所以要求Bean中必須有無(wú)參構(gòu)造器
id:標(biāo)識(shí)容器中的bean 必須唯一
-->
<bean id="helloWorld" class="com.lxf.spring.bean.HelloWorld">
<property name="name" value="zhangsan"></property>
</bean>
private String name;
public void setName(String name)
{
System.out.println("setName:"+name);
this.name = name;
}
- 屬性的注入方式二(構(gòu)造方法注入)
- 通過(guò)構(gòu)造方法注入Bean的屬性值或依賴(lài)的對(duì)象,它保證了Bean實(shí)例在實(shí)例化后就可以使用
- 構(gòu)造器注入在<constructor-arg>元素里聲明屬性,<constructor-arg>中沒(méi)有name屬性;
- 使用構(gòu)造器注入屬性值可以指定參數(shù)的位置和參數(shù)類(lèi)型,以區(qū)分重載構(gòu)造器
<!-- 通過(guò)構(gòu)造器的方式實(shí)現(xiàn)屬性注入,可以指定參數(shù)的位置和參數(shù)類(lèi)型,以區(qū)分重載構(gòu)造器-->
<bean id="car1" class="com.lxf.spring.bean.Car">
<constructor-arg value="汽車(chē)1" index="0" type="java.lang.String"></constructor-arg>
<constructor-arg value="150000" index="1" type="double"></constructor-arg>
</bean>
<!-- 通過(guò)構(gòu)造器的方式實(shí)現(xiàn)屬性注入,可以指定參數(shù)的位置和參數(shù)類(lèi)型,以區(qū)分重載構(gòu)造器 -->
<bean id="car2" class="com.lxf.spring.bean.Car">
<constructor-arg value="汽車(chē)2" index="0" type="java.lang.String"></constructor-arg>
<constructor-arg value="120" index="1" type="int"></constructor-arg>
</bean>
以上兩個(gè)bean,根據(jù)參數(shù)類(lèi)型區(qū)分實(shí)例化的時(shí)候調(diào)用哪個(gè)構(gòu)造器
Bean類(lèi)Car
package com.lxf.spring.bean;
public class Car {
private String cName;
private double price;
private int speed;
/**
* 構(gòu)造器,為汽車(chē)名字和汽車(chē)價(jià)格屬性初始化值
* @param cName
* @param price
*/
public Car(String cName, double price) {
super();
this.cName = cName;
this.price = price;
}
/**
* 重載構(gòu)造器,為汽車(chē)名字和汽車(chē)速度初始化值
* @param cName
* @param speed
*/
public Car(String cName, int speed) {
super();
this.cName = cName;
this.speed = speed;
}
@Override
public String toString() {
return "Car [cName=" + cName + ", price=" + price + ", speed=" + speed + "]";
}
}
測(cè)試:
Car car = (Car) ctx.getBean("car1");
System.out.println(car);
Car car = (Car) ctx.getBean("car2");
System.out.println(car);
輸出:
Car [cName=汽車(chē)1, price=150000.0, speed=0]
Car [cName=汽車(chē)2, price=0.0, speed=120]
- 屬性值也可以使用value子結(jié)點(diǎn)進(jìn)行那個(gè)配置(字面值)
<!-- 使用value子結(jié)點(diǎn)進(jìn)行配置value值,如果value值包含特殊字符,則使用<![CDATA[]]包裹起來(lái) -->
<bean id="car1-1" class="com.lxf.spring.bean.Car">
<constructor-arg index="0" type="java.lang.String">
<value><![CDATA[<汽車(chē)1-1*>]]></value>
</constructor-arg>
<constructor-arg value="150000" index="1" type="double"></constructor-arg>
</bean>
Car car3 = (Car) ctx.getBean("car1-1");
System.out.println(car3);
輸出:
Car [cName=<汽車(chē)1-1*>, price=150000.0, speed=0]
- bean之間的相關(guān)互引用
person類(lèi)
package com.lxf.spring.bean;
public class Person {
//姓名
private String name;
//年齡
private int age;
//該人所擁有的汽車(chē)
private Car car;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Car getCar() {
return car;
}
public void setCar(Car car) {
this.car = car;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + ", car=" + car + "]";
}
}
配置bean文件:
<bean id="car1" class="com.lxf.spring.bean.Car">
<constructor-arg value="汽車(chē)1" index="0" type="java.lang.String"></constructor-arg>
<constructor-arg value="150000" index="1" type="double"></constructor-arg>
</bean>
<bean id="persion" class="com.lxf.spring.bean.Person">
<property name="name" value="lisi"></property>
<property name="age" value="28"></property>
<!-- 使用property的ref屬性建立bean之間的引用關(guān)系 -->
<!-- <property name="car" ref="car1"></property>-->
<!-- 和上面等效 -->
<!--
<property name="car">
<ref bean="car1"/>
</property>-->
<!-- 使用內(nèi)部bean,等效與以上,內(nèi)部bean不能被外部訪(fǎng)問(wèn) -->
<property name="car">
<bean class="com.lxf.spring.bean.Car">
<constructor-arg value="汽車(chē)1" index="0" type="java.lang.String"></constructor-arg>
<constructor-arg value="150000" index="1" type="double"></constructor-arg>
</bean>
</property>
七.級(jí)聯(lián)屬性賦值
<bean id="car" class="com.lxf.spring.bean.Car">
<constructor-arg value="汽車(chē)2" index="0" type="java.lang.String"></constructor-arg>
<constructor-arg value="120" index="1" type="int"></constructor-arg>
</bean>
<bean id="persion2" class="com.lxf.spring.bean.Person">
<constructor-arg value="wangwu"></constructor-arg>
<constructor-arg value="30"></constructor-arg>
<!-- 測(cè)試賦值null
<constructor-arg><null/></constructor-arg>-->
<constructor-arg ref="car"></constructor-arg>
<!-- 級(jí)聯(lián)屬性賦值 -->
<property name="car.price" value="12"></property>
</bean>
八.集合屬性賦值
(1)List類(lèi)型配置
Person類(lèi)中有屬性
//該人所擁有的汽車(chē)集合
private List<Car> cars;
public List<Car> getCars() {
return cars;
}
public void setCars(List<Car> cars) {
this.cars = cars;
}
spring配置bean
<!-- 通過(guò)構(gòu)造器的方式實(shí)現(xiàn)屬性注入,可以指定參數(shù)的位置和參數(shù)類(lèi)型,以區(qū)分重載構(gòu)造器-->
<bean id="car1" class="com.lxf.spring.bean.Car">
<constructor-arg value="汽車(chē)1" index="0" type="java.lang.String"></constructor-arg>
<constructor-arg value="150000" index="1" type="double"></constructor-arg>
</bean>
<!-- 通過(guò)構(gòu)造器的方式實(shí)現(xiàn)屬性注入,可以指定參數(shù)的位置和參數(shù)類(lèi)型,以區(qū)分重載構(gòu)造器 -->
<bean id="car2" class="com.lxf.spring.bean.Car">
<constructor-arg value="汽車(chē)2" index="0" type="java.lang.String"></constructor-arg>
<constructor-arg value="120" index="1" type="int"></constructor-arg>
</bean>
<!--集合屬性賦值 -->
<bean id="person3" class="com.lxf.spring.bean.Person">
<constructor-arg value="wangwu--1"></constructor-arg>
<constructor-arg value="30"></constructor-arg>
<constructor-arg><null/></constructor-arg>
<property name="cars">
<list>
<ref bean="car1"/>
<ref bean="car2"/>
</list>
</property>
</bean>
(2)Map類(lèi)型屬性賦值
Person類(lèi)中的屬性
//map類(lèi)型的汽車(chē)
private Map<String,Car> mapCars;
public Map<String, Car> getMapCars() {
return mapCars;
}
public void setMapCars(Map<String, Car> mapCars) {
this.mapCars = mapCars;
}
Spring配置
<!-- 集合map屬性賦值 -->
<bean id="person4" class="com.lxf.spring.bean.Person" >
<constructor-arg value="趙六"></constructor-arg>
<constructor-arg value="33"></constructor-arg>
<constructor-arg><null/></constructor-arg>
<property name="mapCars">
<!-- 使用map節(jié)點(diǎn)以及map節(jié)點(diǎn)子節(jié)entry配置 map類(lèi)型的屬性 -->
<map>
<entry key="AA" value-ref="car1"></entry>
<entry key="BB" value-ref="car2"></entry>
</map>
</property>
</bean>
(3)Properites屬性賦值
DataSource實(shí)體類(lèi)
package com.lxf.spring.bean;
import java.util.Properties;
public class DataSource {
private Properties properties;
public Properties getProperties() {
return properties;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
@Override
public String toString() {
return "DataSource [properties=" + properties + "]";
}
}
(4)使用Utility scheme定義集合
使用Utility schema里的集合標(biāo)簽定義獨(dú)立的集合Bean,必須在Bean根元素里面定義;
這樣定義的集合就可以被其他Bean共享
注意:需要導(dǎo)入util命名空間
Person實(shí)體類(lèi)屬性
//該人所擁有的汽車(chē)集合
private List<Car> cars;
public List<Car> getCars() {
return cars;
}
public void setCars(List<Car> cars) {
this.cars = cars;
}
Spring配置
<!-- 配置單獨(dú)的集合bean,以供多個(gè)bean進(jìn)行引用,注意:需要導(dǎo)入util命名空間 -->
<util:list id="cars">
<ref bean="car1"/>
<ref bean="car2"/>
</util:list>
<bean id="person5" class="com.lxf.spring.bean.Person">
<constructor-arg value="小青"></constructor-arg>
<constructor-arg value="33"></constructor-arg>
<constructor-arg><null/></constructor-arg>
<property name="cars" ref="cars"></property>
</bean>
從Spring2.5起可以使用P命名空間為bean屬性賦值
Spring配置(注意:需導(dǎo)入 p 命名空間,導(dǎo)入方式類(lèi)似util命名空間)
<!-- 通過(guò) p 命名空間為bean屬性賦值,需要先導(dǎo)入 p 命名空間,相對(duì)于傳統(tǒng)方式更加簡(jiǎn)潔 -->
<bean id="person6" class="com.lxf.spring.bean.Person" p:age="29" p:name="小網(wǎng)" p:cars-ref="cars"></bean>
九.bean的自動(dòng)裝配
使用autowire屬性指定自動(dòng)裝配的方式,
(1) byName根據(jù)其他bean的id值和當(dāng)前bean的setter風(fēng)格屬性名進(jìn)行自動(dòng)裝配,如果沒(méi)有匹配的bean則不裝配
(2)byType根據(jù)其他bean的類(lèi)型和當(dāng)前bean屬性的類(lèi)型進(jìn)行自動(dòng)裝配,若IOC容器中有一個(gè)以上的類(lèi)型匹配的bean,則拋異常
<bean id="address" class="com.lxf.spring.autowire.Address" p:city="Beijing" p:street="huilongguan">
</bean>
<bean id="car" class="com.lxf.spring.autowire.Car" p:brand="Audi" p:price="300000"></bean>
<!-- 使用autowire屬性指定自動(dòng)裝配的方式,
byName根據(jù)其他bean的id值和當(dāng)前bean的setter風(fēng)格屬性名進(jìn)行自動(dòng)裝配,如果沒(méi)有匹配的bean則不裝配
byType根據(jù)其他bean的類(lèi)型和當(dāng)前bean屬性的類(lèi)型進(jìn)行自動(dòng)裝配,若IOC容器中有一個(gè)以上的類(lèi)型匹配的bean,則拋異常 -->
<bean id="person" class="com.lxf.spring.autowire.Person" p:name="zs" autowire="byType"></bean>
自動(dòng)裝配缺點(diǎn):
(1)如果使用autowire屬性自動(dòng)裝配,那么只要使用autowire的bean中引用其他bean屬性的值都自動(dòng)裝載,不能指定某一個(gè)或幾個(gè)屬性使用自動(dòng)裝載;
(2)自動(dòng)裝載byType方式,如果一個(gè)Spring配置文件中有多個(gè)引用類(lèi)型,則該方式會(huì)不知道裝載哪個(gè),會(huì)拋出異常;
所以在平時(shí)開(kāi)發(fā)中盡量使用手動(dòng)配置,整合其他框架的時(shí)候才使用自動(dòng)裝載
十.Bean之間的關(guān)系繼承
- Spring允許繼承Bean的配置,稱(chēng)為父Bean和子Bean;
- 子Bean從父Bean中繼承配置,包括Bean的屬性配置;
- 子Bean也可以覆蓋父Bean繼承來(lái)的配置;
- 父Bean可以作為配置模板,也可以作為Bean實(shí)例,可以設(shè)置<bean>的abstract屬性為true,這樣Spring將不會(huì)實(shí)例化這個(gè)Bean;
- 并不是Bean元素里面的所有屬性都會(huì)被繼承,比如:autowire abstract等不會(huì)被繼承
- 也可以忽略父Bean的class屬性,讓子Bean指定自己的類(lèi),而共享相同屬性配置,但此時(shí)
abstract必須設(shè)為true
<?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">
<!-- 屬性abstract=true代表設(shè)置該bean為模板(不能被容器實(shí)例化),如果為模板則不需要配置 -->
<bean id="address1" class="com.lxf.spring.autowire.Address" p:city="Beijing" p:street="wudaokou" abstract="true"></bean>
<!-- 使用parent屬性繼承其他bean配置 -->
<bean id="address2" p:street="dazhongsi" parent="address1"></bean>
</beans>
十一.Bean之間的關(guān)系依賴(lài)
- 使用depends-on屬性設(shè)定Bean前置依賴(lài)的Bean,前置依賴(lài)的Bean會(huì)在本Bean實(shí)例化之前創(chuàng)建好;
- 如果前置依賴(lài)多個(gè)Bean,則可以通過(guò)逗號(hào),空格或的方式配置Bean的名稱(chēng);
<bean id="car" class="com.lxf.spring.autowire.Car"></bean>
<!-- 使用depends-on屬性設(shè)定Bean前置依賴(lài)的Bean,必須提前配置car的bean -->
<bean id="person" class="com.lxf.spring.autowire.Person" p:name="zs" depends-on="car" p:car-ref="car"></bean>
十二.Bean的作用域
-
默認(rèn)單例: bean屬性scope=singleton(默認(rèn)值),IOC容器初始化的時(shí)創(chuàng)建bean實(shí)例,在整個(gè)容器的生命周期內(nèi)只創(chuàng)建一個(gè)bean,單例的; 比如:
Car類(lèi)有無(wú)參構(gòu)造器:
public class Car {
private String brand;
private double price;
public Car()
{
System.out.println("Car is Constract...");
}
}
Spring配置
<!--
使用bean的scope屬性配置bean的作用域,scope值如下:
singleton:默認(rèn)值,IOC容器初始化的時(shí)創(chuàng)建bean實(shí)例,在整個(gè)容器的生命周期內(nèi)只創(chuàng)建一個(gè)bean,單例的;
-->
<bean id="car" class="com.lxf.spring.autowire.Car" p:brand="Audi" p:price="300000" scope="singleton"></bean>
main方法測(cè)試:
//創(chuàng)建spring的IOC容器對(duì)象
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans-scope.xml");
輸出:
Car is Constract...
證明容器在初始化的時(shí)候創(chuàng)建單例bean;
main方法測(cè)試:
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans-scope.xml");
Car car1 = (Car)ctx.getBean("car");
Car car2 = (Car)ctx.getBean("car");
System.out.println(car1==car2);//輸出true
以上car1=car2,證明每次調(diào)用bean的使用都是
-
多例: bean屬性scope=prototype(原型的),IOC容器初始化時(shí)不創(chuàng)建bean實(shí)例,而在每次請(qǐng)求時(shí)都創(chuàng)建一個(gè)新的Bean實(shí)例,并返回,比如:
修改上面的Spring配置
<!--
使用bean的scope屬性配置bean的作用域,scope值如下:
singleton:默認(rèn)值,IOC容器初始化的時(shí)創(chuàng)建bean實(shí)例,在整個(gè)容器的生命周期內(nèi)只創(chuàng)建一個(gè)bean,單例的;
prototype:原型的,IOC容器初始化時(shí)不創(chuàng)建bean實(shí)例,而在每次請(qǐng)求時(shí)都創(chuàng)建一個(gè)新的Bean實(shí)例,并返回;
-->
<bean id="car" class="com.lxf.spring.autowire.Car" p:brand="Audi" p:price="300000" scope="prototype"></bean>
main方法測(cè)試:
//創(chuàng)建spring的IOC容器對(duì)象
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans-scope.xml"); //不創(chuàng)建bean實(shí)例
Car car1 = (Car)ctx.getBean("car"); //創(chuàng)建一個(gè)bean實(shí)例
Car car2 = (Car)ctx.getBean("car");//再次創(chuàng)建一個(gè)bean實(shí)例
System.out.println(car1==car2);//返回false
十三.配置bean中使用外部屬性文件
- 首先在Spring配置文件中打開(kāi)context命名空間;
- src下新建db.properties屬性配置文件
userName=root
pass=123456
driverClass=com.mysql.jdbc.Driver
jdbcUrl=jdbc:mysql:///test
- 在Spring配置文件(beans-properties.xml)中引用該配置文件中的屬性變量
<!-- 導(dǎo)入屬性文件 classpath代表類(lèi)路徑 -->
<context:property-placeholder location="classpath:db.properties"/>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<!-- 使用外部屬性文件的屬性 -->
<property name="user" value="${userName}"></property>
<property name="password" value="${pass}"></property>
<property name="driverClass" value="${driverClass}"></property>
<property name="jdbcUrl" value="${jdbcUrl}"></property>
</bean>
- main方法測(cè)試:
//1.創(chuàng)建spring的IOC容器對(duì)象
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans-properties.xml");
//獲取數(shù)據(jù)源
DataSource dataSource = (DataSource)ctx.getBean("dataSource");
//打印數(shù)據(jù)庫(kù)連接
System.out.println(dataSource.getConnection());
輸出結(jié)果:
com.mchange.v2.c3p0.impl.NewProxyConnection@ee3d0a5
- 以上測(cè)試需要加入:
c3p0-0.9.1.2.jar
和jdbc jar包
,其中C3P0是一個(gè)開(kāi)源的JDBC連接池
十四.Spring的spel表達(dá)式
<bean id="address" class="com.lxf.spring.spel.Address">
<property name="city" value="#{'北京'}"></property>
<property name="street" value="五道口"></property>
</bean>
<bean id="car" class="com.lxf.spring.spel.Car">
<property name="brand" value="Audi"></property>
<property name="price" value="500000"></property>
<!-- 使用SPEL引用類(lèi)的靜態(tài)屬性,并在SPEL表達(dá)式中進(jìn)行計(jì)算 -->
<property name="tyrePerimeter" value="#{T(java.lang.Math).PI*80}"></property>
</bean>
<bean id="person" class="com.lxf.spring.spel.Person">
<property name="name" value="張三"></property>
<!-- 使用spel來(lái)引用其他bean -->
<property name="car" value="#{car}"></property>
<!-- 使用spel來(lái)引用其他bean屬性 -->
<property name="city" value="#{address.city}"></property>
<!-- 在spel中使用運(yùn)算符 -->
<property name="work" value="#{car.price>300000 ? '金領(lǐng)' : '白領(lǐng)'}"></property>
</bean>
十五.IOC容器中Bean的生命周期
舉例如下:
(1)Car實(shí)體類(lèi):
package com.lxf.spring.cycle;
/**
* 汽車(chē)實(shí)體類(lèi)
* @author lxf
*/
public class Car {
private String brand;
private double price;
//輪胎周長(zhǎng)
private double tyrePerimeter;
/**
* 無(wú)參數(shù)構(gòu)造器
*/
public Car()
{
System.out.println("Car is Constract...");
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
System.out.println("setBrand為品牌屬性賦值");
this.brand = brand;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public double getTyrePerimeter() {
return tyrePerimeter;
}
public void setTyrePerimeter(double tyrePerimeter) {
this.tyrePerimeter = tyrePerimeter;
}
@Override
public String toString() {
return "Car [brand=" + brand + ", price=" + price + ", tyrePerimeter=" + tyrePerimeter + "]";
}
/**
* Bean初始化方法,在IOC容器啟動(dòng)的時(shí)候調(diào)用
*/
public void myInit()
{
System.out.println("創(chuàng)建了IOC容器:調(diào)用Bean的初始化方法");
}
/**
* Bean銷(xiāo)毀方法,在IOC容器關(guān)閉的時(shí)候調(diào)用
*/
public void myDestroy()
{
System.out.println("調(diào)用Bean的銷(xiāo)毀方法,IOC容器關(guān)閉了");
}
}
(2)Spring配置文件(beans-cycle.xml)
<!--
bean的init-method屬性調(diào)用對(duì)應(yīng)類(lèi)中的自定義方法myInit方法,在IOC容器創(chuàng)建的時(shí)候執(zhí)行
bean的destroy-method屬性調(diào)用對(duì)應(yīng)類(lèi)中的自定義方法myDestroy,在IOC容器關(guān)閉的時(shí)候執(zhí)行
-->
<bean id="car" class="com.lxf.spring.cycle.Car"
init-method="myInit"
destroy-method="myDestroy">
<property name="brand" value="Audi"></property>
</bean>
(3)main方法測(cè)試
//創(chuàng)建spring的IOC容器對(duì)象
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("beans-cycle.xml");
Car car1 = (Car)ctx.getBean("car");
System.out.println("使用Bean: "+car1);
//關(guān)閉IOC容器
ctx.close();
輸出結(jié)果如下:
Car is Constract...
setBrand為品牌屬性賦值
創(chuàng)建了IOC容器:調(diào)用Bean的初始化方法
使用Bean: Car [brand=Audi, price=0.0, tyrePerimeter=0.0]
...
調(diào)用Bean的銷(xiāo)毀方法,IOC容器關(guān)閉了
修改以上代碼加入后置處理器bean的生命周期:
(1)新建后置處理器MyBeanPostProcessor
package com.lxf.spring.cycle;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class MyBeanPostProcessor implements BeanPostProcessor {
/**
* bean的init-method方法之后調(diào)用
* 參數(shù):
* bean: IOC傳遞進(jìn)來(lái)的bean實(shí)例
* beanName:bean的id
*/
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
// TODO Auto-generated method stub
if("car".equals(beanName))
{
System.out.println("bean的init-method方法之后調(diào)用:"+bean);
}
return bean;
}
/*
* bean的init-method方法之前調(diào)用
* 參數(shù):
* bean: IOC傳遞進(jìn)來(lái)的bean實(shí)例
* beanName:bean的id
*/
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
// TODO Auto-generated method stub
if("car".equals(beanName))
{
System.out.println("bean的init-method方法之前調(diào)用:"+bean);
Car car = new Car();
car.setBrand("大眾");
//對(duì)bean重新賦值
bean = car;
}
return bean;
}
}
(2)Spring配置文件beans-cycle.xml修改
<!--
bean的init-method屬性調(diào)用對(duì)應(yīng)類(lèi)中的自定義方法myInit方法,在IOC容器創(chuàng)建的時(shí)候執(zhí)行
bean的destroy-method屬性調(diào)用對(duì)應(yīng)類(lèi)中的自定義方法myDestroy,在IOC容器關(guān)閉的時(shí)候執(zhí)行
-->
<bean id="car" class="com.lxf.spring.cycle.Car"
init-method="myInit"
destroy-method="myDestroy">
<property name="brand" value="Audi"></property>
</bean>
<!-- 配置bean的后置處理器: 不需要配置id, IOC容器自動(dòng)識(shí)別 -->
<!--
實(shí)現(xiàn)BeanPostProcessor接口,并具體實(shí)現(xiàn)
postProcessBeforeInitialization(Object bean, String beanName):init-method之前被調(diào)用
postProcessAfterInitialization(Object bean, String beanName) :init-method之后被調(diào)用
以上兩個(gè)方法參數(shù):
bean: bean實(shí)例本身
beanName: IOC容器配置的bean的id
以上兩個(gè)方法返回值:
實(shí)際上返回給用戶(hù)的那個(gè)Bean,注意:可以在以上兩個(gè)方法中修改返回的Bean,甚至返回一個(gè)新Bean
-->
<bean class="com.lxf.spring.cycle.MyBeanPostProcessor"></bean>
(3)main方法測(cè)試:
//創(chuàng)建spring的IOC容器對(duì)象
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("beans-cycle.xml");
Car car1 = (Car)ctx.getBean("car");
System.out.println("使用Bean: "+car1);
//關(guān)閉IOC容器
ctx.close();
輸出結(jié)果:
Car is Constract...
setBrand為品牌屬性賦值
bean的init-method方法之前調(diào)用:Car [brand=Audi, price=0.0, tyrePerimeter=0.0]
Car is Constract...
setBrand為品牌屬性賦值
創(chuàng)建了IOC容器:調(diào)用Bean的初始化方法
bean的init-method方法之后調(diào)用:Car [brand=大眾, price=0.0, tyrePerimeter=0.0]
使用Bean: Car [brand=大眾, price=0.0, tyrePerimeter=0.0]
調(diào)用Bean的銷(xiāo)毀方法,IOC容器關(guān)閉了
十六.使用工廠方法創(chuàng)建Bean
舉例:
(1)新建靜態(tài)工廠方法類(lèi):StaticFactory
package com.lxf.spring.factory;
import java.util.HashMap;
import java.util.Map;
/**
* 靜態(tài)工廠方法:直接調(diào)用某一個(gè)類(lèi)的靜態(tài)方法可以返回Bean實(shí)例
* @author lxf
*
*/
public class StaticFactory {
private static Map<String,Car> cars = new HashMap<String,Car>();
static{
cars.put("audi", new Car("audi"));
cars.put("ford", new Car("ford"));
}
/**
* 靜態(tài)工廠方法返回對(duì)應(yīng)Bean實(shí)例
* @param name
* @return
*/
public static Car getCar(String name)
{
return cars.get(name);
}
}
(2)Spring配置文件beans-factory.xml
<!-- 通過(guò)靜態(tài)方法工廠配置bean, 注意不是配置靜態(tài)方法實(shí)例,而是bean實(shí)例 -->
<!--
class屬性:指向靜態(tài)工廠方法的全類(lèi)名
factory-method屬性:指向靜態(tài)工廠方法名
constructor-arg標(biāo)簽:如果工廠方法需要傳入?yún)?shù),則使用constructor-arg標(biāo)簽來(lái)配置
-->
<bean id="car1"
class="com.lxf.spring.factory.StaticFactory"
factory-method="getCar">
<constructor-arg value="audi" /></bean>
(3)man方法測(cè)試:
//創(chuàng)建spring的IOC容器對(duì)象
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("beans-factory.xml");
Car car1 = (Car)ctx.getBean("car1");
System.out.println("使用Bean: "+car1);
輸出:
使用Bean: Car [brand=audi, price=0.0, tyrePerimeter=0.0]
舉例:
(1)新建實(shí)例工廠方法類(lèi):InstanceFactory
package com.lxf.spring.factory;
import java.util.HashMap;
import java.util.Map;
/**
* 實(shí)例工廠方法:實(shí)例工廠的方法,即先需要?jiǎng)?chuàng)建工廠本身實(shí)例,
* 再調(diào)用工廠的實(shí)例方法來(lái)返回bean的實(shí)例.
* @author lxf
*/
public class InstanceFactory {
private Map<String,Car> cars = null;
public InstanceFactory()
{
cars = new HashMap<String,Car>();
cars.put("audi", new Car("audi"));
cars.put("ford", new Car("ford"));
}
public Car getCar(String name)
{
return cars.get(name);
}
}
(2)Spring配置文件(beans-factory.xml)
<!-- 先創(chuàng)建工廠實(shí)例本身 -->
<bean id="factory" class="com.lxf.spring.factory.InstanceFactory"></bean>
<!-- 在通過(guò)實(shí)例工廠方法配置bean實(shí)例 -->
<!--
factory-bean屬性:指向?qū)嵗S方法的bean
factory-method屬性:指向?qū)嵗龔S方法名
constructor-arg標(biāo)簽:如果工廠方法需要傳入?yún)?shù),則使用constructor-arg標(biāo)簽來(lái)配置
-->
<bean id="car2" factory-bean="factory" factory-method="getCar">
<constructor-arg value="ford"></constructor-arg>
</bean>
(3)mani方法測(cè)試:
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("beans-factory.xml");
Car car2 = (Car)ctx.getBean("car2");
System.out.println("使用Bean: "+car2);
輸出:
使用Bean: Car [brand=ford, price=0.0, tyrePerimeter=0.0]
使用FactoryBean的方式配置Bean
- 其實(shí)就是自己定義一個(gè)類(lèi),實(shí)現(xiàn)Spring的FactoryBean接口,實(shí)現(xiàn)該接口的三個(gè)方法即可;(其中有一個(gè)方法返回Bean實(shí)例)
package com.lxf.spring.factorybean;
import org.springframework.beans.factory.FactoryBean;
/**
* 通過(guò)FactoryBean的方式配置Bean,需要實(shí)現(xiàn)FactoryBean接口
* @author lxf
* @param <T>
*/
public class CarFactoryBean<T> implements FactoryBean<T> {
private String brand;
public void setBrand(String brand) {
this.brand = brand;
}
@Override
/**
* 返回bean對(duì)象
*/
public T getObject() throws Exception {
// TODO Auto-generated method stub
return (T) new Car(brand,5000000);
}
@Override
/**
* 返回Bean類(lèi)型
*/
public Class<?> getObjectType() {
// TODO Auto-generated method stub
return Car.class;
}
@Override
/**
* 是否是單例
*/
public boolean isSingleton() {
// TODO Auto-generated method stub
return true;
}
}
- 在Spring配置文件中beans-facotrybean.xml中配置自己定義的類(lèi)
<!--
通過(guò)FactoryBean類(lèi)配置Bean的實(shí)例
class:指向FactoryBean的全類(lèi)名
property:配置FactoryBean的屬性
但實(shí)際返回的實(shí)例確實(shí)FacboryBean的getObject()方法返回的實(shí)例
-->
<bean id="car" class="com.lxf.spring.factorybean.CarFactoryBean">
<property name="brand" value="BMW"></property>
</bean>
- main方法測(cè)試:
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("beans-factorybean.xml");
Car car1 = (Car)ctx.getBean("car");
System.out.println("使用Bean: "+car1);
輸出:
使用Bean: Car [brand=BMW, price=5000000.0, tyrePerimeter=0.0]
使用注解的方式配置bean
注意:需要引入spring-aop-4.3.9.RELEASE.jar
Spring配置文件beans-annotation.xml配置
<!--
指定Spring IOC容器的掃描包,IOC容器在啟動(dòng)的時(shí)候,
會(huì)掃表base-package指定的當(dāng)前包以及子包下所有包含指定注解的bean,并將其實(shí)例
可通過(guò)resource-pattern="repository/*.class"指定掃描資源
<context:component-scan
base-package="com.spring.beans.annotation"
resource-pattern="repository/*.class">
</context:component-scan> -->
<!-- 排除指定注解下的目標(biāo)類(lèi)
<context:component-scan
base-package="com.spring.beans.annotation" >
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
</context:component-scan>-->
<!-- 包含指定注解下的目標(biāo)類(lèi) context:include-filter要和use-default-filters屬性配合使用(默認(rèn)掃描所有相關(guān)注解)
<context:component-scan
base-package="com.spring.beans.annotation" use-default-filters="false" >
<context:include-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
</context:component-scan>-->
<!-- 排除指定類(lèi)bean的加載
<context:component-scan
base-package="com.spring.beans.annotation" >
<context:exclude-filter type="assignable" expression="com.spring.beans.annotation.repository.UserRepositoryImpl"/>
</context:component-scan>-->
<!-- 包含指定類(lèi)bean的加載 context:include-filter需要和use-default-filter屬性配合使用-->
<context:component-scan
base-package="com.spring.beans.annotation" use-default-filters="false">
<context:include-filter type="assignable" expression="com.spring.beans.annotation.repository.UserRepositoryImpl"/>
</context:component-scan>
以上目錄結(jié)構(gòu):
src
|__com.spring.beans.annotation
| |__Main.java
| |__TestObject.java
| |__service
| |__UserService.java
| |__respository
| |__UserRespository.java
| |__controller
| |__UserController.java
|__beans.annotation.xml
UserService.java類(lèi)帶有@Service注解
package com.spring.beans.annotation.service;
import org.springframework.stereotype.Service;
@Service
public class UserService {
public void add()
{
System.out.println("UserService add...");
}
}
其他User*.java分別帶有如下注解
@Repository("userRepository")
@Controller
@Repository("userRepository"
Bean之間屬性互相依賴(lài)的解決方案:
package com.spring.beans.annotation.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import com.spring.beans.annotation.TestObject;
import com.spring.beans.annotation.repository.UserRepository;
import com.spring.beans.annotation.service.UserService;
@Controller
public class UserController {
@Autowired
private UserService userService;
@Autowired
//如果IOC容器中存在多個(gè)UserRepository接口的實(shí)現(xiàn)類(lèi),
//可以指定具體裝在哪個(gè)實(shí)現(xiàn)類(lèi),注意首字母小寫(xiě)(spring規(guī)定)
@Qualifier("jdbcRespository")
private UserRepository userRepository;
//如果IOC容器中沒(méi)有testObj這個(gè)bean,則使用@Autowired(required=false,否則異常
@Autowired(required=false)
private TestObject testObj;
public void execute()
{
System.out.println("UserControler execute...");
userService.add();
}
}
十七.Spring4.* 泛型的依賴(lài)注入
在實(shí)際開(kāi)發(fā)中,往往我們可以將一些結(jié)構(gòu)職能相似的類(lèi)抽象出一定的泛型超類(lèi)。這樣相應(yīng)結(jié)構(gòu)中的類(lèi)之間的依賴(lài)關(guān)系我們可以通過(guò)泛型超類(lèi)來(lái)建立,而其他的子類(lèi)只要繼承了它們,就能夠建立相應(yīng)的依賴(lài)關(guān)系:
參考鏈接:https://my.oschina.net/happyBKs/blog/482508