`
ihyperwin
  • 浏览: 425959 次
  • 性别: 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(方法注入)

    “Lookup方法”可以使Spring替换一个bean原有的,获取其它对象具体的方法,并自动返回在容器中的查找结果。下面这篇文章主要给大家介绍了关于Spring中Lookup(方法注入)的相关资料,需要的朋友可以参考下

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

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

    requestUtils lookup方法简介

    requestUtils lookup方法简介

    Ofbiz之LOOKUP字段使用方法

    Ofbiz的Lookup字段,讲解ofbiz辅助输入,包括文本,选择框,日期,时间,主从文本框。后面还介绍一下自定义修改的Lookup

    spring-jndi-lookup:如何使用Spring从JNDI查找数据源

    如何使用Spring从JNDI查找数据源 Server.xml &lt;资源名称=“ jdbc / javatechie”全局=“ jdbc / javatechie” auth =“容器” type =“ javax.sql.DataSource” driverClassName =“ com.mysql.jdbc.Driver” url...

    【含源码和addin】RevitLookup 2020

    【亲测可用】Revit 2020 Lookup Tables是Revit表格查找工具,是revit开发必不可少的一个组件,需要的朋友可以下载! 用法:将RevitLookup.addin和RevitLookup.dll放到C:\ProgramData\Autodesk\Revit\Addins\2019下...

    Spring-Reference_zh_CN(Spring中文参考手册)

    Lookup方法注入 3.3.8.2. 自定义方法的替代方案 3.4. bean的作用域 3.4.1. Singleton作用域 3.4.2. Prototype作用域 3.4.3. 其他作用域 3.4.3.1. 初始化web配置 3.4.3.2. Request作用域 3.4.3.3. Session作用域 3.4...

    springioc和spring aop

    其中最常见的方式叫做依赖注入(Dependency Injection,简称DI),还有一种方式叫“依赖查找”(Dependency Lookup)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体,将其所依赖的对象的...

    vc错误查看工具lookup

    vc错误查看工具lookup vc错误查看工具lookup

    Spring.3.x企业应用开发实战(完整版).part2

    4.5.1 lookup方法注入 4.5.2 方法替换 4.6 之间的关系 4.6.1 继承 4.6.2 依赖 4.6.3 引用 4.7 整合多个配置文件 4.8 Bean作用域 4.8.1 singleton作用域 4.8.2 prototype作用域 4.8.3 Web应用环境相关的Bean作用域 ...

    RevitLookup-2021.0.0.13

    RevitLookup-2021.0.0.13,供各位做REVIT二次开发的同仁们下载、学习、研究。

    RevitLookup2018

    Revit2018的Lookup

    informatica lookup 组件使用案例

    informatica lookup 组件使用案例

    RevitLookup-2019.0.0.3.rar

    Revit二次开发必助插件revit lookup,辅助开发人员查看revit内部结构。方便开和学习内部结构

    RevitLookup-2016.0.0.6 已编译 直接使用

    revit开发必备工具 本包中是已经编译过的文件,可以直接使用 ...编辑其中RevitLookup.dll 路径为编译路径 C:\RevitLookup-2016.0.0.6\CS\bin\Debug\RevitLookup.dll 重启revit: 即可在菜单栏看到工具

    lookup滤镜详解.docx

    详解lookup滤镜原理及用法,Lookup是基于图片颜色映射的一种滤镜,它可以实现各种各样的效果。

    Revit2018 Lookup

    Revit 2018 Lookup Tables顾名思义就是Revit表格查找工具,revit二次开发是离不开这个按钮的,由于revit中管件和线管配件族的尺寸参数会随着公称直径的变化而变化,revit可以通过这个按钮来实现这个功能,是revit...

    lookup函数的使用

    excel 函数教程 lookup函数的经典查找使用方式

    NetBeans lookup的例子

    用NetBeans8.0做的的一个lookup查询的例子

    LOOKUP函数处理内存数组

    LOOKUP函数处理内存数组,LOOKUP高级应用.

Global site tag (gtag.js) - Google Analytics