`
ihyperwin
  • 浏览: 434558 次
  • 性别: Icon_minigender_1
  • 来自: 南京
社区版块
存档分类
最新评论

Spring之方法注入(lookup method)

 
阅读更多
Spring使用CGLIB的动态字节码增强功能,所以,必须要加入CGLIB包

当Bean依赖另一个生命周期不同的bean,尤其是当singleton依赖一个non-singleton时,常会遇到不少问题,Lookup Method Injection正是对付这些问题而出现的,在上述情况中,setter和构造注入都会导致singleton去维护一个non-singleton bean的单个实例,某些情况下,我们希望让singleton bean每次要求获得bean时候都返回一个non-singleton bean的新实例

当一个singleton bean A 在每次方法调用的时候都需要一个non-singleton bean B,此时就会产生这样一个问题,因为A为singleton,所以容器只会创建一次A,那么也只有一次机会来创建A的属性,Bean B也只能被初始化一次,但是我们调用每个方法的时候又都需要一个新的B的实例。通常的时候我们只要new一个就可以,但在Spring中这不符合整体性的设计,这样就有了方法注入。
       让我们开始一个简单的测试。
       在你的工程的根目录中分别建立一个src,classes,lib文件夹。此次我们将采用Ant来进行部署。
       在src中建立Random.java,HelloRandom.java,HelloAbstract.java,Test.java。代码如下。
       Random.java这是一个可以产生随机数的类,很简单。

    package com.testspring.basic.lookup;
       public class Random {
               private int num = (int)(100*Math.random());
               public void printRandom(){
                   System.out.println("随机数是"+num);
               }
        }
     
    HelloRandom.java一个代理接口。

     package com.testspring.basic.lookup;
    public interface HelloRandom {
        public Random getRandom();
        public abstract Random createRandom();    //这个方法最为重要,是方法注入的关键
    }
     
    HelloAbstract.java

     package com.testspring.basic.lookup;
    public abstract class HelloAbstract implements HelloRandom{
        private Random random;
        public void setRandom(Random random){
              this.random = random;
        }
        public Random getRandom(){
            return this.random;
         }
        public abstract Random createRandom();
    }
     
       Test.java用于测试

    package com.testspring;
       import org.springframework.context.ApplicationContext;
       import com.testspring.basic.lookup.*;
       public class Test {
           public static void main(String[] args) {
             try{
                  ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
                  HelloRandom helloRandom = (HelloRandom)context.getBean("helloRandom");
                    System.out.println("下面两个实例没有采用方法注入");
                    Random r1 = helloRandom.getRandom();
                    Random r2 = helloRandom.getRandom();
                    System.out.println("Random 的两个实例是否指向同一个引用:" + (r1 == r2));
                    r1.printRandom();
                    r2.printRandom();
                  System.out.println();
                  System.out.println("下面两个实例采用方法注入");
                    Random r3 = helloRandom.createRandom();
                    Random r4 = helloRandom.createRandom();
                  System.out.println("Random 的两个实例是否指向同一个引用:" + (r3 == r4));
                  r3.printRandom();
                    r4.printRandom();
                 }catch(Exception e){
                     e.printStackTrace();
               }
          }
      }


      在src中建立一个bean.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 id="myRandom" class="com.testspring.basic.lookup.Random" scope="prototype" />
              <bean id="helloRandom" class="com.testspring.basic.lookup.HelloAbstract">
                   <lookup-method name="createRandom" bean="myRandom"/>
                       <property name="random">
                               <ref local="myRandom" />  
                       </property>
             </bean>
     </beans>
     在根目录中建立一个build.xml文件
     <?xml version="1.0" encoding="UTF-8"?>
     <project name="MySpring" default="run" basedir=".">
                       <!-- 全局变量的定义 -->
           <property name="src.dir" value="src" />                       <!-- 源文件位置 -->
           <property name="classes.dir" value="classes" />     <!-- class文件位置 -->
           <property name="lib.dir" value="lib" />                          <!-- 引用的jar文件位置 -->
                      <!--当前工程环境变量-->
           <path id="Project-Classpath">
                  <pathelement path="${classes.dir}"/>
                <fileset dir="${lib.dir}">
                       <include name="*.jar"/>
                   </fileset>
           </path>
                      <!--编译-->
          <target name="compile" depends="clean">
                   <javac srcdir="${src.dir}" destdir="${classes.dir}">
                           <classpath refid="Project-Classpath" />
                   </javac>
          </target>
                      <!--复制除了java文件以外的文件-->
          <target name="copy-resources" depends="compile">
              <copy todir="${classes.dir}">
                    <fileset dir="${src.dir}">
                        <exclude name="**/*.java"/>
                    </fileset>
                   </copy>
        </target>
          <!--运行-->
        <target name="run">
                <java fork="true" classname="com.testspring.Test">
                        <classpath refid="Project-Classpath" />
                </java>
        </target>
     </project>
     将spring.jar,cglib-nodep-2.1_3.jar放入lib中。
     运行build命令就可以看到我们的结果了
    ----------------------------------------------------------------------------------------------
   下面两个实例没有采用方法注入
     Random 的两个实例是否指向同一个引用:true
     随机数是99
   随机数是99

    下面两个实例采用方法注入
    Random 的两个实例是否指向同一个引用:false
    随机数是98
    随机数是17

注意事项:

1.应用场合:一个singleton的Bean需要引用一个prototype的Bean; 一个无状态的Bean需要引用一个有状态的Bean; ... ; 等等情景下.
2.假定你有三个singleton,公用一个依赖,希望每个singleton有自己的实例依赖,所以将依赖设置成singleton,但
   实际上每个singleton在其生命周期中使用协作着的同一个实例足以,这种情况下,setter是最好的选择,使用方
   法查找注入会增加不必要的开销
3.我们也可以使用实现BeanFactoryAware的方式代替Lookup Method Injection

    public void setBeanFactory(Beanfactory factory){
         this.factory=factory;
   }
   public Random createRandom(){
      return (Random)factory.getBean("myRandom");
   }

   使用上述方法在效率上和使用本例的方法,相差无几(100000次差别在几毫秒),所以,建议使用本里的方法,减少和spring api的耦合

4.尽管可以不把查找方法定义成abstract,但还是建议这样做,可以防止不小心忘了配置查找方法而留一个空方法在代码中
5. 记住在任何时候只要定义了一个Bean的Lookup方法,那么这个Bean的实例将是一个CGLIB动态生成的实例而不是原来类的实例。
6.Spring允许在一个Bean中定义多个Lookup方法。
7.Spring还允许Lookup方法中定义的方法带有参数,但是Sping不会处理这些参数。
8.Spring对Lookup方法也存在一些限制:
方法不能是private的,但可以是protected的。
方法不能是静态的。
分享到:
评论

相关推荐

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

    在Spring框架中,Lookup方法注入是一种特殊的依赖注入方式,它允许Spring容器动态替换bean中的某个方法,以便在运行时返回不同实例。这种方法主要用于处理单例bean依赖非单例bean的情况,确保每次调用都能获得一个新...

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

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

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

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

    pro spring 中文版

    - Spring提供了对Bean生命周期的精细控制,如初始化方法(init-method)和销毁方法(destroy-method)。 4. **自动装配(Autowiring)** - 自动装配是Spring框架的一个特性,允许容器自动将依赖项匹配到相应的...

    spring里面想要让一个类的实例在所有属性都准备好之后就让它自动执行某些方法

    在Spring框架中,如果你希望一个类的实例在所有属性注入完成后自动执行某些特定的方法,你可以利用Spring的初始化回调机制。这个机制允许你在对象完全构造并准备好执行业务逻辑时执行一些自定义的操作。以下是对这个...

    spring-beans-3.0.xsd

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

    对于Spring初学者的学习建议

    - **Template Method模式**:理解Spring中的模板方法模式如何简化代码结构。 推荐阅读《Expert one-on-one J2EE Design and Development》的第四章,该章节不仅适合Spring初学者,也是Java开发者必读的经典内容。 ...

    spring rmi 集成

    5. **Spring配置**:在Spring的配置文件中,可以使用`&lt;bean&gt;`标签定义RMI服务,并使用`&lt;lookup-method&gt;`标签来查找并注入远程对象。 ```xml &lt;bean id="myServiceExporter" class="org.springframework.remoting...

    spring学习笔记

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

    Spring 配置文件 和详细笔记

    Spring 框架是Java开发中的一个核心组件,它提供了依赖注入(Dependency Injection,DI)和面向切面编程(Aspect-Oriented Programming,AOP)等特性,极大地简化了企业级应用的开发工作。Spring配置文件是Spring...

    spring 静态实例化

    Spring框架作为Java领域中最为广泛使用的依赖注入(Dependency Injection, DI)容器之一,其强大的功能不仅体现在对复杂系统的管理上,还包括了许多高级特性,如静态实例化。本文将深入探讨Spring中的静态实例化概念...

    spring3.0 xsd文件

    10. `&lt;bean&gt;`的`init-method`和`destroy-method`属性:指定bean初始化和销毁时调用的方法。 Spring 3.0-xsd压缩包可能包含了Spring的核心配置XSD、AOP配置XSD、数据源配置XSD等多个文件,这些文件一起构成了Spring ...

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

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

    spring+rmi实现非本地部署

    在IT行业中,Spring框架是Java领域最常用的轻量级应用框架之一,而RMI(Remote Method Invocation)则是Java提供的一种远程方法调用机制,用于构建分布式应用程序。将Spring与RMI结合,可以实现非本地部署的服务,...

    java spring rmi

    Java Spring RMI(Remote Method Invocation)是Java平台上用于构建分布式应用程序的一种技术,它允许Java对象在不同的JVM(Java Virtual Machine)之间进行交互。Spring框架提供了对RMI的支持,简化了RMI的配置和...

    Spring 2.x配置详解

    这段配置查找 JNDI 名称为 `java:comp/env/jdbc/myDS` 的数据源,并将其引用作为 `dataSource` 注入到其他 bean 中。 #### Spring Annotations Spring 2.5 引入了丰富的注解集,这些注解有助于减少 XML 配置的数量...

    Spring(RMI)实例

    Spring框架是Java开发中广泛应用的轻量级框架,它提供了丰富的功能来简化应用程序的构建,包括依赖注入、AOP(面向切面编程)以及多种集成技术。RMI(Remote Method Invocation,远程方法调用)是Java平台上的一个...

Global site tag (gtag.js) - Google Analytics