2010-9-25

spring depends on 讲解

使用depends-on

 

多数情况下,一个bean对另一个bean的依赖最简单的做法就是将一个bean设置为另外一个bean的属性。在xml配置文件中最常见的就是使用<ref/>元素。有时候它还有另外一种变体,如果一个bean能感知IoC容器,只要给出它所依赖的id,那么就可以通过编程的方式从容器中取得它所依赖的对象。无论采用哪一种方法,被依赖bean将在依赖bean之前被适当的初始化。

在少数情况下,有时候bean之间的依赖关系并不是那么的直接(例如,当类中的静态块的初始化被时,如数据库驱动的注册)。depends-on属性可以用于当前bean初始化之前显式地强制一个或多个bean被初始化。下面的例子中使用了depends-on属性来指定一个bean的依赖。

Java代码
1.<BEAN class=ExampleBean id=beanOne depends-on="manager"></BEAN>
2.<BEAN class=ManagerBean id=manager></BEAN>

 

若需要表达对多个bean的依赖,可以在'depends-on'中将指定的多个bean名字用分隔符进行分隔,分隔符可以是逗号、空格及分号等。下面的例子中使用了'depends-on'来表达对多个bean的依赖。Java代码


 

3.3.5. 延迟初始化bean

 

ApplicationContext实现的默认行为就是在启动时将所有singleton bean提前进行实例化。提前实例化意味着作为初始化过程的一部分,ApplicationContext实例会创建并配置所有的singleton bean。通常情况下这是件好事,因为这样在配置中的任何错误就会即刻被发现(否则的话可能要花几个小时甚至几天)。

有时候这种默认处理可能并不是你想要的。如果你不想让一个singleton bean在ApplicationContext实现在初始化时被提前实例化,那么可以将bean设置为延迟实例化。一个延迟初始化bean将告诉IoC 容器是在启动时还是在第一次被用到时实例化。

在XML配置文件中,延迟初始化将通过<bean/>元素中的lazy-init属性来进行控制。例如:

Java代码

1.<BEAN class=com.foo.ExpensiveToCreateBean id=lazy lazy-init="true"></BEAN>
2.    <!-- various properties here... -->
3.  
4.  <BEAN class=com.foo.AnotherBean name="not.lazy"></BEAN>
5.    <!-- various properties here... -->


ApplicationContext实现加载上述配置时,设置为lazy的bean将不会ApplicationContext启动时提前被实例化,而not.lazy却会被提前实例化。

需要说明的是,如果一个bean被设置为延迟初始化,而另一个非延迟初始化的singleton bean依赖于它,那么当ApplicationContext提前实例化singleton bean时,它必须也确保所有上述singleton 依赖bean也被预先初始化,当然也包括设置为延迟实例化的bean。因此,如果Ioc容器在启动的时候创建了那些设置为延迟实例化的bean的实例,你也不要觉得奇怪,因为那些延迟初始化的bean可能在配置的某个地方被注入到了一个非延迟初始化singleton bean里面。


--
we drink green tea

Spring的InitializingBean和init-method比较

Spring的InitializingBean和init-method

Spring在设置完一个bean所有的属性后,会检查bean是否实现了InitializingBean接口,如果实现就调用bean的afterPropertiesSet方法。另外,如果bean是单例的,则afterPropertiesSet方法只会被调用一次;否则每次创建bean时afterPropertiesSet方法都会被重新调用.
Spring虽然可以通过InitializingBean完成一个bean初始化后对这个bean的回调,但是这种方式要求bean实现 InitializingBean接口。一但bean实现了InitializingBean接口,那么这个bean的代码就和Spring耦合到一起了。通常情况下不建议直接实现InitializingBean,而是用Spring提供的init-method的功能来执行一个bean 子定义的初始化方法,这可以在一个bean的配置文件中通过init-method声明:
<bean id="testBean" class="TestClass" init-method="initialize"/>
spring要求这个init-method方法是一个无参数的方法
如果一个bean同时实现了这两种方式的初始化配置,则spring会先调用afterPropertiesSet方法,然后通过反射调用init-method,任何一个方法出错都会导致spring创建bean失败.如果afterPropertiesSet方法调用失败,也不会再继续执行init-mehtod方法.

