java - Spring ApplicationContext getBean 仅在 AutoWired 之前有效

标签 java spring spring-boot reflection dependency-injection

我正在为命令创建一个路由 Controller 结构。 每个 Controller 都有一个@ControlController注释:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Component // Because @Component all controllers will be spring managed.
public @interface ControlController {
}

Controller 应包含带有 @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); 处毫无异常地停止。

我发现当我 AutoWire controllerClass 时由于某种原因它有效。在哪个类中自动连接 Controller 并不重要。但当然,自动连接每个 Controller 是一个丑陋的修复。

为什么 ApplicationContext.getBean 会卡住以及如何解决此问题?

更新: 我刚刚发现使用getBean中的bean名称也有效。 示例:

this.applicationContext.getBean(MainController.class); //Doesn't work

this.applicationContext.getBean("mainController"); // Works

更新: 我忘了提一些非常重要的事情(我认为):executeCommand方法是从线程调用的,但该线程是由 spring 管理的。当我在没有线程的情况下运行它时,它可以工作,但我确实需要线程。我怎样才能做beans在线程中工作?

最佳答案

您可以尝试使用“名称”搜索Controller;此解决方案意味着通过获取注释来查找 Controller 的名称。

即:

@Service
@Component(value = "statService")
public class Controller {...} 

public class AnnotationFinder {

    public static String findComponentName(Class cls) {
        for (Annotation annotation : cls.getDeclaredAnnotations()) {
            if (annotation.annotationType().equals(Component.class)) {
                return annotation.value();
            }
        }
        return null;
    }
}

当您获得 @Component 时,您将获得 value 成员和 =>

对象 Controller = this.applicationContext.getBean(AnnotationFinder.findComponentName(controllerClass));

关于java - Spring ApplicationContext getBean 仅在 AutoWired 之前有效,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46528887/

相关文章:

java - Spring +(什么库)用于 JSON REST API

java - 如何在 ATG 中模拟存储库项目

java - ArchUnit:检查包是否相互依赖的最优雅的方法

spring - Maven 错误 - Spring Surf Alfresco

spring-boot - 如何加快Spring Boot 2.0基本身份验证的速度?

java - Spring Cassandra 模型映射

java - 该方法应该返回一个排序数组,但为什么我会收到 NullPointerException?

java - 指定自定义应用程序上下文

java - Spring 数据 : JPA Schema JpaRepositoryConfigDefinitionParser intiailization fails

Javascript:是否可以将字符串转换为数组的数组?