Spring内核研究-管理bean之间的关系一(depends-on)

来源:互联网 发布:淘宝进店提醒软件 编辑:程序博客网 时间:2024/06/08 09:27
depend-on用来表示一个Bean的实例化依靠另一个Bean先实例化。如果在一个bean A上定义了depend-on B那么就表示:A 实例化前先实例化 B。
    这种情况下,A可能根本不需要持有一个B对象。
    比如说,你的DAO Bean实例化之前你必须要先实例化Database Bean,DAO Bean并不需要持有一个Database Bean的实例。因为DAO的使用是依赖Database启动的,如果Database Bean不启动,那么DAO即使实例化也是不可用的。这种情况DAO对Database的依赖是不直接的。
    除了在DAO上使用构造函数注入Database Bean以外,Spring没有任何依赖注入的关系能够满足上面的情况。但是DAO也许根本不需要Database的实例被注入,因为DAO是通过JDBC访问数据库的,它不需要调用Database 上的任何方法和属性。
    在这种情况下你可以使用depends-on来定义在DAO被实例化之前先去实例化Database。你可这样定义:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd"
> <beans> <bean name="dao" class="research.spring.beanfactory.ch3.Dao" depends-on="database"> </bean> <bean id="database" class="research.spring.beanfactory.ch3.Database"> </bean>
</beans>
 
通过定义depends-on=”database”可以控制Sping实例化dao的顺序。在任何时候Spring总会保证实例化DAO之前先实例Database。
    通常depends-on常常应用在上面的场景中。如果DAO depend-on Database的同时需要得到Database的实例,那么使用构造函数注入是一个比较好的解决办法。因为构造函数注入的方式是要先实例化目标对象依赖的对象然后在实例化目标对象。关于构造函数的输入请参考另一篇文章《Spring内核研究-set方法注入和构造函数注入

    DAO depend-on Database时,也可以在DAO上定义setDatabase方法来接收一个Database的实例。这样Sping会保证DAO创建前先创建Database实例,然后在把实例化DAO后调用DAO的setDatabase方法把刚才创建的Database的实例注入给DAO。前提条件时Database必须定义成单例的。否则Spring在DAO depend-on Database时会创建一个Database的实例,在DAO.setDatabase时又会创建Database另外的一个实例。这种情况可能不是你想要的,而且很可能会造成比较隐蔽的错误。

    使用set方法注入depend-on的对象:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd"
> <beans> <bean name="dao" class="research.spring.beanfactory.ch3.Dao" depends-on="database "> <property name="database"> <ref bean="database"></ref> </property> </bean> <bean id="database" class="research.spring.beanfactory.ch3.Database"> </bean>
</beans>

     一般在depends-on一个对象并且又需要这个对象实例的情况下,我都建议你使用构造函数的注入方式替换depend-on。只有不能构造函数中添加依赖对象参数的情况下才使用上面例子里的方式。
可以同时使用depends-on和构造函数注入,如A depends-on B 并且 new A(B b)。
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd"
> <beans> <bean name="dao" class="research.spring.beanfactory.ch3.Dao" depends-on="database"> <constructor-arg> <ref bean="database"></ref> </constructor-arg> </bean> <bean id="database" class="research.spring.beanfactory.ch3.Database"> </bean>
</beans>

    然而这种做法是不合适的,因为在构在函数中注入依赖对象的方式可以包含depends-on的情况。也就时说new A(B b)包含了A depends-on B的所有情况。既然已经定义了new A(B b)就没有必要在定义A depends-on B。所以,new A(B b)可以替代A depends-on BA创建前必须创建B,而且A不需要使用B实例的情况下只能使用A depends-on B
 

    Spring允许Bean和Bean依赖的Bean(合作者)上同时定义depends-on。比如A depends-on B && B depends-on C && C depends-on D。下面这样定义是合法的。Sping实例化他们的顺序是D->C->B->A。

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd"
> <beans> <bean name="a" class="research.spring.beanfactory.ch3.A" depends-on="b" /> <bean name="b" class="research.spring.beanfactory.ch3.B" depends-on="c" /> <bean name="c" class="research.spring.beanfactory.ch3.C" depends-on="D" /> <bean name="d" class="research.spring.beanfactory.ch3.D" /> </beans>
    但是Spring不允许A depends-on B && B depends-on A的情况。看下面的例子,由于D又依赖回A,这种在依赖关系中形成了一个闭环,Spring将无法处理这种依赖关系。所以下面的这种定义是不合法的。
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd"
> <beans> <bean name="a" class="research.spring.beanfactory.ch3.A" depends-on="b" /> <bean name="b" class="research.spring.beanfactory.ch3.B" depends-on="c" /> <bean name="c" class="research.spring.beanfactory.ch3.C" depends-on="D" /> <bean name="d" class="research.spring.beanfactory.ch3.D" depends-on="A"/> </beans>
 
    一个Bean可以同时depends-on多个对象如,A depends-on D,C,B。可以使用“,”或“;”定义多个depends-on的对象。
 
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd"
> <beans> <bean name="a" class="research.spring.beanfactory.ch3.A" depends-on="d,c,b" /> <bean name="b" class="research.spring.beanfactory.ch3.B" /> <bean name="c" class="research.spring.beanfactory.ch3.C" /> <bean name="d" class="research.spring.beanfactory.ch3.D" /> </beans>

    上面的例子中A的实例化需要先实例化D,C,B。Spring会按照depend-on中定义的顺序来处理Bean。在这个例子里Spring实例化对象的顺利是D->C->B->A。虽然实例化对象的顺序和前面“A depends-on B && B depends-on C && C depends-on D”的情况一下,但是这里的意义是完全不同的。不能用“A depends-on D,C,B”代替“A depends-on B && B depends-on C && C depends-on D”。

     depends-on是一个非常又用的功能,借助depends-on我们可以管理那些依赖关系不明显或者没有直接依赖关系的对象。
