gpt4 book ai didi

java - Spring 不会在运行时发现新上下文的 @RequestMapping 注释

转载 作者:塔克拉玛干 更新时间:2023-11-02 19:13:27 24 4
gpt4 key购买 nike

我刚刚尝试为我的 spring boot web 应用程序开发一个插件系统。该应用程序使用根上下文路径部署在 tomcat 服务器上。插件系统允许我在运行时加载专门准备的 jar 文件。系统还应该能够在运行时取消部署插件。这些 jar 包含在当前工作目录的插件文件夹中。我希望每个插件都有自己的 spring 上下文来操作。依赖注入(inject)按预期工作,但 spring 没有发现我的插件上下文的 @RequestMapping 注释。所以我的问题是:如何让 spring 发现我的插件的那些 @RequestMapping 注释(在运行时)?

我正在使用最新的 spring boot 版本和以下 application.yml:

# Server
server:
error:
whitelabel:
enabled: true
session:
persistent: true
tomcat:
uri-encoding: UTF-8
# Spring
spring:
application:
name: Plugins
mvc:
favicon:
enabled: false
favicon:
enabled: false
thymeleaf:
encoding: UTF-8
# Logging
logging:
file: application.log
level.: error

这是加载插件的代码:

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
URLClassLoader urlClassLoader = URLClassLoader.newInstance(new URL[] { plugin.getPluginURL() }, getClass().getClassLoader()); // plugin.getPluginURL will refer to a jar file with the plugin code (see below).
context.setClassLoader(urlClassLoader);
context.setParent(applicationContext); // applicationContext is the the context of the original spring application. It was autowired.
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context, true);
scanner.scan("my.plugin.package");
context.refresh();

和 Controller 代码(在我的插件中):

@Controller
public class PluginTestController {
@PostConstruct
private void postContruct() {
System.out.println("Controller ready.");
}

@RequestMapping(value = "/test", method = RequestMethod.GET)
public ResponseEntity<String> doGet() {
return new ResponseEntity<>("Hello!", HttpStatus.OK);
}
}

当我启动应用程序并加载插件时,我可以看到“ Controller 准备就绪”。在控制台中。但是,当我尝试访问 url (localhost:8080/test) 时,我只能看到 404 错误页面。非插件 spring 上下文 Controller 的每个 url 都被正确映射(例如,我可以访问 localhost:8080/index)。我发现它可能与 RequestMappingHandlerMapping 有关。但是我真的不明白如何利用它来使注释再次工作。

编辑:我找到了一种使用以下代码使 @RequestMapping 注释适用于我的 Controller 的方法:

// context is the Plugins context, that i just created earlier.
for (Map.Entry < String, Object > bean: context.getBeansWithAnnotation(Controller.class).entrySet()) {
Object obj = bean.getValue();
// From http://stackoverflow.com/questions/27929965/find-method-level-custom-annotation-in-a-spring-context
// As you are using AOP check for AOP proxying. If you are proxying with Spring CGLIB (not via Spring AOP)
// Use org.springframework.cglib.proxy.Proxy#isProxyClass to detect proxy If you are proxying using JDK
// Proxy use java.lang.reflect.Proxy#isProxyClass
Class < ? > objClz = obj.getClass();
if (org.springframework.aop.support.AopUtils.isAopProxy(obj)) {
objClz = org.springframework.aop.support.AopUtils.getTargetClass(obj);
}
for (Method m: objClz.getDeclaredMethods()) {
if (m.isAnnotationPresent(RequestMapping.class)) {
RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(m, RequestMapping.class);
RequestMappingInfo requestMappingInfo = RequestMappingInfo
.paths(requestMapping.path())
.methods(requestMapping.method())
.params(requestMapping.params())
.headers(requestMapping.headers())
.consumes(requestMapping.consumes())
.produces(requestMapping.produces())
.mappingName(requestMapping.name())
.customCondition(null)
.build();
// This will register the actual mapping, so that the Controller can handle the Request
requestMappingHandlerMapping.registerMapping(requestMappingInfo, obj, m);
}
}
}

但是我仍在寻找一种使用 Spring 方式使其工作的方法:https://github.com/spring-projects/spring-framework/blob/fb7ae010c867ae48ab51f48cce97fe2c07f44115/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerMethodMapping.java

感谢阅读。

最佳答案

SpringMvc有自己的@RequestMapping缓存,具体代码为RequestMappingHandlerMapping。如您所见,显示了init方法,也许您可​​以在加载新插件后调用init方法。

protected void initHandlerMethods() {
if (logger.isDebugEnabled()) {
logger.debug("Looking for request mappings in application context: " + getApplicationContext());
}

String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
getApplicationContext().getBeanNamesForType(Object.class));

for (String beanName : beanNames) {
if (isHandler(getApplicationContext().getType(beanName))){
detectHandlerMethods(beanName);
}
}
handlerMethodsInitialized(getHandlerMethods());
}

这是spring3的RequestMappingHandlerMapping代码,可能spring4的impl有一些改动。

关于java - Spring 不会在运行时发现新上下文的 @RequestMapping 注释,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40441028/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com