lookup-method and the injection replace-method

Official documentation:

In section 1.4.6 of the core Spring5

In most applications, the container most of the bean are singletons . When singleton bean needs collaboration with another non-singleton bean singleton bean needs another embodiment when cooperative non-single bean, bean is typically defined by a bean property to another process dependencies. When the bean life cycle does not cause problems at the same time. A single embodiment of the bean is assumed that requires non-singleton (prototype) bean B, each method may be called on the A. Example bean A container creates only a single, so only one chance to set the properties. Each time desired, the container can not offer a new instance of bean B bean A.

The solution is to give up some control reversal. You can implement ApplicationContextAwareinterface to the make of the bean Aware The Container A , and through to the container making a getBean ( " B") call request each time Bean A needs (typically new) bean B instance. The following example shows the method:

// a class that uses a stateful Command-style class to perform some processing
package fiona.apple;
​
// Spring-API imports
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
​
public class CommandManager implements ApplicationContextAware {
​
    private ApplicationContext applicationContext;
​
    public Object process(Map commandState) {
        // grab a new instance of the appropriate Command
        Command command = createCommand();
        // set the state on the (hopefully brand new) Command instance
        command.setState(commandState);
        return command.execute();
    }
​
    protected Command createCommand() {
        // notice the Spring API dependency!
        return this.applicationContext.getBean("command", Command.class);
    }
​
    public void setApplicationContext(
            ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}

 

The foregoing is undesirable, because the service code and coupled to know Spring Framework. Method injection is an advanced feature Spring IoC container, allows you to cleanly handle this use case.

Find Method Injection

Lookup Method is a method of injecting a management bean container cover and the container vessel returns the search results to another named bean ability. Find relates generally prototype bean, such as the preceding section in the scene described. Spring Framework covering dynamically generated subclass of this method to implement this method by using the injection CGLIB library to generate bytecode.

  • To make this work dynamic subclass, Spring bean container can not subclass finalof a class, and can not be rewritten final.

  • To have a abstractunit test class method requires you to own this class subclass, and provides abstractstub implementation methods.

  • Scanning assembly also requires a specific method, which requires a specific class to get.

  • Another key is to find a method to limit does not apply to factory methods, in particular, the configuration is not a class @Beanmethod, because in this case the container is not responsible for creating instances can not be created dynamically generated subclass runtime.

For the previous code segment CommandManagerclass, Spring dynamically container cover createCommand()implementation of the method. CommandManagerSpring class has no dependencies, because the sample rewritten show:

package fiona.apple;
​
// no more Spring imports!
public abstract class CommandManager {
​
    public Object process(Object commandState) {
        // grab a new instance of the appropriate Command interface
        Command command = createCommand();
        // set the state on the (hopefully brand new) Command instance
        command.setState(commandState);
        return command.execute();
    }
​
    // okay... but where is the implementation of this method?
    protected abstract Command createCommand();
}

 

To injection containing the client class (in this case CommandManager), the method needs to be injected in the form of signature:

<public|protected> [abstract] <return-type> theMethodName(no-arguments);

If the method abstractis dynamically generated subclass implement the method. Otherwise, dynamically generated subclass specific methods defined in the cover original class. Consider the following example:

<!-- a stateful bean deployed as a prototype (non-singleton) -->
<bean id="myCommand" class="fiona.apple.AsyncCommand" scope="prototype">
    <!-- inject dependencies here as required -->
</bean><!-- commandProcessor uses statefulCommandHelper -->
<bean id="commandManager" class="fiona.apple.CommandManager">
    <lookup-method name="createCommand" bean="myCommand"/>
</bean>

 

Identified as commandManagerthe bean need myCommandto call their own when a new instance of the bean's createCommand()methods. If you actually need, you have to be careful myCommandbean deployed as a prototype. If Singleton , always returns the myCommandsame instance of the bean.

Alternatively, annotation-based component model, you can @Lookupfind a method, as shown in the following example annotation statement:

public abstract class CommandManager {
​
    public Object process(Object commandState) {
        Command command = createCommand();
        command.setState(commandState);
        return command.execute();
    }
​
    @Lookup("myCommand")
    protected abstract Command createCommand();
}

 

Alternatively, a more conventional nature, you can rely on the return type resolution target for bean lookup method of statement:

public abstract class CommandManager {
​
    public Object process(Object commandState) {
        MyCommand command = createCommand();
        command.setState(commandState);
        return command.execute();
    }
​
    @Lookup
    protected abstract MyCommand createCommand();
}

 

Please note that you should generally use specific stub implementation to declare this search method annotated to make them compatible with the rules of the Spring component scans, which by default abstract class is ignored. This restriction does not apply explicit registration or explicitly imported bean class.

Any method to replace

Compared with the method of injection find a less useful method is to form the injection method can be used to implement any other alternative methods managed bean. You can skip the rest of this section to safely until you really need this feature.

XML-based configuration metadata, you can use the replaced-methodmethod element to an existing implementation was replaced bean deployed. Consider the following class, which has called us want to overwrite the computeValuemethod:

public class MyValueCalculator {
​
    public String computeValue(String input) {
        // some real code...
    }
​
    // some other methods...
}

 

Implement org.springframework.beans.factory.support.MethodReplacerthe interface class to provide a new method definition, as the following example:

/**
 * meant to be used to override the existing computeValue(String)
 * implementation in MyValueCalculator
 */
public class ReplacementComputeValue implements MethodReplacer {
​
    public Object reimplement(Object o, Method m, Object[] args) throws Throwable {
        // get the input value, work with it, and return a computed result
        String input = (String) args[0];
        ...
        return ...;
    }
}

 

Deploy the original class and a method of covering the specified bean definition like the following example:

<bean id="myValueCalculator" class="x.y.z.MyValueCalculator">
    <!-- arbitrary method replacement -->
    <replaced-method name="computeValue" replacer="replacementComputeValue">
        <arg-type>String</arg-type>
    </replaced-method>
</bean><bean id="replacementComputeValue" class="a.b.c.ReplacementComputeValue"/>

 

You can <replaced-method/>use one or more elements of the <arg-type/>element to indicate the methods to be covered by the signature. Only when a plurality of signature method overloading and variants, only need the presence of the parameter class. For convenience, the character string parameter type may be a fully qualified type name substring. For example, all of the following matches java.lang.String:

java.lang.String
String
Str

 

Code demonstrates:

look-up:

public abstract class Car {
    