发布于 2006年7月4日 16:49   由 陈杰   有 1 篇评论
Spring内核研究-通过工厂注入
    Spring专门设计了对工厂模式支持,你可以使用静态工厂方法来创建一个Bean,也可以使用实例工厂的方法来创建Bean。下面分别介绍这2种方法。
静态工厂注入
    定义一个Bean使用自己类上的静态工厂方法来创建自己。
我们继续使用上一篇文章《Spring内核研究-Lookup方法注入》的例子来说明如何使用静态工厂创建Bean。
context.xml
    factory-menthod定义了userDao Bean使用UserDao类的getInstance方法来创建自己的实例。userManager仍然通过lookup方法获得userDao。Lookup方法并不关心一个Bean的实例时怎样创建的,所以可以混合使用lookup方法和factory-menthod方法。
xml version="1.0" encoding="UTF-8"?> DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd"
> <beans> <bean name="userManager" class="research.spring.beanfactory.ch2.UserManager"> <lookup-method name="getUserDao" bean="userDao" /> bean> <bean name="userDao" class="research.spring.beanfactory.ch2.UserDao"
 factory-method="getInstance" / > beans>

UserDao.java
    增加一个getInstance方法来创建自己的实例。
package research.spring.beanfactory.ch2;

public class UserDao {
public static UserDao getInstance() {

return new UserDao("static factory method");
}

private String name = "";

public UserDao(String name) {
this.name = name;
}

public void create() {

System.
out.println("create user from - " + name);
}
}

Test.java
package research.spring.beanfactory.ch2;

import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;

public class Test {

public static void main(String[] args) {

XmlBeanFactory factory
=new XmlBeanFactory(new ClassPathResource(
"research/spring/beanfactory/ch2/context.xml"));

UserManager manager
=(UserManager) factory.getBean("userManager");
manager.createUser();
}

}

运行Test.java,你会看到:

create user from - static factory method

这说明userDao使用它自己得静态工厂创建得。
 
静态工厂方法存在一些限制:
  1. 静态工厂方法上不能有参数,也不能在Spring种定义静态工厂方法的参数。
  2. 静态工厂方法只能是public的,不能是private或protected的。
  3. 静态工厂方法不能和构造函数注入一起使用。下面的定义时不能正常工作的:

 

 

package research.spring.beanfactory.ch2;

import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;

public class Test {

public static void main(String[] args) {

XmlBeanFactory factory=new XmlBeanFactory(new ClassPathResource(
"research/spring/beanfactory/ch2/context.xml"));

UserManager manager=(UserManager) factory.getBean("userManager");
manager.createUser();
}

}
实例工厂注入
    定义一个Bean使用这个Bean的工厂对象上的工厂方法来创建自己。
我们定义一个UserDao的Factory来创建UserDao。
UserDaoFactory.java
package research.spring.beanfactory.ch2;
public class UserDaoFactory{
public UserDao getUserDao(){

return new UserDao("UserDaoFactory");
}
}
修改context.xml:
xml version="1.0" encoding="UTF-8"?> DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd"
> <beans> <bean name="userManager" class="research.spring.beanfactory.ch2.UserManager"> <lookup-method name="getUserDao" bean="userDao" /> bean> <bean name="userDao" class="research.spring.beanfactory.ch2.UserDao"
 factory-bean
="userDaoFactory" factory-method="getUserDao" > bean> <bean name="userDaoFactory" class="research.spring.beanfactory.ch2.UserDaoFactory">
bean> beans>

再次运行Test.java你会看到:
create user from – UserDaoFactory
 
    通过上面的配置Spring已经使用userDaoFactory实例的工厂方法来创建userDao了。
  • factory-bean定义了工厂Bean
  • factory-method定义了工厂方法
 

 

    实例工厂和静态工厂一样都存在相同的限制:
  1. 静态工厂方法上不能有参数,也不能在Spring种定义静态工厂方法的参数。
  2. 静态工厂方法只能是public的,不能是private或protected的。
  3. 静态工厂方法不能和构造函数注入一起使用。

 

   
    和静态工厂不同的是:
  •  实例工厂方法不能是静态的,而静态工厂方法必须是静态的。

 

    通过上面的例子我们看到Spring对工厂模式对了完整的支持。但是这里还是需要说明,如果使用IoC模式设计的系统一般情况下不需要为任何Bean做工厂类。在我的观点里,工厂模式仅仅是遗留系统,使用依赖注入模式可以取代工厂模式。Spring对工厂的支持仅仅是为了可以很好的集成遗留系统。
 
原创粉丝点击