--
we drink green tea

Spring-IOC,各种集合类注入

Spring的注入:
(1)setter注入:
Spring中成员list,set,map,props的配置:
一>>>>list和数组的配置:无论类中的属性是一个list还是数组,均需要用<list></list>元素装载此属性
  <property name="testList">
 <list>
  <value>test1</value>
  <ref bean="test1">
 </list>
  </property> 
  在spring中使用hibernate持久化对象,需要配置一个LocalSessionFactoryBean,
  这个类中有一个mappingResources属性,由利用list来组装所有的mappingResources文件。例:
  <bean id="sessionFactory" class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
 <property name="mappingResources">
  <list>
   <value>/com/wes/spring/resource/Test1.hbm.xml</value>
   <value>/com/wes/spring/resource/Test2.hbm.xml</value>
   <value>/com/wes/spring/resource/Test3.hbm.xml</value>
  </list>
 </property>
  </bean>
  通过以上配置就达到了在sessionFactory中取到hbm配置文件的目的了。
二>>>>Set的配置:有时为了确保集合中数据的唯一性,需要用到一个java.util.Set的属性,具体配置如下:
 <property name="testSet">
  <set>
   <value>test1</value>
   <ref bean="test1">  <!-- 和list一样set可以装配任何属性的对象 -->
  </set>
        </property>
三>>>>Map属性:很多时候需要用map去存放一些key-->value对,这是java.util.Map类型的属性配置如下:
 <property name="testMap">
  <map>
   <entry key="key1">
    <value>test1</value>
   </entry>
   <entry key="key2"> 
    <ref bean="test2">
   </entry>
  </map>
 </property><!--目前Spring中只允许String类型的为主键-->
四>>>>Properties:java.util.Properties也能通过配置达到初始化的目的:
 <property name="testProps">
  <props>
   <prop key="key1">test1</prop>
   <prop key="key2">test2</prop>
  </props><!-- 所有key value值均为String类型 -->
 </property>
五>>>>设置null,明确将一个属性设置为null
 <property name="test1"><null/></property>

    注:setter注入的缺点是它假设了所有的可变属性都可以通过set方法访问到,也许你不希望自己的Bean是这样的。首先:
当一个bean实例化的时候,它的所有属性都没有设置,它会处于一个不确定状态。其次:有时候要求一些属性的值只能在创建的时候设置一次,以后就不能改变了。一种替代的方法是构造注入。

通常应用:一般在一些比较固定的场合应用,像数据源(DataSource),固定属性(性别),还有其他一些固定属性想配置进来的都可以。

(2)构造注入:
 package com.wes.spring;
 public class Test{
  private String a;
  private String b;
  public Test(String a,String b) {this.a = a; this.b=b}
 }
 具体配置:
 <bean id="test" class="com.wes.spring.Test">
  <constructor-arg index="1">
   <value>bbbb</value>
  <constructor-arg>
  <constructor-arg index="0">
   <value>aaaa</value>
  <constructor-arg>

 </bean><!-- 当有多个参数时用index指定具体要赋的变量,index从0开始,也可以用type(变量类型)指定,但如果参数的类型一样时就没办法用type指定了 --> 
we drink green tea

Spring-IOC,各种集合类以及数组的注入


public class Some {
 private String name;

 public String getName() {
  return name;
 }

 public void setName(String name) {
  this.name = name;
 }
 
 public String toString(){
  return name;
 }
}

package 集合类注入;

import java.util.List;
import java.util.Map;

