Spring深入淺出(二)IOC的單例 ,繼承,依賴,JDBC,工廠模式以及自動裝載


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去自動裝配。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM