Spring-framwork 提供了一種基於方法級的注入方式
考慮一種情況,一個singleton A 和一個 prototype B,A中有一個方法每次執行的時候都需要一個B的實例,由於Spring容器在初始A的時候已經初始好一切,那麼這個時候如何做到每次執行該方法的時候,提供一個依賴B呢?
解決有兩種方法:
1.通過實現 ApplicationContextAware 接口,硬編碼實現每次調用該方法的時候注入一個實例B,然而這種方法會使代碼和注入過程耦合在一起
2.提供一個abstract方法,Spring使用CGLIB重寫抽象方法提供注入 (Method Injection)
方法注入,提供了方法級的注入方式,保證每次執行到該方法的時候都會提供一個新的B實例來使用,由Spring容器通過配置完成解耦工作。
Command接口:
package com.interfaces;
public interface Command {
void setState(String commandState);
String execute();
}
Command實現:
package com.domain;
import com.interfaces.Command;
public class AttackCommand implements Command {
private String commandState;
private static int count = 0;
private final int id = count++;
public AttackCommand() {
System.out.println("command init");
}
public String execute() {
return "Attack Command " + id + ": starting attack " + commandState;
}
public void setState(String commandState) {
this.commandState = commandState;
}
}
Method 1:
package com.domain;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import com.interfaces.Command;
public class CoupleCommandManager implements ApplicationContextAware {
private ApplicationContext applicationContext;
public String process(String commandState) {
Command command = createCommand();
command.setState(commandState);
return command.execute();
}
protected Command createCommand() {
return applicationContext.getBean("attackCommand", Command.class);
}
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
Method 2:
package com.domain;
import com.interfaces.Command;
public abstract class CommandManager {
public String process(String commandState){
Command command = createCommand();
command.setState(commandState);
return command.execute();
}
protected abstract Command createCommand();
}
xml配置文件
<bean id="attackCommand" class="com.domain.AttackCommand" scope="prototype"/>
<bean id="coupleCommandManager" class="com.domain.CoupleCommandManager"></bean>
<bean id="commandManager" class="com.domain.CommandManager">
<lookup-method name="createCommand" bean="attackCommand"/>
</bean>
java cfg:
@Bean
@Scope("prototype")
public Command attackCommand() {
return new AttackCommand();
}
@Bean
public CommandManager commandManager() {
return new CommandManager() {
@Override
protected Command createCommand() {
return attackCommand();
}
};
}