public class SomeBean {
 private String[] someStrArray;
 private Some[] someObjArray;
 private List someList;
 private Map someMap;
 public List getSomeList() {
  return someList;
 }
 public void setSomeList(List someList) {
  this.someList = someList;
 }
 public Map getSomeMap() {
  return someMap;
 }
 public void setSomeMap(Map someMap) {
  this.someMap = someMap;
 }
 public Some[] getSomeObjArray() {
  return someObjArray;
 }
 public void setSomeObjArray(Some[] someObjArray) {
  this.someObjArray = someObjArray;
 }
 public String[] getSomeStrArray() {
  return someStrArray;
 }
 public void setSomeStrArray(String[] someStrArray) {
  this.someStrArray = someStrArray;
 }
}

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">

<beans>
 <bean id="some1" class="集合类注入.Some">
  <property name="name" value="tom"/>
 </bean>
 <bean id="some2" class="集合类注入.Some">
  <property name="name" value="joy"/>
 </bean>
 <bean id="someBean" class="集合类注入.SomeBean">
  <property name="someStrArray">
   <list>
    <value>Hello</value>
    <value>Welcome</value>
   </list>
  </property>
  
  <property name="someObjArray">
   <list>
    <ref bean="some1"/>
    <ref bean="some2"/>
   </list>
  </property>
  <property name="someList">
   <list>
    <value>hehehehe</value>
    <ref bean="some1"/>
    <ref bean="some2"/>
   </list>
  </property>
  <property name="someMap">
   <map>
    <entry key="MapTest">
     <value>Hello!TOM</value>
    </entry>
    <entry key="someKey1">
     <ref bean="some1"/>
    </entry>
   </map>
  </property>
 </bean>
</beans>

package 集合类注入;

import java.util.Iterator;
import java.util.List;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestArray {
 public static void main(String[] args){
  ApplicationContext context = new ClassPathXmlApplicationContext("集合类注入//bean-config.xml");
  SomeBean someBean = (SomeBean)context.getBean("someBean");
  String[] strs = someBean.getSomeStrArray();
  for(int i = 0; i < strs.length; i++){
   System.out.println(strs[i]);
  }
  List someList = someBean.getSomeList();
  
  for(Iterator it = someList.iterator(); it.hasNext();){
   System.out.println(it.next());
  }
 }
}

--
we drink green tea

spring 继承的实现

SomeBean.java

java 代码
  1. package com.gjx.spring;   
  2. //测试Spring的继承   
  3. public class SomeBean {   
  4.   
  5.     private String name;   
  6.     private int age;   
  7.     public int getAge() {   
  8.         return age;   
  9.     }   
  10.     public void setAge(int age) {   
  11.         this.age = age;   
  12.     }   
  13.     public String getName() {   
  14.         return name;   
  15.     }   
  16.     public void setName(String name) {   
  17.         this.name = name;   
  18.     }   
  19. }   

somebean-config.xml

xml 代码
xml 代码
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2.   
  3. <beans xmlns="http://www.springframework.org/schema/beans"  
  4.          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  5.          xmlns:aop="http://www.springframework.org/schema/aop"  
  6.          xmlns:tx="http://www.springframework.org/schema/tx"  
  7.          xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd   
  8.            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd   
  9.            http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">  
  10. <!-- 在配制文件中设置继承,这是一个完全抽象的继承 -->  
  11.     <bean id="inheritedSomeBean" abstract="true">  
  12.         <property name="name">  
  13.             <value>冬国</value>  
  14.         </property>  
  15.         <property name="age">  
  16.             <value>22</value>  
  17.         </property>    
  18.     </bean>  
  19.     <!-- 注意这里的parent="inheritedSomeBean"与前面的对应 -->  
  20.     <bean id="some" class="com.gjx.spring.SomeBean" parent="inheritedSomeBean">  
  21.         <property name="name">  
  22.             <value>完全抽象的继承</value>  
  23.         </property>  
  24.     </bean>  
  25.        
  26.        
  27. <!-- 下面是从一个Bean的实例来继承  在这里的beanInstance也是可以被实例化的-->  
  28.     <bean id="beanInstance" class="com.gjx.spring.SomeBean">  
  29.         <property name="name">  
  30.             <value>冬国</value>  
  31.         </property>  
  32.         <property name="age">  
  33.             <value>30</value>  
  34.         </property>    
  35.     </bean>  
  36.     <bean id="instanceSome" class="com.gjx.spring.SomeBean" parent="beanInstance">  
  37.         <property name="name">  
  38.             <value>实例来继承</value>  
  39.         </property>  
  40.     </bean>  
  41.        
  42.   
  43. </beans>  

 

