【发布时间】:2017-10-02 15:40:16
【问题描述】:
我正在为命令创建一个路由控制器结构。
每个控制器都有一个@ControlController 注解:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Component // Because @Component all controllers will be spring managed.
public @interface ControlController {
}
控制器应该包含带有@CommandMapping注解的方法:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CommandMapping {
String value();
}
@CommandMapping 注解的值就是命令。所以当值与被调用的命令相同时,应该调用该方法。
在应用程序启动时,调用以下代码来获取所有@CommandMappings:
/**
* Load all controller mappings.
*/
private void fetchControllers() {
// Get all beans with the ControlController annotation.
Map<String, Object> controllers = this.applicationContext.getBeansWithAnnotation(ControlController.class);
for (Map.Entry<String, Object> entry : controllers.entrySet()) {
Class controller = entry.getValue().getClass();
for (Method method: controller.getMethods()) {
// Check every method in a controller for the CommandMapping annotation.
// When the annotation is present the method is a command mapping.
if (method.isAnnotationPresent(CommandMapping.class)) {
CommandMapping commandMapping = method.getAnnotation(CommandMapping.class);
// Add the command mapping to the controller list.
this.controllers.put(commandMapping.value(), method);
}
}
}
}
此代码将找到所有带有@ControlController 注释的bean,并将循环遍历所有方法以找到@CommandMapping 注释。所有方法都将放在Map<String, Method>中。
到目前为止,一切都很完美。
以下方法用于执行属于命令的正确方法:
/**
* Execute a command for a client.
*
* @param client The client.
* @param command The command.
*/
public void executeCommand(Client client, String command) {
// Get the method that belongs to the command.
Method method = this.controllers.get(command);
Class<?> controllerClass = method.getDeclaringClass();
// The the controller that belongs to the method.
Object controller = this.applicationContext.getBean(controllerClass); // Here the code just stops.
System.out.println("Yeah"); // This isn't executed.
try {
List<Object> arguments = new ArrayList<>();
for (Parameter parameter: method.getParameters()) {
// Add arguments based on the parameter type.
}
method.invoke(controller, arguments.toArray(new Object[arguments.size()]));
} catch (Exception exception) {
exception.printStackTrace();
}
}
代码在this.applicationContext.getBean(controllerClass);处停止,没有任何异常
我发现当我自动连接 controllerClass 时,它出于某种原因可以正常工作。我在哪个类中自动连接控制器并不重要。但是当然自动装配每个控制器是一个丑陋的修复。
为什么 ApplicationContext.getBean 卡住了,我该如何解决这个问题?
更新:
我刚刚发现在getBean 中使用bean 名称也可以。
示例:
this.applicationContext.getBean(MainController.class); //Doesn't work
this.applicationContext.getBean("mainController"); // Works
更新:
我忘了提一些非常重要的事情(我认为):executeCommand 方法是从线程调用的,但线程是弹簧管理的。当我在没有线程的情况下运行它时,它可以工作,但我真的需要线程。如何让beans 在线程中工作?
【问题讨论】:
-
@Zorglube ApplicationContext 已经正确注入。
-
this.applicationContext.getBean(MainController.class); //Doesn't work this.applicationContext.getBean("mainController"); // Works这很奇怪...您是否尝试过使用@Component(value = "MyControllerSpecificName")设置您的控制器名称? -
或者
MainController controller = this.applicationContext.getBean(MainController.class); -
给组件(控制器)命名是通过命名而不是通过给类命名。我真的很想上课,因为这是我从方法中得到的:
Class<?> controllerClass = method.getDeclaringClass();。MainController controller = this.applicationContext.getBean(MainController.class);不起作用。
标签: java spring spring-boot reflection dependency-injection