summary of Spring method injection

Method Injection was introduced in Spring 1.1, which comes in two loosely related forms, Lookup Method Injection and Method Replacement.

Lookup Method Injection

It's added to overcome the problems encountered when a bean depends on another bean with a different lifecycle - specifically, when a singleton depends on a non-singleton.

Here's an example, we create one non-singleton bean and two singleton beans that both implement the same interface. One of the singletons obtains an instance of the non-singleton bean using "traditional" setter injection; the other uses Method Injection.

java: non-singleton bean 
  1. public class MyHelper {   
  2.        
  3.     public void doSomethingHelpful() {   
  4.         // do something!   
  5.     }   
  6. }  
java: this interface will be implemented by two singleton beans
  1. public interface DemoBean {   
  2.        
  3.     public MyHelper getMyHelper();   
  4.     public void someOperation();   
  5. }  
java: traditional singleton bean
  1. public class StandardLookupDemoBean implements DemoBean {   
  2.        
  3.     private MyHelper helper;   
  4.        
  5.     public void setMyHelper(MyHelper helper) {   
  6.         this.helper = helper;   
  7.     }   
  8.        
  9.     public MyHelper getMyHelper() {   
  10.         return this.helper;   
  11.     }   
  12.        
  13.     public void someOperation() {   
  14.         helper.doSomethingHelpful();   
  15.     }   
  16. }  
java: method injection bean
  1. public abstract class AbstractLookupDemoBean implements DemoBean {   
  2.        
  3.     public abstract MyHelper getMyHelper();   
  4.        
  5.     public void someOperation() {   
  6.         getMyHelper().doSomethingHelpful();   
  7.     }   
  8. }  
xml: configuration file
  1. <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"    
  2. "http://www.springframework.org/dtd/spring-beans.dtd">  
  3. <beans>  
  4.     <bean id="helper" class="MyHelper"    
  5.           singleton="false"/>  
  6.     <bean id="abstractLookupBean"    
  7.           class="AbstractLookupDemoBean">  
  8.         <lookup-method name="getMyHelper" bean="helper"/>  
  9.     </bean>  
  10.     <bean id="standardLookupBean"    
  11.           class="StandardLookupDemoBean">  
  12.         <property name="myHelper">  
  13.             <ref local="helper"/>  
  14.         </property>  
  15.     </bean>  
  16. </beans>  

Use Method Lookup Injection when you're working with beans of different lifecycles rather than implementing BeanFactoryAware and performing the lookup manually. Using Method Lookup Injection, you can keep your beans decoupled from Spring without any noticeable performance loss.

Although you don't have to make your lookup method abstract, doing so prevents you from forgetting to configure the lookup method and then using a blank implementation by accident.

Method Replacement

Using method replacement, you can replace the implementation of any method on any beans arbitrarily without having to change the source of the bean you are modifying.

Internally you achieve this by creating a subclass of the bean class dynamically. You use CGLIB and redirect calls to the method you want to replace to another bean that implements the MethodReplace interface.

java: any one of the two formatMessage methods can be replaced
  1. public class ReplacementTarget {   
  2.        
  3.     public String formatMessage(String msg) {   
  4.         return "<h1>" + msg + "</h1>";   
  5.     }   
  6.        
  7.     public String formatMessage(Object msg) {   
  8.         return "<h1>" + msg + "</h1>";   
  9.     }   
  10. }  
java: method replacer class, must implement MethodReplacer interface
  1. public class FormatMessageReplacer implements MethodReplacer {   
  2.        
  3.     public Object reimplement(Object target, Method method, Object[] args)   
  4.             throws Throwable {   
  5.        
  6.         if (isFormatMessageMethod(method)) {   
  7.        
  8.             String msg = (String) args[0];       
  9.             return "<h2>" + msg + "</h2>";   
  10.         } else {   
  11.             throw new IllegalArgumentException("Unable to reimplement method "  
  12.                     + method.getName());   
  13.         }   
  14.     }   
  15.        
  16.     private boolean isFormatMessageMethod(Method method) {   
  17.        
  18.         // check correct number of params   
  19.         if (method.getParameterTypes().length != 1) {   
  20.             return false;   
  21.         }       
  22.         // check method name   
  23.         if (!("formatMessage".equals(method.getName()))) {   
  24.             return false;   
  25.         }      
  26.         // check return type   
  27.         if (method.getReturnType() != String.class) {   
  28.             return false;   
  29.         }      
  30.         // check parameter type is correct   
  31.         if (method.getParameterTypes()[0] != String.class) {   
  32.             return false;   
  33.         }       
  34.         return true;   
  35.     }   
  36. }  
xml: mind the replaced-method portion
  1. <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"    
  2. "http://www.springframework.org/dtd/spring-beans.dtd">  
  3. <beans>  
  4.     <bean id="methodReplacer"    
  5.           class="FormatMessageReplacer"/>  
  6.     <bean id="replacementTarget"    
  7.           class="ReplacementTarget">  
  8.         <replaced-method name="formatMessage" replacer="methodReplacer">  
  9.             <arg-type>String</arg-type>  
  10.         </replaced-method>  
  11.     </bean>  
  12.     <bean id="standardTarget"    
  13.           class="ReplacementTarget"/>  
  14. </beans>  
java: testing code piece
  1. public class MethodReplacementExample {   
  2.        
  3.     public static void main(String[] args) {   
  4.         BeanFactory factory = new XmlBeanFactory(new FileSystemResource(   
  5.                 "./replacement.xml"));   
  6.        
  7.         ReplacementTarget replacementTarget =    
  8.                           (ReplacementTarget) factory.getBean("replacementTarget");   
  9.         ReplacementTarget standardTarget =    
  10.                              (ReplacementTarget) factory.getBean("standardTarget");   
  11.        
  12.         displayInfo(replacementTarget);   
  13.         displayInfo(standardTarget);   
  14.     }   
  15.        
  16.     private static void displayInfo(ReplacementTarget target) {   
  17.         System.out.println(target.formatMessage("Hello World!"));   
  18.        
  19.         StopWatch stopWatch = new StopWatch();   
  20.         stopWatch.start("perfTest");   
  21.        
  22.         for (int x = 0; x < 1000000; x++) {   
  23.             String out = target.formatMessage("foo");   
  24.         }   
  25.        
  26.         stopWatch.stop();   
  27.        
  28.         System.out.println("1000000 invocations took: "  
  29.                 + stopWatch.getTotalTimeMillis() + " ms");   
  30.     }   
  31. }  

result:

<h2>Hello World!</h2>
1000000 invocations took: 3609 ms
<h1>Hello World!</h1>
1000000 invocations took: 844 ms

We still prefer to use standard Java mechanisms for overriding methods rather than depending on runtime bytecode enhancement. If you're going to use it, the recommendation is to use one MethodReplacer per method or group of overloaded methods. Avoid the temptation to use a single MethodReplacer for lots of unrelated methods; this results in lots of unnecessary String comparisons.

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值