测试类:

java 代码
  1. package Test.com.gjx.spring;   
  2.   
  3. import junit.framework.TestCase;   
  4.   
  5. import org.springframework.beans.factory.BeanFactory;   
  6. import org.springframework.beans.factory.xml.XmlBeanFactory;   
  7. import org.springframework.context.ApplicationContext;   
  8. import org.springframework.context.support.ClassPathXmlApplicationContext;   
  9. import org.springframework.core.io.ClassPathResource;   
  10. import org.springframework.core.io.Resource;   
  11.   
  12. import com.gjx.spring.HelloBean;   
  13. import com.gjx.spring.SomeBean;   
  14.   
  15. public class TestHelloBean extends TestCase {   
  16.     //测试继承   
  17.     public void testSomeBean(){   
  18.         ApplicationContext context=new ClassPathXmlApplicationContext("somebean-config.xml");   
  19.         SomeBean some=(SomeBean)context.getBean("some");   
  20.         SomeBean instanceSome=(SomeBean)context.getBean("instanceSome");   
  21.            
  22.         System.out.println("Abstract>>>  name="+some.getName()+"  age="+some.getAge());   
  23.         System.out.println("Instance>>>  name="+instanceSome.getName()+"  age="+instanceSome.getAge());   
  24.     }   
  25. }   

测试结果:

冬国
Abstract>>>  name=完全抽象的继承  age=22
Instance>>>  name=实例来继承  age=30


--
we drink green tea

2010-9-24

Spring Bean的继承和java类继承的区别

 Spring Bean的继承和java类继承的区别 收藏

1.Spring中子bean和父bean可以是不同类型,java中子类必定是一个特定的父类

2.Spring中继承是实例之间的关系,主要表现在参数的延续,java类中的继承是类之间的关系,主要表现为方法,属性的延续

3.Spring子bean不可以作为父bean使用,不具有多态性,java反之


--
we drink green tea

Spring入门示例及相关概念介绍

Spring入门示例及相关概念介绍

作者:http://blog.csdn.net/fenglibing,转载请保留。

    相对于Hibernate(冬眠),Spring(春天),具有更多的诗意与希望的感觉,是为了解决传统J2EE开发效率过低、开发商之间不统一、没有真正实现写一次到处使用,它的优点有如下:

1、低侵入式设计,代码污染极低。

2、独立于各种应用服务,真正实现写一次到处都可以使用。

3、用户可选择的自由度高,用户可以选择部分或者是全部SPRING的功能,它并不是设计来取代其它框架,可以和其它的框架(如STRUTSHIBERNATE)等结合极好。

4、面向接口的编程方式,使得代码的偶合度降到最低。

5、所有的BEAN默认都被会单态化,相同的BEAN只会被初使化一次,因而节省了BEAN初使化的时间及减少垃圾回收,增加了应用效率。

...

有以上的优点的结合,因而它是被广大程序员所欢迎的,因为它可以给我们带来高效、稳定的开发,很大程度的减少了程序的开发、维护周期,也就自然的减少了软件开发的费用。下面简单的介绍两个应用示例,这些示例都来自于书本,都简单易懂,我也会详细的加以说明,另外需要使用下面的示例,需要引用SpringJAR包:Spring.jar,该JAR包包括了大部份的应用,如果暂时不需要SPRINT的其它功能,该JAR足以。

