java

位置:IT落伍者 >> java >> 浏览文章

Spring 依赖注入原理学习


发布日期:2021年07月13日
 
Spring 依赖注入原理学习

首先我们来看看 Spring 参考文档的 执行SQL语句 这里有个代码片断

import javaxsqlDataSource;      import orgsprireJdbcTemplate;      public class ExecuteAStatement {          private JdbcTemplate jt;                    private DataSource dataSource;          public void doExecute() {                        jt = new JdbcTemplate(dataSource);                        jtexecute(create table mytable (id integer name varchar()));                     }          public void setDataSource(DataSource dataSource) {                        thisdataSource = dataSource;                    }        }

这个就是普通的 Java 类 再参考 DataSource接口 这里的另一个代码片断

DriverManagerDataSource dataSource = new DriverManagerDataSource();dataSourcesetDriverClassName(orghsqldbjdbcDriver);dataSourcesetUrl(jdbc:hsqldb:hsql://localhost:);dataSourcesetUsername(sa);dataSourcesetPassword();

当然上面的连接方式可以配置成我们课程里面介绍的 MyEclipse Derby 的数据库连接

orgapachederbyjdbcClientDriverjdbc:derby://localhost:/myeclipse;create=trueappapp

我们可以写一个测试类来执行代码

import orgspringframeworkjdbcdatasourceDriverManagerDataSource;public class TestTemplate {  public static void main(String[] args) {    // 新建一个数据源对象    DriverManagerDataSource dataSource = new DriverManagerDataSource();    dataSourcesetDriverClassName(orghsqldbjdbcDriver);    dataSourcesetUrl(jdbc:hsqldb:hsql://localhost:);    dataSourcesetUsername(sa);    dataSourcesetPassword();       // 新建一个ExecuteAStatement 对象    ExecuteAStatement eas = new ExecuteAStatement();    // 给执行表达式的对象关联数据源(也就是常说的注入 通过 JavaBean 的 setXxx 方法关联起来)    eassetDataSource(dataSource);    // 执行功能代码    easdoExecute();  }}

这个代码可以跑通 就是普通的编程方式 大家可以去看刚才介绍的文档附近的详细说明

那么如果用 Spring 来做 代码会变成这样

ExecuteAStatement 类代码保持不变 多了个 beansxml

ExecuteAStatement 类代码保持不变 多了个 beansxml:

<?xml version= encoding=UTF?>

<beans

xmlns=

xmlns:xsi=instance

xsi:schemaLocation= beansxsd>

<bean id=userDAO class=ExecuteAStatement>

<property name=dataSource>

<ref bean=myDataSource />

</property>

</bean>

<bean id=myDataSource

class=orgspringframeworkjdbcdatasourceDriverManagerDataSource>

<property name=driverClassName>

<value>orghsqldbjdbcDriver</value>

</property>

<property name=url>

<value>jdbc:hsqldb:hsql://localhost:</value>

</property>

<property name=username>

<value>sa</value>

</property>

<property name=password>

<value></value>

</property>

</bean>

</beans>

测试类

import orgntextApplicationContext;import orgntextsupportClassPathXmlApplicationContext;public class Test { public static void main(String[] args) throws IOException {  ApplicationContext context = new ClassPathXmlApplicationContext(beansxml);  ExecuteAStatement eas =(ExecuteAStatement)contextgetBean(userDAO);      // 执行功能代码      easdoExecute(); }}

和上面的 TestTemplate 类相比 就会发现 new DriverManagerDataSource() 这个过程不用我们写了 运行的时候会发现一切都执行的好好的 也就是常说的 ExecuteAStatement 的 dataSource 这个属性被注入了

那么这个过程到底该如何理解呢? Spring 是一个对象池 可以简化为一个 Map 存多个主键和对象的映射 那么 Spring 运行的过程中 会根据 beansxml 一步步进行必要的解析工作

Map springEngine = new HashMap()

OK 解析到了

<bean id=userDAO class=ExecuteAStatement> 发现 bean 定义 那就新建一个实例存到对象池里吧 主键就是 userDAO 值就是对象

ExecuteAStatement bean = new ExecuteAStatement()

springEngineput(userDAO bean

再往下执行 发现 property 定义

<property name=dataSource>

到了这里 就知道应该调用 beansetDataSource(DataSource) 方法了 可以接着执行 发现

<ref bean=myDataSource /> 这个方法的参数还没有呢 是个 bean 的引用 好了 要调用这个方法 还是先 new 一个名字为 myDataSource 的 bean 就跳到下面寻找 myDataSource 的定义 找到了

<bean id=myDataSource

  class=orgspringframeworkjdbcdatasourceDriverManagerDataSource>

  <property name=driverClassName>

      <value>orghsqldbjdbcDriver</value>

  </property>

  

  <property name=url>

      <value>jdbc:hsqldb:hsql://localhost:</value>

  </property>

  

  <property name=username>

      <value>sa</value>

  </property>

  

  <property name=password>

      <value></value>

  </property>      

</bean>

像以前一样 先实例化这个类 然后看到 property 表情就调用对应的 setXxx() 这样的方法 相当于下面一段代码

// 新建一个数据源对象    DriverManagerDataSource bean = new DriverManagerDataSource();    beansetDriverClassName(orghsqldbjdbcDriver);    beansetUrl(jdbc:hsqldb:hsql://localhost:);    beansetUsername(sa);    beansetPassword();

不是还有个 bean 的 id 名字为 myDataSource 嘛 那就把它存到对象池里面

springEngineput(myDataSource bean

好了 最后就是把他们两个关联起来了 通过 ref 里指定的 bean id 名来关联起来

// 省略类型转换的代码

springEngineget(userDAOsetDataSource(springEngineget(myDataSource))

最后返回给用户的就是一个对象池(一个 Map)了 所以别人调用的时候 就发现 springEngineget(userDAO) 回来的类的 dataSource 属性已经被实例化过了 这些都是 Spring 幕后工作的代码 通过反射机制来实现

所以最后写代码调用

contextgetBean(userDAO) 的时候 得到的是 ExecuteAStatement 这时候还有一个 myDataSource 也可以被调用

contextgetBean(myDataSource 得到的是 DriverManagerDataSource

               

上一篇:关于OJB和Hibernate框架的评议

下一篇:Spring i18n的better practice