Turn from: Spring Method injection
Referencesin most cases, the beans in the container are of type Singleton. If a singleton bean is to reference another singleton bean, or if a non-singleton bean is to reference another non-singleton bean, It is usually possible to define a bean as the property value of another bean. This can be problematic for beans with different lifecycles, for example, when calling a method of a singleton type bean A, you need to refer to another non-singleton (prototype) type of bean B, for Bean a The container is created only once, so that it is not necessary to have the container give bean a a new instance of Bean B every time it is needed
For the above problem Spring offers three solutions:
- Discard control reversal. By implementing the Applicationcontextaware interface, bean A can sense the bean container and, when needed, request a new instance of Bean B by using Getbean ("B") to the container.
- Lookup method Injection. The lookup method injection takes advantage of the container's ability to overwrite a container-managed bean method, returning a bean instance of the specified name.
- Alternatives to custom methods. This injection can be implemented using another method of the bean to replace the custom method.
Here only the first two scenarios to achieve, the third solution because not commonly used, skip the mention, interested can understand.
One: The realization of the environment
- Eclipse3.4
- JDK1.5
- Spring3.0.3
- Junit 4 test Framework
- The dependent jar has log4j-1.2.16.jar,commons-logging-api-1.1.1.jar,cglib-nodep-2.2.jar.
Two: By implementing the Applicationcontextaware interface in a programmatic way
Applicationcontextaware and Beanfactoryaware are similar, the usage is similar, the object that implements the Applicationcontextaware interface will have a applicationcontext reference, This way we can operate the applicationcontext programmatically. Look at the following example.
Java code
Packagecom.flysnow.injection; Importorg.springframework.beans.BeansException; ImportOrg.springframework.context.ApplicationContext; ImportOrg.springframework.context.ApplicationContextAware; ImportCom.flysnow.injection.command.Command; /*** Command Manager *@authorSnow Ruthless **/ Public classCommandmanagerImplementsApplicationcontextaware {//reference for saving ApplicationContext, set-mode injection PrivateApplicationContext ApplicationContext; //methods for simulating business processes PublicObject process () {command command=CreateCommand (); returnCommand.Execute (); } //get a command PrivateCommand CreateCommand () {return(Command) This. Applicationcontext.getbean ("Asynccommand");// } Public voidSetapplicationcontext (ApplicationContext applicationcontext)throwsbeansexception { This. Applicationcontext=applicationcontext;//get the ApplicationContext reference } }
The command interface and its implementation class Asynccommand are defined below.
Package Com.flysnow.injection.command; /** * One command interface @author Snow Ruthless * * /Public interface command { /** * Executes commands @return */ Public Object execute (); }
Java code
PackageCom.flysnow.injection.command; /*** Implementation of an Asynchronous processing command *@authorSnow Ruthless **/ Public classAsynccommandImplementsCommand {/*(non-javadoc) * @see Com.flysnow.lookup.command.command#execute ()*/ PublicObject Execute () {//to return to the instance, it is good to test the time to see that each return is not the same instance return This; } }
The bean configuration file is as follows:
XML code
<?xml version= "1.0" encoding= "UTF-8"?> <beans xmlns= "Http://www.springframework.org/schema/beans" xmlns:xsi= "Http://www.w3.org/2001/XMLSchema-instance" xsi:schemalocation= "http// Www.springframework.org/schema/beans http://www.springframework.org/schema/beans/ Spring-beans-3.0.xsd "> <!--by scope=" prototype "defines the bean as a multiple-- class=" Com.flysnow.injection.command.AsyncCommand "scope=" prototype "></bean> class=" Com.flysnow.injection.CommandManager "> </bean> </beans>
The above is mainly a single case bean Commandmanager's process () method needs to refer to a prototype (not singleton) Bean, So when invoking the process, it is easy to get a command from the container using the CreateCommand method, and then to execute the business calculation with comments in the code.
The test classes are as follows:
Java code
Packagecom.flysnow.injection; ImportOrg.junit.Before; Importorg.junit.Test; ImportOrg.springframework.context.ApplicationContext; ImportOrg.springframework.context.support.ClassPathXmlApplicationContext; ImportCom.flysnow.injection.CommandManager; Public classTestcommandmanager {PrivateApplicationContext context; @Before Public voidSetUp ()throwsException {Context=NewClasspathxmlapplicationcontext ("Beans.xml"); } @Test Public voidtestprocess () {Commandmanager Manager=context.getbean ("Commandmanager", Commandmanager.class); System.out.println ("The address of the first execution Process,command is:" +manager.process ()); System.out.println (The address of the second execution Process,command is: "+manager.process ()); } }
The output from the console output can be seen two times the address of the command in the loan is not the same, because we configured the Scope= "prototype" property for Asynccommand, this way is to make every instance of the bean from the container is different. In this way we implement a method (Process method) in a singleton bean (Commandmanager) that refers to a non-singleton bean (Asynccommand). Although we did, this is not a good approach because our business code and the spring framework have been coupled. Another clean implementation of spring provided by the following is the lookup method injection.
Three: Through the Lookup method injection to achieve
It's easy to use this approach because spring has done a lot of work for us, and all we have to do is bean configuration and business class.
- The first modification of the Commandmanager class is abstract, and the modified CreateCommand method is also abstract.
- Remove Applicationcontextaware implementation and related set method and ApplicationContext variable definition
- Modify the Bean configuration file to add <lookup-method name= "CreateCommand" bean= "Asynccommand"/> in the Commandmanager bean.
- Others remain the same
The modified Commandmanager and bean configuration files are as follows:
Java code
Public Abstract class Commandmanager { // The method of simulating business processing public Object process () { command command=CreateCommand (); return Command.Execute (); } // get a command protected Abstract Command CreateCommand (); }
XML code
class= "Com.flysnow.injection.CommandManager" > <lookup-method name= "CreateCommand" bean= " Asynccommand "/>
Run the test, the console print out the address of the two command is not the same, indicating that we have implemented.
The name attribute in the <lookup-method> tag is the method of obtaining a command instance (Asynccommand) for the Commandmanager Bean, and the CreateCommand method, The Bean property is what type of command to return, here is Asynccommand.
The CreateCommand method here becomes the injected method, and his definition must be:
Java code
<Public | protected> [abstract] <return-type> themethodname (no-arguments);
The injected method is not necessarily abstract, and if the injected method is abstract, the dynamically generated subclass (here is the subclass of dynamically generated Commandmanager) implements the method. Otherwise, dynamically generated subclasses override the specific methods in the class. In order for this dynamic subclass to work properly, the Cglib jar file needs to be placed in the classpath, which is why we quoted the Cglib package. Also, the class that the spring container is to subclass (Commandmanager) cannot be final, and the method to overwrite (CreateCommand) cannot be final.
Four: summary
The lookup method is injected cleanly, easily extensible, and more compliant with IOC rules, so try to use this approach.
Spring Method Injection