以下的程序,全部都是调试通过的。

示例一、不同的人说不同的话

1、建立接口

工厂模式SRPING中是随处体现,且提倡面向接口,因此首先建立接口:人

package test;
public interface Person {
 public void sayHello();
 public void sayBye();
}

2、建立两种具体的人:中国人、美国人

//中国人

package test;

public class Chinese implements Person {
 public void sayBye() {
  System.out.println("
再见");
 }
 public void sayHello() {
  System.out.println("
你好");
 }
}

//美国人

package test;

public class American implements Person {
 public void sayBye() {
  System.out.println("Bye");
 }
 public void sayHello() {
  System.out.println("hello");
 }
}

3、建立bean映射配置文件,bean.xml(这个文件名是什么没有关系,在初使化的时候指定给初使化程序就可以)

<?xml version="1.0" encoding="gb2312"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
 "http://www.sprintframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="chinese" class="test.Chinese"/>
<bean id="american" class="test.American"/>
</beans>

4、建立JAVA测试类:

public void doIt(){

  /*获取bean映射配置文件,配置文件放于与当前测试类在同一个目录下*/
  ApplicationContext ctx=new FileSystemXmlApplicationContext(getClass().getResource("bean.xml").toString());
  Person person=null;
  person=(Person)ctx.getBean("chinese");
  person.sayHello();
  person.sayBye();
  
  person=(Person)ctx.getBean("american");
  person.sayHello();
  person.sayBye();
 }

5、对以上示例调用的说明:

A)、对接口Person和具体实现类ChineseAmerican就没有什么需要说明的了,和其它的编程方式,都是先定义接口,实现类再通过继承接口实现其方法。

B)、映射类中将类的路径定义为一个id的名称,到时系统根据传到的id名称,到配置文件中去找到该类的绝对路径,再通过反射原理加载该类,并返回其对象,这个是通过getBean这个动作完成的。

C)、根据里氏代换原则,能够接收父类的地方,都可以接收子类,所以这个时候通过getBean返回的对象(如Chinese或者American),都可以赋给接口Person,这个时候接口类调用其中的方法的时候,因为这个时候父类实际上接受的是子类的对象,因而这个时候调用的就是指定子类的方法。这个时候Spring就帮我们完成了如下工作:

Person person=new Chinese();

只是子类不是通过显示给出来的,而是通过Spring工厂通过映射配置生成的。

 

示例二、设值注入

设值注入是依赖注入的一种,依赖注入早期叫控制反转,也可以称反射,他们的意义都相同。当某个 Java 实例(调用者)需要另一个Java 实例(被调用者)时,在传统的程序设计过程中,通常由调用者来创建被调用者的实例。而在依赖注入的模式下,创建被调用者的工作不再由调用者来完成,通常由 Spring 容器来完成,然后注入调用者,因此称为控制反转,也称为依赖注入。

1、建立接口:人与斧头

人,定义一个动作:

package test2;
public interface Person {
 public void useAxe();
}

斧头,定义一个动作:

package test2;

public interface Axe {
 public void chop();
}

2、建立接口的实现类:中国人与石斧

中国人

package test2;

public class Chinese implements Person{
 /*
默认无参构造方法不管为私的还是公有的,都可以访问,并且要保证bean中存在可以被外界访问的无参构造函数*/
 private Chinese(){};
 /*
定义需要被使用的斧头接口,具体使用什么斧头这里不管*/
 private Axe axe;
 /*
定义被注入斧头的set方法,该方法一定要符合JAVABEAN的标准。在运行时候,
  *Sping
就会根据配置的<ref local=""/>,找到需要注入的实现类*/
 public void setAxe(Axe axe){
  this.axe=axe;
 }

