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.

 

你可能感兴趣的:(spring,xml,bean,performance)