如何在 Spring Boot 中自动装配服务并将动态参数传递给构造函数
How to autowire a service in Spring Boot and pass dynamic parameters to the constructor
我正在处理 Spring 启动项目,在尝试自动装配服务时遇到了一些问题。这是我当前的代码:
@Component
public class StealFromPocket implements Command {
private Integer gameId;
private Player playerFrom;
@Autowired
GameService gameService;
public StealFromPocket(Integer gameId, Player playerFrom) {
this.gameId = gameId;
this.playerFrom = playerFrom;
}
@Override
public void execute() {
gameService.findPlayersByGameId(gameId).forEach(player -> {
new StealCoinCommand(playerFrom, player).execute();
});
}
}
构造函数参数 gameId
和 playerFrom
在运行时是已知的,所以我不能对它们进行硬编码或将它们存储在配置文件中。
这是 StealFromPocket
通过反射从 service
实例化的地方(completeClassName
将根据用户交互而改变。在这个例子中,它将是 org.springframework...StealFromPocket
:
Class<?> clazz = Class.forName(completeClassName);
Object card = clazz.getDeclaredConstructor(Integer.class, Player.class).newInstance(gameId, playerFrom);
Method method = clazz.getDeclaredMethod("execute");
method.invoke(card);
尝试构建项目时,出现以下错误:
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of constructor in org.springframework.ntfh.cardlogic.abilitycard.rogue.RobarBolsillos required a bean of type 'java.lang.Integer' that could not be found.
Action:
Consider defining a bean of type 'java.lang.Integer' in your configuration.
我认为问题是我没有将 GameService
作为构造函数参数传递,但由于我项目的性质,这些服务不能作为参数传递,因为它们会因 class 通过反射实例化。
我通过更改 class 的实现来修复此问题,以便 execute
方法接收相应的参数,并且自动装配的字段是 StealFromPocket
class。现在看起来像这样:
@Component
public class StealFromPocket {
@Autowired
private GameService gameService;
public void execute(Player playerFrom) {
Integer gameId = playerFrom.getGame().getId();
gameService.findPlayersByGameId(gameId).forEach(player -> {
new StealCoinCommand(playerFrom, player).execute();
});
}
}
在 GameService.java
中,我执行以下操作:
// Get the class from its name
Class<?> clazz = Class.forName(completeClassName);
// Instantiate an object of the class
Object cardCommand = clazz.getDeclaredConstructor().newInstance();
// Autowire the new object's dependencies (services used inside)
AutowireCapableBeanFactory factory = applicationContext.getAutowireCapableBeanFactory();
factory.autowireBean(cardCommand);
factory.initializeBean(cardCommand, className);
// Get a reference to the method "execute", that receives 2 parameters
Method method = clazz.getDeclaredMethod("execute", Player.class);
// Execute the method with the parameters
method.invoke(cardCommand, playerFrom);
我正在处理 Spring 启动项目,在尝试自动装配服务时遇到了一些问题。这是我当前的代码:
@Component
public class StealFromPocket implements Command {
private Integer gameId;
private Player playerFrom;
@Autowired
GameService gameService;
public StealFromPocket(Integer gameId, Player playerFrom) {
this.gameId = gameId;
this.playerFrom = playerFrom;
}
@Override
public void execute() {
gameService.findPlayersByGameId(gameId).forEach(player -> {
new StealCoinCommand(playerFrom, player).execute();
});
}
}
构造函数参数 gameId
和 playerFrom
在运行时是已知的,所以我不能对它们进行硬编码或将它们存储在配置文件中。
这是 StealFromPocket
通过反射从 service
实例化的地方(completeClassName
将根据用户交互而改变。在这个例子中,它将是 org.springframework...StealFromPocket
:
Class<?> clazz = Class.forName(completeClassName);
Object card = clazz.getDeclaredConstructor(Integer.class, Player.class).newInstance(gameId, playerFrom);
Method method = clazz.getDeclaredMethod("execute");
method.invoke(card);
尝试构建项目时,出现以下错误:
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of constructor in org.springframework.ntfh.cardlogic.abilitycard.rogue.RobarBolsillos required a bean of type 'java.lang.Integer' that could not be found.
Action:
Consider defining a bean of type 'java.lang.Integer' in your configuration.
我认为问题是我没有将 GameService
作为构造函数参数传递,但由于我项目的性质,这些服务不能作为参数传递,因为它们会因 class 通过反射实例化。
我通过更改 class 的实现来修复此问题,以便 execute
方法接收相应的参数,并且自动装配的字段是 StealFromPocket
class。现在看起来像这样:
@Component
public class StealFromPocket {
@Autowired
private GameService gameService;
public void execute(Player playerFrom) {
Integer gameId = playerFrom.getGame().getId();
gameService.findPlayersByGameId(gameId).forEach(player -> {
new StealCoinCommand(playerFrom, player).execute();
});
}
}
在 GameService.java
中,我执行以下操作:
// Get the class from its name
Class<?> clazz = Class.forName(completeClassName);
// Instantiate an object of the class
Object cardCommand = clazz.getDeclaredConstructor().newInstance();
// Autowire the new object's dependencies (services used inside)
AutowireCapableBeanFactory factory = applicationContext.getAutowireCapableBeanFactory();
factory.autowireBean(cardCommand);
factory.initializeBean(cardCommand, className);
// Get a reference to the method "execute", that receives 2 parameters
Method method = clazz.getDeclaredMethod("execute", Player.class);
// Execute the method with the parameters
method.invoke(cardCommand, playerFrom);