天天看点

Spring --- IOC

[i][b]一) IOC其实很简单[/b][/i]

什么是IOC(控制反转)? 这名词听起来玄乎,其实so easy。简而言之,就是通过配置文件来反过来控制代码变化。广义上说,凡是你使用了配置文件的形式来提高代码的灵活性和通用性的,都可以说是一种控制反转。因为那部分由配置文件决定的逻辑便是你将控制权从代码手中反转到配置文件中的运用。(一家之言,仅供参考。也许片面也许错误~~)。总结来说,所谓“控制反转”的概念就是:控制权由应用代码中转到了外部容器,控制权的转移就是所谓反转。

那么,如何实现IOC呢?这更简单,只要知道怎么载入配置文件的人都可以定义一套解析规则来实现。但如果每人一套自己的规则这显然IOC界就变得各自为战,乱作一团了。经业界大牛们的实践经验和总结讨论。我们基本都统一使用以下三种方式:

[b]Type1:接口注入:[/b]

doIt()到底做些什么,由注入的InterfaceB b决定。一个具体的实例就是Servlet:

public class MyServlet extends HttpServlet { 

  public void doGet( HttpServletRequest request,  HttpServletResponse response) 
     throws ServletException, IOException { 
   …… 
  } 
} 
           

HttpServletRequest和HttpServletResponse实例由Servlet Container

在运行期动态注入。

[b]Type2:设值注入:[/b]

即我们最熟悉的set get注入。

[b]Type3: 构造子注入:[/b]

即通过构造函数完成依赖关系的设定

public class DIByConstructor { 
   private final DataSource dataSource; 
   private final String message; 

   public DIByConstructor(DataSource ds, String msg) { 
     this.dataSource = ds; 
     this.message = msg; 
    } 
  …… 
} 
           

这便是我们常说的依赖注入DI。IOC通过DI的方式来实现其理念!

最后引用一个大牛的结论:

接口注入模式因为历史较为悠久,在很多容器中都已经得到应用。但由于其在灵活性、易用性上不如两种注入模式,因而在IOC的专题世界内并不被看好。

Type3和Type2模式各有千秋,而Spring、PicoContainer都对Type3和Type2类型的依赖注入机制提供了良好支持。这也就为我们提供了更多的选择余地。理论上,以Type3类型为主,辅之以Type2类型机制作为补充,可以达到最好的依赖注入效果,不过对于基于Spring Framework开发的应用而言,Type2使用更加广泛。

[i][b]二) Spring的IOC其实不简单[/b][/i]

[b]1)name 和 id[/b]

在BeanFactory的配置中,<bean>是我们最常见的配置项,它有两个最常见的属性,即id和name。

首先它们都可以通过BeanFactory的getBean()属性来获得对应的实例。

但是区别如下:

1' id和name 都不能以数字,符号打头,不能有空格。但id在spring初始化的时候就报错,name则在getBean()时报错。

2' 配置文件中不允许出现两个id相同的<bean>,但配置文件中允许出现两个name相同的<bean>。在用getBean()返回实例时,后面一个Bean被返回。

3' name属性可以用,隔开指定多个名字,如<bean name="b1,b2,b3">,相当于多个别名。或者显示的声明别名:

<alias name="fromName" alias="toName"/>

其它的注意点有:

1' 如果id和name都没有指定,则用类全名作为name,如<bean class="com.test.noNameId">,则你可以通过

getBean("com.test.noNameId")返回该实例。

2' 如果存在多个id和name都没有指定,且实例类都一样的<bean>,如:

<bean class = "com.test.noNameId" />   
<bean class = "com.test.noNameId" />   
<bean class = "com.test.noNameId" />  
           

则第一个bean通过getBean("com.test.noNameId")获得,

第二个bean通过getBean("com.test.noNameId#1")获得,

第三个bean通过getBean("com.test.noNameId#2")获得,以此类推。

[b]2) bean的初始化[/b]

bean的初始化有三种方法:

1' 构造函数初始化

<bean id="exampleBean" class="examples.ExampleBean"/> 
  <bean name="anotherExample" class="examples.ExampleBeanTwo"/>
           

spring最常见的一种初始化配置。初始化时调用默认的构造函数。

2' 静态工厂方法初始化

<bean id="clientService" class="examples.ClientService" factory-method="createInstance"/>
   public class ClientService {
       private static ClientService clientService = new ClientService();
       private ClientService() {}
       public static ClientService createInstance() {
           return clientService;
       }
   }
           

初始化时,spring会调用静态方法createInstance来实例化clientService。

3' 工厂方法初始化

<bean id="serviceLocator" class="examples.DefaultServiceLocator"></bean>
<bean id="clientService" factory-bean="serviceLocator" factory-method="createClientServiceInstance"/>
public class DefaultServiceLocator {
    private static ClientService clientService = new ClientServiceImpl();
    private DefaultServiceLocator() {}
    public ClientService createClientServiceInstance() {
        return clientService;
    }
}
           

初始化clientService时,spring会调用DefaultServiceLocator.createClientServiceInstance()来实例化。

[b]3)Collections[/b]

<bean id="moreComplexObject" class="example.ComplexObject">

<!-- results in a setAdminEmails(java.util.Properties) call -->
<property name="adminEmails">
  <props>
    <prop key="administrator">[email protected]</prop>
    <prop key="support">[email protected]</prop>
    <prop key="development">[email protected]</prop>
  </props>
</property>

<!-- results in a setSomeList(java.util.List) call -->
<property name="someList">
  <list>
    <value>a list element followed by a reference</value>
    <ref bean="myDataSource" />
  </list>
</property>

<!-- results in a setSomeMap(java.util.Map) call -->
<property name="someMap">
  <map>
    <entry key="an entry" value="just some string"/>
    <entry key ="a ref" value-ref="myDataSource"/>
  </map>
</property>

<!-- results in a setSomeSet(java.util.Set) call -->
<property name="someSet">
  <set>
    <value>just some string</value>
    <ref bean="myDataSource" />
  </set>
</property>

</bean>
           

Collection merge

<beans>
<bean id="parent" abstract="true" class="example.ComplexObject">
  <property name="adminEmails">
    <props>
      <prop key="administrator">[email protected]</prop>
      <prop key="support">[email protected]</prop>
    </props>
  </property>
</bean>
<bean id="child" parent="parent">
  <property name="adminEmails">
    <!-- the merge is specified on the *child* collection definition -->
    <props merge="true">
      <prop key="sales">[email protected]</prop>
      <prop key="support">[email protected]</prop>
    </props>
  </property>
</bean>
<beans>
           

child的bean将具有property:

[email protected]

[email protected]

[email protected]

4) null的表示

<bean class="ExampleBean">
  <property name="email"><null/></property>
</bean>
           

5) p-namespace c-namespace的缩写

<bean name="john-classic" class="com.example.Person">
  <property name="name" value="John Doe"/>
  <property name="spouse" ref="jane"/>
</bean>
<bean name="john-modern" class="com.example.Person" p:name="John Doe" p:spouse-ref="jane"/>
<bean name="jane" class="com.example.Person">
  <property name="name" value="Jane Doe"/>
</bean>
           
<bean id="bar" class="x.y.Bar"/>
<bean id="baz" class="x.y.Baz"/>
<-- 'traditional' declaration -->
<bean id="foo" class="x.y.Foo">
  <constructor-arg ref="bar"/>
  <constructor-arg ref="baz"/>
  <constructor-arg value="[email protected]"/>
</bean>
<-- 'c-namespace' declaration -->
<bean id="foo" class="x.y.Foo" c:bar-ref="bar" c:baz-ref="baz" c:email="[email protected]">