IOC的單例模式--Bean
Spring中的bean是根據scope來決定的。
scope有4種類型:
1.singleton:單例模型,表示通過Spring容器獲取的該對象是唯一的。常用並且默認。
2.prototype:多例模型,表示通過Spring容器獲取的對象都是不同的(類似於Java基礎中new出來的對象地址是唯一的)。
3.reqeust:請求,表示在一次http請求內有效。
4.session:會話,表示在一個用戶會話內有效。
1.創建一個對象
public class User { private int id; private String name; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
2.在spring的l配置文件中將User的實例化。
<?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="user" class="com.test.entity.User"> <property name="id" value="1"></property> <property name="name" value="User1"></property> </bean> </beans>
3.測試類中通過Spring容器獲取兩個User實例化對象,並且通過==方法判斷是否為同一個對象。
public class Test { public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); User u1 = (User) applicationContext.getBean("user"); User u2 = (User) applicationContext.getBean("user"); System.out.println(u1 == u2); } }
總結:看到結果打印true,表示user1和user2是同一個對象,所以scope默認值為singleton(單例模式),也就是用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"> <bean id="user" class="com.test.entity.User" scope="prototype"> <property name="id" value="2"></property> <property name="name" value="User2"></property> </bean> </beans>
Spring的繼承
Spring的繼承,與Java的繼承不一樣,子bean和父bean的方法一樣,子bean可以繼承父bean中的屬性。
如果子bean繼承父bean,同時子bean給屬性賦值,那么會覆蓋掉父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="user" class="com.test.entity.User"> <property name="id" value="1"></property> <property name="name" value="張三1"></property> </bean> <bean id="user2" class="com.test.entity.User" parent="user"> <!-- 覆蓋掉user的name屬性值 --> <property name="name" value="張三2"></property> </bean>
</beans>
Spring的依賴
與繼承類似,依賴也是bean和bean之間的一種關聯方式,配置依賴關系后,被依賴的bean一定先創建,再創建依賴的bean。
使用的關鍵字是depends-on="被依賴的bean的id"
<?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"> <!-- user依賴於car --> <bean id="user" class="com.test.entity.User" depends-on="car"> <property name="id" value="1"></property> <property name="name" value="張三"></property> </bean> <bean id="car" class="com.test.entity.Car"> <property name="id" value="1"></property> <property name="brand" value="寶馬"></property> </bean> </beans>
上述代碼執行順序是:car-->user。先創建car,再創建user
Spring讀取外部資源。
在開發中,類似於數據庫等文件的配置會保存在一個properties文件中,便於維護,因此使用Spring需要來讀取數據源對象。
1.先創建一個peoperties文件在路徑下,具體位置根據項目需求來放置。
##key==value的形式
driverName = com.mysql.jdbc.Driver url = jdbc:mysql://localhost:3306/shop user = root pwd = root
2.spring的配置文件中配置數據源,這里用到的是C3P0數據源。
<?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-4.0.xsd"> <!-- 導入外部的資源文件 --> <context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder> <!-- 創建數據源 ,通過${}讀取資源文件中的數據,${}中填寫key,name中的值根據連接池的不同名字可能不同,盡量反編譯代碼去找一下對應的屬性名--> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="user" value="${user}"></property> <property name="password" value="${pwd}"></property> <property name="driverClass" value="${driverName}"></property> <property name="jdbcUrl" value="${url}"></property> </bean> </beans>
3.測試
public class Test { public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); DataSource ds = (DataSource) applicationContext.getBean("dataSource"); Connection conn = null; try { conn = ds.getConnection(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(conn); } }
IOC通過工廠方法創建對象
Spring中的IOC是典型的工廠模式,那么如何使用工廠模式來創建bean?
IOC通過工廠模式創建bean有兩種方式:
1.靜態工廠方法
2.實例工廠方法
靜態工廠實例化
1.先創建一個實體類
2.創建靜態工廠類,靜態工廠方法。
3.編寫Spring的配置文件
4.編寫測試類
1 //步驟1:創建一個實體類 2 public class Car { 3 private int num; 4 private String brand; 5 public int getNum() { 6 return num; 7 } 8 public void setNum(int num) { 9 this.num = num; 10 } 11 public String getBrand() { 12 return brand; 13 } 14 public void setBrand(String brand) { 15 this.brand = brand; 16 } 17 public Car(int num, String brand) { 18 super(); 19 this.num = num; 20 this.brand = brand; 21 } 22 public Car() { 23 super(); 24 } 25 @Override 26 public String toString() { 27 return "Car [num=" + num + ", brand=" + brand + "]"; 28 } 29 }
//步驟2:創建一個靜態類 public class StaticCarFactory { private static Map<Integer,Car> cars; //靜態代碼塊 static{ cars = new HashMap<Integer,Car>(); cars.put(1, new Car(1,"奧迪")); cars.put(2, new Car(2,"寶馬")); } //靜態方法 public static Car getCar(int num){ return cars.get(id); } }
<?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"> <!-- 配置靜態工廠創建car對象 --> <!-- factory-method:指向靜態方法 getCar() --> <bean id="car1" class="com.test.entity.StaticCarFactory" factory-method="getCar"> <!-- value為要生成的哪個對象的key --> <constructor-arg value="1"></constructor-arg> </bean> </beans>
//步驟4:測試類 public class Test { public static void main(String[] args) throws SQLException { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); Car car = (Car) applicationContext.getBean("car1"); System.out.println(car); } }
實例工廠方法
1.創建實例工廠類,工廠方法 。
2.spring的配置文件中配置bean。
3.在測試類中直接獲取car2對象。
//步驟1:創建實例工廠類 public class InstanceCarFactory { private Map<Integer,Car> cars; public InstanceCarFactory() { cars = new HashMap<Integer,Car>(); cars.put(1, new Car(1,"奧迪")); cars.put(2, new Car(2,"寶馬")); } public Car getCar(int num){ return cars.get(num); } }
<?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="carFactory" class="com.test.entity.InstanceCarFactory"></bean> <!-- 通過實例工廠對象創建car對象 factory-bean:放置實例化的工廠對象bean的id,然后再設置factory-method:調用方法 --> <bean id="car2" factory-bean="carFactory" factory-method="getCar"> <constructor-arg value="1"></constructor-arg> </bean> </beans>
測試類與靜態工程的方式一樣,並且結果也是生成key為1的car對象。
總結
兩種方式的區別:
(1)使用靜態工廠方法的方式創建car對象,不需要實例化工廠對象,因為靜態工廠的靜態方法,不需要創建對象即可調用。所以spring的配置文件只需要配置一個Car的bean,而不需要配置工廠bean。
(2)使用實例工廠方法創建car對象,必須先實例化工廠對象,因為調用的是非靜態方法,必須通過對象調用,不能直接通過類來調用,所以spring的配置文件中需要先配置工廠bean,再配置Car bean。
IOC的自動裝載
Spring框架提供了一種更加簡便的方式:自動裝載,不需要手動配置property,IOC容器會根據bean的配置自動選擇bean完成依賴注入(DI)。
自動裝載有兩種方式:
byName:通過屬性名自動裝載。
byType:通過屬性對應的數據類型自動裝載。
//先創建一個實體類,並且生成setter/getter方法和toString方法 public class Person { private int id; private String name; private Car car; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Car getCar() { return car; } public void setCar(Car car) { this.car = car; } @Override public String toString() { return "Person [id=" + id + ", name=" + name + ", car=" + car + "]"; } }
<?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"> <!-- 創建person對象時,沒有在property中配置car屬性 所以IOC容器會自動進行裝載 autowire="byName"表示通過匹配屬性名的方式去裝載對應的bean Person實體類中有car屬性,所以就將的bean注入到person中。 --> <bean id="p1" class="com.test.entity.Person" autowire="byName"> <property name="id" value="1"></property> <property name="name" value="ZhangSan"></property> </bean> <bean id="car1" class="com.test.entity.StaticCarFactory" factory-method="getCar"> <constructor-arg value="1"></constructor-arg> </bean> <!-- byType即通過屬性的數據類型來配置。 關鍵字:autowire="byType" --> <bean id="p2" class="com.test.entity.Person" autowire="byType"> <property name="id" value="1"></property> <property name="name" value="張三"></property> </bean> <bean id="car2" class="com.test.entity.StaticCarFactory" factory-method="getCar"> <constructor-arg value="1"></constructor-arg> </bean> </beans>
注意:
(1)使用了byType進行自動裝載,如果spring的配置文件中配置了兩個Car的bean,但是IOC容器不知道應該將哪一個bean裝載到person對象中,因此可能會報錯。所以在使用byType進行自動裝載時,spring的配置文件中只能配置一個Car的bean才能使用byType。
(2)通過property標簽手動進行屬性的注入優先級更高,若自動注入和手動配置兩種方式同時存在,則以property的配置為主。
所以在日常的代碼編寫過程中,盡量避免的使用byType去自動裝配。