Я только что попытался разработать систему плагинов для моего веб-приложения весной загрузки. Приложение развертывается на сервере tomcat с использованием корневого контекстного пути. Система плагинов позволяет загружать специально подготовленные файлы jar во время выполнения. Система также должна иметь возможность отключать плагины во время выполнения. Эти банки хранятся внутри папки плагинов в текущем рабочем каталоге. Я хотел, чтобы каждый плагин имел свой собственный весенний контекст для работы. Инъекция зависимостей работает так, как ожидалось, но весна не обнаруживает аннотацию @RequestMapping для контекста плагина. Поэтому мой вопрос: как я могу заставить весну обнаружить эти аннотации @RequestMapping для моих плагинов (во время выполнения)?Spring не обнаруживает аннотацию @RequestMapping для нового контекста во время выполнения
Я использую последнюю версию весной загрузки и следующий 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
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);
}
}
Когда я запускаю приложение и загружаю плагин, я вижу «Contr oller ready. " в консоли. Однако, когда я пытаюсь получить доступ к url (localhost: 8080/test), я просто вижу страницу ошибки 404. Каждый URL-адрес контроллеров контекстных весов без плагинов правильно отображается (я могу получить доступ к localhost: 8080/index, например). Я узнал, что это может иметь какое-то отношение к RequestMappingHandlerMapping. Однако я действительно не понимаю, как использовать это, чтобы снова выполнить аннотацию.
Edit: я нашел способ сделать @RequestMapping
аннотаций работы для моего контроллера, используя следующий код:
// 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);
}
}
}
Однако я все еще ищу способ, чтобы заставить его работать, используя пружинный путь: https://github.com/spring-projects/spring-framework/blob/fb7ae010c867ae48ab51f48cce97fe2c07f44115/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerMethodMapping.java
Спасибо за чтение.
можете ли вы разместить свои приложения.properties? – alexbt
@Alex Я только что обновил сообщение, чтобы включить приложение application.yml –
Я просто заметил, что ваш метод PluginTestController.doGet является закрытым. Я не могу проверить это на данный момент, но вы уверены, что это поддерживается? Хорошо, посмотрел, он поддерживается. (Https://sebastian.marsching.com/blog/archives/149-Springs-RequestMapping-annotation-works-on-private-methods.html) по-прежнему я бы попытался изменить методы на публичные – alexbt