去掉对Spring BeanFacotry的getBean方法的依赖

来源:互联网 发布:linux 获取命令返回值 编辑:程序博客网 时间:2024/06/03 11:39

在使用Spring时,有时会碰到这种情况: 
 

引用
需要在一个类中使用一个非Singlton类型的Bean,比如每次方法调用都需要new一个新的Bean。但是,由于Spring的依赖注入是在Bean初始化完成之后进行的,而且只进行一次,因此就无法在每次方法调用时注入新的Bean。

  那么如何解决这个问题呢,一般的做法可能是实现Spring的ApplicationContextAware接口,然后在没个方法中显示地调用ApplicationContext的getBean方法。如下面代码所示: 
Java代码 
  1. public class ClazzA implements ApplicationContextAware{  
  2.    private ApplicationContext applicationContext;  
  3.   
  4.    void setApplicationContext(ApplicationContext applicationContext){  
  5.        this.applicationContext = applicationContext;  
  6.    }  
  7.   
  8.    public void methodA(){  
  9.       Object bean = this.applicationContext.getBean("...");  
  10.       ...  
  11.    }  
  12.   
  13.    public void methodB(){  
  14.       Object bean = this.applicationContext.getBean("...");  
  15.       ...  
  16.    }  
  17.   
  18.    ...  
  19. }  

  上面的代码可以解决我们之前说的问题,但是,这样做就形成了对Spring框架代码的依赖,降低了应用程序代码的可以执行和可重用性。 
  不过不用担心,Spring已经为我们考虑到了这一点,并且提供了几种更好的解决方案。下面讲一下其中的两种。这两种方法Spring都是通过使用CGLIB自动生成字节码来完成的。 
  解决方案一:Lookup Method。 
  仍然以上面的ClazzA为例。这种方法需要将ClazzA定义为抽象类,并在该类中定义一个抽象的createBean方法。修改后的代码如下: 
Java代码 
  1. public abstract class ClazzA{  
  2.    public void methodA(){  
  3.       ClazzB bean = this.applicationContext.getBean("...");  
  4.       ...  
  5.    }  
  6.   
  7.    public void methodB(){  
  8.       ClazzB bean = this.applicationContext.getBean("...");  
  9.       ...  
  10.    }  
  11.   
  12.    public abstract ClazzB createBean();  
  13.    ...  
  14. }  

然后在Spring的配置文件中做如下定义: 
Xml代码 
  1. <bean id="clazzB" class="edu.sjtu.spring.ClazzB" scope="prototype">  
  2.   <!-- inject dependencies here as required -->  
  3. </bean>  
  4.   
  5. <!-- commandProcessor uses statefulCommandHelper -->  
  6. <bean id="clazzA" class="edu.sjtu.spring.ClazzA">  
  7.   <lookup-method name="createBean" bean="command"/>  
  8. </bean>  

这样定义之后,Spring就会使用CGLIB自动生成一个实现了createBean方法的ClazzA的一个实现类,并让createBean返回ClazzB。 
上面所说的那个createBean方法必须符合下面的方法签名: 
Java代码 
  1. <public|protected> [abstract] <return-type> theMethodName(no-arguments);  


详细信息可以参见Spring文档的3.4节。 
  解决方案二:使用ServiceLocatorFactoryBean。 
  这种方案交第一种方案更加灵活一点,但是付出的代价是要单独定一个工厂接口。这种方法在Spring的ServiceLocatorFactoryBean类的API文档中有详细介绍,这里就不再累述了。

原创粉丝点击