Spring依賴注入原理學習

梧桐雨—168發表於2008-03-26
首先我們來看看 Spring 參考文件的 11.2.6. 執行SQL語句 這裡有個程式碼片斷:

import javax.sql.DataSource;
      import org.springframework.jdbc.core.JdbcTemplate;
      public class ExecuteAStatement {
          private JdbcTemplate jt;
            
        private DataSource dataSource;
          public void doExecute() {
                
        jt = new JdbcTemplate(dataSource);
                
        jt.execute("create table mytable (id integer, name varchar(100))"); 
            
        }
          public void setDataSource(DataSource dataSource) {
                
        this.dataSource = dataSource;
            
        }
        }

  這個就是普通的 Java 類, 再參考 11.2.4. DataSource介面, 這裡的另一個程式碼片斷:

DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("org.hsqldb.jdbcDriver");
dataSource.setUrl("jdbc:hsqldb:hsql://localhost:");
dataSource.setUsername("sa");
dataSource.setPassword("");

  當然上面的連線方式可以配置成我們課程裡面介紹的 MyEclipse Derby 的資料庫連線:

org.apache.derby.jdbc.ClientDriver
jdbc:derby://localhost:1527/myeclipse;create=true
app
app

  我們可以寫一個測試類來執行程式碼:

import org.springframework.jdbc.datasource.DriverManagerDataSource;
public class TestTemplate {
  public static void main(String[] args) {
    // 新建一個資料來源物件
    DriverManagerDataSource dataSource = new DriverManagerDataSource();
    dataSource.setDriverClassName("org.hsqldb.jdbcDriver");
    dataSource.setUrl("jdbc:hsqldb:hsql://localhost:");
    dataSource.setUsername("sa");
    dataSource.setPassword("");
   
    // 新建一個ExecuteAStatement 物件
    ExecuteAStatement eas = new ExecuteAStatement();
    // 給執行表示式的物件關聯資料來源(也就是常說的注入, 通過 JavaBean 的 setXxx 方法關聯起來)
    eas.setDataSource(dataSource);
    // 執行功能程式碼
    eas.doExecute();
  }
}

  這個程式碼可以跑通, 就是普通的程式設計方式, 大家可以去看剛才介紹的文件附近的詳細說明。

  那麼如果用 Spring 來做, 程式碼會變成這樣:

  ExecuteAStatement 類程式碼保持不變, 多了個 beans.xml:

ExecuteAStatement 類程式碼保持不變, 多了個 beans.xml:

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-2.0.xsd">





class="org.springframework.jdbc.datasource.DriverManagerDataSource">

org.hsqldb.jdbcDriver



jdbc:hsqldb:hsql://localhost:



sa





 

  測試類:

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
 public static void main(String[] args) throws IOException {
  ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
  ExecuteAStatement eas =(ExecuteAStatement)context.getBean("userDAO");
      // 執行功能程式碼
      eas.doExecute();
 }
}

  和上面的 TestTemplate 類相比, 就會發現 new DriverManagerDataSource() 這個過程不用我們寫了, 執行的時候會發現一切都執行的好好的, 也就是常說的 ExecuteAStatement 的 dataSource 這個屬性被注入了。

  那麼這個過程到底該如何理解呢? Spring 是一個物件池, 可以簡化為一個 Map, 存多個主鍵和物件的對映。 那麼 Spring 執行的過程中, 會根據 beans.xml 一步步進行必要的解析工作:

  Map springEngine = new HashMap();

  OK, 解析到了

  , 發現 bean 定義, 那就新建一個例項存到物件池裡吧, 主鍵就是 userDAO, 值就是物件:

  ExecuteAStatement bean1 = new ExecuteAStatement();

  springEngine.put("userDAO", bean1);

  再往下執行, 發現 property 定義:

  

  到了這裡, 就知道應該呼叫 bean1.setDataSource(DataSource) 方法了。 可以接著執行, 發現

  , 哦, 這個方法的引數還沒有呢, 是個 bean 的引用, 好了, 要呼叫這個方法, 還是先 new 一個名字為 myDataSource 的 bean2 吧。 就跳到下面尋找 myDataSource 的定義, 找到了:

  class="org.springframework.jdbc.datasource.DriverManagerDataSource">

org.hsqldb.jdbcDriver



jdbc:hsqldb:hsql://localhost:



sa





  像以前一樣, 先例項化這個類, 然後看到 property 表情就呼叫對應的 setXxx() 這樣的方法, 相當於下面一段程式碼:

 // 新建一個資料來源物件
    DriverManagerDataSource bean2 = new DriverManagerDataSource();
    bean2.setDriverClassName("org.hsqldb.jdbcDriver");
    bean2.setUrl("jdbc:hsqldb:hsql://localhost:");
    bean2.setUsername("sa");
    bean2.setPassword("");

  不是還有個 bean 的 id 名字為 myDataSource 嘛, 那就把它存到物件池裡面:

  springEngine.put("myDataSource", bean2);

  好了, 最後就是把他們兩個關聯起來了, 通過 ref 裡指定的 bean id 名來關聯起來:

  // 省略型別轉換的程式碼

  springEngine.get("userDAO")。setDataSource(springEngine.get("myDataSource"));

  最後返回給使用者的就是一個物件池(一個 Map)了, 所以別人呼叫的時候, 就發現 springEngine.get("userDAO") 回來的類的 dataSource 屬性已經被例項化過了, 這些都是 Spring 幕後工作的程式碼, 通過反射機制來實現。

  所以最後寫程式碼呼叫:

  context.getBean("userDAO") 的時候, 得到的是 ExecuteAStatement, 這時候還有一個 myDataSource, 也可以被呼叫:

  context.getBean("myDataSource"), 得到的是 DriverManagerDataSource

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/13270562/viewspace-217880/,如需轉載,請註明出處,否則將追究法律責任。

相關文章