java - Spring does not discover @RequestMapping annotation for a new context at runtime -
i tried develop plugin system spring boot web application. application deployed on tomcat server using root context path. plugin system allows me load specially prepared jar files @ runtime. system should able undeploy plugins @ runtime. jars contained inside plugin folder in current working dir. wanted every plugin have it's own spring context operate with. dependency injection working expected spring not discover @requestmapping annotation plugin context. question is: how can make spring discover @requestmapping annotations plugins (at runtime)?
i using latest spring boot version , following 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
this code loads plugin:
annotationconfigapplicationcontext context = new annotationconfigapplicationcontext(); urlclassloader urlclassloader = urlclassloader.newinstance(new url[] { plugin.getpluginurl() }, getclass().getclassloader()); // plugin.getpluginurl refer jar file plugin code (see below). context.setclassloader(urlclassloader); context.setparent(applicationcontext); // applicationcontext the context of original spring application. autowired. classpathbeandefinitionscanner scanner = new classpathbeandefinitionscanner(context, true); scanner.scan("my.plugin.package"); context.refresh();
and controller code (inside plugin):
@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); } }
when start application , load plugin can see "controller ready." in console. when try access url (localhost:8080/test) see 404 error page. every url of non plugin spring context controllers gets mapped correctly (i can access localhost:8080/index example). found out have requestmappinghandlermapping. dont understand how make use of in order make annotation work again.
edit: found way make @requestmapping
annotation work controller using following code:
// context plugins context, created earlier. (map.entry < string, object > bean: context.getbeanswithannotation(controller.class).entryset()) { object obj = bean.getvalue(); // http://stackoverflow.com/questions/27929965/find-method-level-custom-annotation-in-a-spring-context // using aop check aop proxying. if proxying spring cglib (not via spring aop) // use org.springframework.cglib.proxy.proxy#isproxyclass detect proxy if 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); } (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(); // register actual mapping, controller can handle request requestmappinghandlermapping.registermapping(requestmappinginfo, obj, m); } } }
however still searching way make work using spring way: https://github.com/spring-projects/spring-framework/blob/fb7ae010c867ae48ab51f48cce97fe2c07f44115/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/abstracthandlermethodmapping.java
thanks reading.
the springmvc has it's own cache of @requestmapping
, detail code requestmappinghandlermapping
. can see, init method shown, maybe can call init method after load new plugin.
protected void inithandlermethods() { if (logger.isdebugenabled()) { logger.debug("looking request mappings in application context: " + getapplicationcontext()); } string[] beannames = (this.detecthandlermethodsinancestorcontexts ? beanfactoryutils.beannamesfortypeincludingancestors(getapplicationcontext(), object.class) : getapplicationcontext().getbeannamesfortype(object.class)); (string beanname : beannames) { if (ishandler(getapplicationcontext().gettype(beanname))){ detecthandlermethods(beanname); } } handlermethodsinitialized(gethandlermethods()); }
this spring3's requestmappinghandlermapping
code, maybe there changes in spring4's impl.
Comments
Post a Comment