 /*
这个时候使用的axe,就不再是接口Axe本身,而是被注入的子类实例,所以这里的chop()动作就是具体子类的chop动作*/
 public void useAxe() {
  axe.chop();
 }
}

石斧

package test2;

public class StoneAxe implements Axe {
 public void chop() {
  System.out.println("
石斧慢慢砍");
 }
}
3
、建立映射配置文件bean.xml

<?xml version="1.0" encoding="gb2312"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
 "http://www.sprintframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="chinese" class="test2.Chinese">
 <!-- 
声明实现类test2.Chinese中的属性 -->
 <property name="axe">
  <!-- 
指定其中声明的属性,需要用本地的那个id对应的class
    
这里local的值为"stoneAxe",表示axe的属性值在注入的时候,
    
将会用test2.StoneAxe实例注入,到时在实例类Chinese中使用
    axe
的时候,实际上调用的时候StoneAxe的实例
   -->
  <ref local="stoneAxe"/>
 </property>

</bean>
<bean id="stoneAxe" class="test2.StoneAxe"/>
</beans>

4、测试用例:

package test2;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
public class Caller {
 public static void main(String[] args) {
  Caller caller=new Caller();
  caller.doIt();  
 }
 public  void doIt(){
  String bean=getClass().getResource("bean.xml").toString();
  ApplicationContext ctx=new FileSystemXmlApplicationContext(bean);
  Person person=(Person)ctx.getBean("chinese");
  person.useAxe();
 }
}

5、对以上示例调用的说明:

程序及XML文件中都有详细说明,这里就不说明了。

 

三、构造注入:

构造注入即是通过构造函数进行注入,到目前为止,SPRINT支持设值注入与构造注入两种方式,它们可以同时存在。

现在采用的实例为了和设值注入进行对比,因此使用的程序都是设值注入的程序,其中的接口和测试实例都不需要修改,修改的只是需要被注入的实现类Chinese,以及配置文件,不同之处用加粗体表示。

1、修改实现类Chinese如下;

package test2;
public class Chinese implements Person{
 /*
默认无参构造方法不管为私的还是公有的,都可以访问,并且要保证bean中存在可以被外界访问的无参构造函数*/
 private Chinese(){}; 
 /*
定义需要被使用的斧头接口,具体使用什么斧头这里不管*/
 private Axe axe;
 public Chinese(Axe axe){
  this.axe=axe;
 }

 /*
这个时候使用的axe,就不再是接口Axe本身,而是被注入的子类实例,所以这里的chop()动作就是具体子类的chop动作*/
 public void useAxe() {
  axe.chop();
 }
}
2
、修改配置文件bean.xml

<?xml version="1.0" encoding="gb2312"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
 "http://www.sprintframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="chinese" class="test2.Chinese">
 <!-- 
定义需要被构造注入的实现类,同设值注入的结果一样,都是注入接口的实现类 -->
 <constructor-arg><ref bean="stoneAxe"/></constructor-arg>
</bean>
<bean id="stoneAxe" class="test2.StoneAxe"/>
</beans>

 

3、设值注入与构造注入实现的结果是一样的,都在将需要被调用的实现类注入到调用的实现类。

设值注入与传统JAVABEAN的写法一样,比较容易接受;而构造注入在应用程序加载的时候就已经完成了注入,可以控制加载顺序。各有优缺点,根据不同的情况选用了。

 

四、后记

编程中理解与使用SPRING就像是人从学走路到跑步的过程,如果没有理解什么是单态模式、工厂模式、反射、JAVABEANXML基础、接口及其实现等等,理解SPRING就会比较困难,就算是可以使用通,也不一定知道为什么,看看网上的一些信息,动不动要求说会不会SPRINGHIBERNATE等等,很少提到基础知识是否扎实。我在面试别人的过程中,往往更注意面试人员的程序基础、编程风格、动手能力、文档编写能力等,当然对当前一些流行的框架也会有提问,毕竟好的东西也是需要借签的。


--
we drink green tea