`

lookup-method (1)

阅读更多

“Lookup方法”可以使Spring替换一个bean原有的,获取其它对象具体的方法,并自动返回在容器中的查找结果。
我们来 看这个例子:
UserDao.java
    在UserDao的构造函数中接受一个name参数,创建UserDao的对象会把自己的名字传递给userDao,这样userDao的create方 法中就会把userDao的创建者打印出来。

package research.spring.beanfactory.ch2;
public class UserDao {  
    private String name="";  
    public UserDao(String name){
              this.name=name;  
    }  
    public void create(){
              System.out.println("create user from - "+name);
    }
}
 


UserManager.java
    在这段代码中UserManager依靠getUserDao方法来获取UserDao对象。由于在getUserDao方法里显示的声明了如何去实例一 个UserDao,所以上面的代码不符合IoC模式的风格。虽然使用GetUserDao封装了UserDao的创建过程,但是UserManager和 UserDao的关系仍然非常紧密。

package research.spring.beanfactory.ch2;
public class UserManager {
      public UserDao getUserDao() {
              return new UserDao("UserManager.getUserDao()");
       }
       public void createUser() {
              UserDao dao = getUserDao(); //通过getUserDao获得userDao
             dao.create();
        }
}
 

LookupMethodTest.java
    通过BeanFactory获得UserManager,并调用createUser方法。

package research.spring.beanfactory.ch2;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
public class LookupMethodTest {
        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();    //create a User
        }
}
 


   context.xml

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">
   </bean>
    <bean name="userDao class="research.spring.beanfactory.ch2.UserDao" >
    </bean>
</beans>
 


运行LookupMethodTest你会看到屏幕输入” create user from - UserManager.getUserDao()”。

    由于是遗留系统,所以我们不能修改UserManager。现在我希望让这个UserManager依赖的Dao对象由spring管理,而不修改原有的 代码。
    在这个场景中我们就可以利用Spring提供的“Lookup方法”来替换原有的getUserDao方法,实现自动获取userDao的功能。修改 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" >
       <constructor-arg>
           <value>lookup method</value>
       </constructor-arg>
    </bean>
    <bean name="userDaoFactory" class="research.spring.beanfactory.ch2.UserDaoFactory">
    </bean>
</beans>
 


    再次运行LookupMethodTest你会看到不同的输出结果“create user from - lookup method”。字符串“lookup method”是通过构造函数注入给userDao的。原来的userManager.java并没有作任何修改,仍然是通过UserDao dao = getUserDao();来获得userDao的。这说明Spring已经替换了原有的getUserDao方法的实现,当执行getUserDao时 Spring会在容器中寻找指定的Bean,并返回这个Bean。

Lookup方法的工作机制
    通过这种机制我们可以在不修改原系统代码的情况下,可以轻易的把UserDao换成别的类型相容的对象而不会影响原系统。Spring是使用CGLIB在 字节码级别动态实现出userManager的子类,并重写getUserDao方法的方式来实现这个神奇的功能的。
修改 LookupMethodTest.java:

package research.spring.beanfactory.ch2;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
public class LookupMethodTest {
        public static void main(String[] args) {
              XmlBeanFactory factory=new XmlBeanFactory(new ClassPathResource(
         "research/spring/beanfactory/ch2/context.xml"));
              UserManager manager=(UserManager) factory.getBean("userManager");
              System.out.println(manager.toString()); //打印userManager的信息
              manager.createUser();    //create a User
        }
}
 


    我们在获取UserManager的实例后打印出这个实例的信息,再次运行LookupMethodTest你会看到:

注意manager.toString()打印出了:
research.spring.beanfactory.ch2.UserManager$$EnhancerByCGLIB$$886cdee9@1238bd2
    这个是CGLIG动态生成的类,而不是原来的UserManager的实例。所以请记住在任何时候只要定义了一个Bean的Lookup方法,那么这个 Bean的实例将是一个CGLIB动态生成的实例而不是原来类的实例。

Spring允许在一个Bean中定义多个Lookup方法。

<bean name="userManager"       class="research.spring.beanfactory.ch2.UserManager">
       <lookup-method name="getUserDao" bean="userDao" />
       <lookup-method name="getOtherDao" bean="otherDao" />
</bean>
 

 上面的做法是合法的,并且可以正常工作。

    虽然Spring会用CGLIB动态生成一个带有Lookup方法bean的子类,但是这并不影响Spring完成其它的功能。Sping还是允许 Lookup方法和setXXX、构造函数注入以及后面我们将介绍的自动依赖检查和自动装配的功能同时使用。

    Spring还允许Lookup方法中定义的方法带有参数,但是Sping不会处理这些参数。
修改UserManager:

package research.spring.beanfactory.ch2;
public class UserManager {
       private UserDao dao;
        public void setDao(UserDao dao) {
              this.dao = dao;
       }
        public UserDao getUserDao(String daoName){
              return new UserDao("UserManager.getUserDao()");
       }
        public void createUser(){
              UserDao dao = getUserDao(“userDao”); //通过getUserDao获得userDao
              dao.create();
        }
}
 


  虽然方法上由参数,但是上面的代码可以正常工作。Spring不会处理这些参数。

Spring对Lookup方法也存在一些限制:
方 法不能是private的,但可以是protected的。
方法不能是静态的。
在抽象类和接口上应用Lookup方法有一个比较有趣 的用法,就是在抽象类上定义Lookup方法。你一定记得经典的工厂模式吧。定义一个抽象工厂,然后为每一类具体产品实现一个具体产品的工厂。
一 个抽象工厂:

package research.spring.beanfactory.ch2;
public abstract class Factory {
   public abstract UserDao getProduct();
}
 


具体一类产品 的工厂:

package research.spring.beanfactory.ch2;
public class UserDaoFactory extends Factory{
   public UserDao getProduct(){
          return new UserDao("UserDaoFactory");
   }
}
 

 

用户可以通过:
new UserDaoFactory().getProduce();
来获取具体的UserDao产品。
    但是如果有很多产品就需要做出实现出很多工厂如,DocumentDaoFactory、GroupDaoFactory等等,这样系统中会出现大量的工 厂。工厂的泛滥并不能说明系统的设计是合理的。
    既然Spring可以在抽象类上使用Lookup方法,那么我们就可以不同实现真的去实现那么多的子类了。我们可以在抽象类上直接定义Lookup方法和 目标对象。用户直接通过抽象类来获得需要的产品对象。看下面这个例子:
Factory.java

package research.spring.beanfactory.ch2;
public abstract class Factory {
   public abstract Object getProduct();
}
 

context.xml
    如果指定userDaoFactory的类为一个抽象类,并且再这个bean里定义了Lookup方法,那么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="userManager"       class="research.spring.beanfactory.ch2.UserManager">
       <lookup-method name="getUserDao" bean="userDao" />
   </bean>
    <bean name="userDao" class="research.spring.beanfactory.ch2.UserDao" >
       <constructor-arg>
               <value>lookup method</value>
       </constructor-arg>
   </bean>
    <bean name="userDaoFactory" class="research.spring.beanfactory.ch2.Factory" singleton="false">
      <lookup-method name="getProduct" bean="userDao" />
    </bean>
</beans>
 

Test.java

package research.spring.beanfactory.ch2;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
public class LookupMethodTest{
        public static void main(String[] args){
              XmlBeanFactory factory=new XmlBeanFactory(new ClassPathResource("research/spring/beanfactory/ch2/context.xml"));
              //获得抽象工厂
              Factory abstractFactory=(Factory) factory.getBean("userDaoFactory");
              UserDao userDao=(UserDao) abstractFactory.getProduct();
              System.out.println(userDao.toString());
              userDao.create();
       }
}
 

 

运行Test你会看到:
research.spring.beanfactory.ch2.UserManager$$EnhancerByCGLIB$$cc2f8f1c@12c7568
create user from - lookup method

    对,这个结果和上面的例子是完全一样的。UserDao并没有改变,我们通过抽象的Factory获得了具体的UserDao的实例。这样即使系统中很多 的具体产品我们也不需要实现每类产品的工厂类了。只需要在系统中配置多个抽象工厂,并且配置每个工厂的singlton为false,在用户使用时使用不 同抽象工厂的实例就可以了。

<bean name="userDaoFactory" class="research.spring.beanfactory.ch2.Factory" singleton="false">
       <lookup-method name="getProduct" bean="userDao" />
</bean>
<bean name="documentDaoFactory" class="research.spring.beanfactory.ch2.Factory" singleton="false">
       <lookup-method name="getProduct" bean="documentDao" />
</bean>
 


Spring 不关心抽象类中的定义的lookup方法是否时抽象的,Spring都会重写这个方法。

    既然Sping可以动态实现抽象类的子类那么,它能不能动态创建出实现一个接口的类呢。答案时肯定的。上面的例子可以直接把Factory变成一个接口, 仍然可以正常工作。
    这里需要注意的是,只要在一个Bean上明确的定义了Lookup方法,Spring才会使用CGLIB来做原对象的字节码代理。如果一个没有定义 Lookup方法的抽象类或接口是不能直接被Spring实例的。

    本文介绍了Lookup方法的使用和工作原理,希望读者能够对Lookup方法有了比较深入的了解。虽然我的例子可以简化工厂模式,但是我并不鼓励大家在 实际系统中这样做。因为我始终认为“工厂模式”只要在遗留系统中才会碰到。使用IoC模式基本上可以替代所有的对象创建模式。本章的例子只是为了说明 Lookup方法如何使用,和Lookup方法的一些特殊情况。Lookup方法一般只在处理遗留代码时使用。

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/qking93415981/archive/2007/08/10/1735617.aspx

分享到:
评论
发表评论

文章已被作者锁定,不允许评论。

相关推荐

    深入理解Spring中的Lookup(方法注入)

    &lt;lookup-method name="getClassB" bean="classB"/&gt; ``` Java配置: ```java @Configuration public class AppConfig { @Bean @Scope("prototype") public ClassB classB() { return new ClassB(); } @...

    lookup-dns-cache:通过避免线程池并为特定主机名使用DNS TTL缓存来加速nodejs`dns.lookup`方法的实现

    // With "request" modulerequest ( { url : 'http://google.com' , method : 'GET' , lookup : lookup} , ( error , response , body ) =&gt; { // ...} ) ;// Direct usagelookup ( 'google.com' , { } , ( error , ...

    dns-lookup-cache:通过避免线程池并为特定主机名使用DNS TTL缓存来加速nodejs“ dns.lookup”方法的实现

    dns-lookup- dns.lookup... method : 'GET' , lookup : lookup } , ( error , response , body ) =&gt; { // ... } ) ; // Direct usage lookup ( 'google.com' , { } , ( error , address , family ) =&gt; { // ... }

    Spring ApplicationContext.xml配置的12个技巧演示教学.pdf

    lookup-method 可以用来注入 Bean,避免了硬编码的依赖关系。 7. 使用 factory-method 来实例化 Bean factory-method 可以用来实例化 Bean,提供了更多的灵活性。 8. 使用 depends-on 来指定 Bean 的依赖关系 ...

    Spring实战之协调作用域不同步的Bean操作示例

    `&lt;lookup-method&gt;`元素用于定义一个lookup-method,`&lt;property&gt;`元素用于设置Bean的属性值。 接口和实现类 在本文示例中,我们定义了两个接口:Dog和Person。Dog接口定义了一个run方法,Person接口定义了一个hunt...

    JAVA spring 系列案例50个和学习资料

    Spring系列第12篇:lazy-init:bean延迟初始化Spring系列第13篇:使用继承简化bean配置(abstract & parent)Spring系列第14篇:lookup-method和replaced-method比较陌生,怎么玩的?Spring系列第15篇:代理详解(Java...

    Remote-method-invocation

    远程方法调用(Remote Method Invocation,RMI)是Java编程语言中的一种机制,它允许一个对象在某个Java虚拟机(JVM)上执行方法,而该对象实际位于另一个JVM中。这种技术使得分布式计算成为可能,使得Java应用程序...

    spring学习笔记

    2. 使用方法注入(lookup-method),让容器在运行时重写bean的方法,返回其他bean的新实例。 Spring还提供了定制bean生命周期行为的机制。例如,可以在bean初始化完成后执行特定操作: 1. 使用`init-method`属性,...

    RESTLET开发(三)

    &lt;lookup-method name="create" bean="StudentResource"/&gt; &lt;lookup-method name="create" bean="StudentsResource"/&gt; ``` 这段配置指定了两个URL路径:`/student/{studentId}` 和 `/student`,...

    RMI客户端调用远程服务器方法-远程方法调用

    在Java编程领域,远程方法调用(Remote Method Invocation,RMI)是一种强大的技术,它允许一个Java对象在某个JVM(Java虚拟机)上执行另一个JVM中的对象的方法。RMI是分布式计算的基础,尤其在构建分布式应用程序时...

    spring 静态实例化

    例如,在提供的代码示例中,我们看到了一个名为`useType`的Bean实例被定义,并且通过`&lt;lookup-method&gt;`指定了一个名为`getMyType`的方法,该方法返回另一个名为`test.sat.type.MyType.TypeOne`的Bean实例。...

    spring-beans-3.0.xsd

    在`&lt;bean&gt;`元素中,`lookup-method`和`replaced-method`属性的引入,使得在运行时动态查找或替换bean的方法成为可能,这是对AOP(面向切面编程)的一种补充,提供了更细粒度的控制。 除此之外,`&lt;util&gt;`命名空间在...

    Spring源码总结.pdf

    在解析`bean`时,会创建`GenericBeanDefinition`对象,设置属性,处理元数据、lookup-method、replaced-method、构造参数、属性、qualifier等。 4. **自定义标签解析**: - 自定义标签解析涉及到Spring的命名空间...

    Spring 框架中注入或替换方法实现

    在上面的示例中,我们使用 lookup-method 标签来注入 getAuthor() 方法,该方法将返回一个新的 Author Bean 的实例。 四、单元测试 为了验证上述实现,我们可以编写单元测试来测试该实现。例如,我们可以编写以下...

    wget-1.11.4-1

    --dns-timeout=SECS set the DNS lookup timeout to SECS. --connect-timeout=SECS set the connect timeout to SECS. --read-timeout=SECS set the read timeout to SECS. -w, --wait=SECONDS wait SECONDS ...

    Spring2.0的配置2

    10. **使用`&lt;lookup-method&gt;`和`&lt;factory-method&gt;`**: 这两个元素允许在运行时动态创建bean,而不是在配置时静态定义。这对于实现策略模式或动态代理等场景很有帮助。 11. **使用`&lt;bean&gt;`的`lazy-init`属性**: ...

    Spring中xml的配置[定义].pdf

    除了这些核心概念,Spring的XML配置还包括其他元素,如`&lt;import&gt;`引入其他配置文件,`&lt;alias&gt;`为bean定义别名,以及`&lt;lookup-method&gt;`和`&lt;replaced-method&gt;`来处理方法的动态代理等。XML配置提供了一种声明式的方式...

    unigui0.83.5.820

    - 0000776: UniDBLookUpXXX: ListSource cursor position does not follow Lookup value - 0000773: UniDBGrid: Column.Title.Font/Color - 0000771: UniDBGrid: Column.Font property - 0000772: UniDBGrid: ...

Global site tag (gtag.js) - Google Analytics