    //用于lookup-method注入
    @Lookup("taxi")
    public abstract Taxi createTaxi();

    private Taxi taxi;

    public Taxi getTaxi() {
        return taxi;
    }

    //setter注入
    public void setTaxi(Taxi taxi) {
        this.taxi = taxi;
    }

}
public class Taxi {
    public void say() {
        System.out.println("I am a Taxi...");
    }
}

 

xml file

<-! ==================== Lookup Method-injection property ==================== - -> 
    < bean the above mentioned id = "CAR" class = "spring2.Car" > 
        ! <- Note: the following sentence injection configuration and lookup-method does not matter, we are just for demonstration and explanation to configure the bean -> 
            < Property name = "Taxi" REF = "Taxi"  />  
        <-! Lookup Method-injection -> 
            < Lookup Method- name = "createTaxi" the bean = "Taxi"  />   
    </ the bean > 
    < the bean ID = "Taxi "
        class="spring2.Taxi" scope="prototype" />

 

Test categories:

public  class Test1 { 
    
       the ClassPathXmlApplicationContext XmlBeanFactory = null ; 

        @Before 
        public  void initXmlBeanFactory () { 
            System.out.println ( "\ n-test method begins ======== ======= \ n-" ); 
            XmlBeanFactory = new new the ClassPathXmlApplicationContext ( "spring2.xml" ); 
        } 

        @After 
        public  void After () { 
            System.out.println ( "\ n-ended test method ======== ======= \ n" ); 
        } 

        @Test 
        public  void test8 () {
            // test injection lookup-method 
            Car CAR1 = xmlBeanFactory.getBean ( "CAR", Car. Class ); 
            Car CAR2 = xmlBeanFactory.getBean ( "CAR", Car. Class ); 

            System.out.println ( "Car: Singleton, Therefore animal1 == animal2 be "+ (CAR1 == CAR2)); 

            Taxi DOG1 = car1.getTaxi (); 
            Taxi dog2 = car2.getTaxi (); 
            System.out.println ( " Taxi: the prototype, Car: Singleton, injection lookup-method is not used so dog1 == dog2 be "+ (== DOG1 dog2)); 

            // Note: this is obtained by createDog () method 
            Taxi taxi3 = car1.createTaxi ();
            Taxi4 Taxi  =car2.createTaxi (); 
            System.out.println ( "Taxi: the prototype, Car: Singleton, using a lookup-method implanted so dog3 == dog4 be" + (taxi3 == taxi4)); 

        } 

}

 

result:

======== test method starts ======= 
Car: Singleton, so animal1 == animal2 be to true 
Taxi: prototype, Car: Singleton, did not use the Lookup -method injection == so DOG1 dog2 should as to true 
Taxi: prototype, Car: Singleton, using the Lookup -method == injected so dog3 dog4 be false

 ======== ======= end of the test method

 

replaced-method

public class ReplaceDog implements MethodReplacer {
    @Override
    public Object reimplement(Object obj, Method method, Object[] args) throws Throwable {
        System.out.println("Hello, I am a white dog...");

        Arrays.stream(args).forEach(str -> System.out.println("参数:" + str));
        return obj;
    }
}
public class OriginalDog {
    public void sayHello() {
        System.out.println("Hello,I am a black dog...");
    }

    public void sayHello(String name) {
        System.out.println("Hello,I am a black dog, my name is " + name);
    }
}

xml configuration

<!-- ====================replace-method属性注入==================== -->
<bean id="dogReplaceMethod" class="com.lyc.cn.v2.day01.method.replaceMethod.ReplaceDog"/>
<bean id="originalDogReplaceMethod" class="com.lyc.cn.v2.day01.method.replaceMethod.OriginalDog">
    <replaced-method name="sayHello" replacer="dogReplaceMethod">
        <arg-type match="java.lang.String"></arg-type>
    </replaced-method>
</bean>

Test categories:

@Test
 public  void test9 () {
     // Test replace-method implanted 
    OriginalDog originalDog = xmlBeanFactory.getBean ( "originalDogReplaceMethod", OriginalDog. Class ); 
    originalDog.sayHello ( "output has been replaced ..." ); 
}

result:

======== ======= test method begins 

December 9, 2019 3:59:33 pm org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh 
information: Refreshing org.springframework.context.support @ 3caeaf62 .ClassPathXmlApplicationContext: the Startup DATE [Mon Dec 09 15:59:33 CST 2019]; root of context Hierarchy 
org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions December 9, 2019 3:59:33 pm 
information: Definitions the XML from the bean class loading path Resource [spring2.xml] 
the Hello, the I AM a White Dog ... 
parameters: the output has been replaced. . . 

======== ======= end of the test method

 

 

Guess you like

Origin www.cnblogs.com/dalianpai/p/12009977.html