Spring / REST application with HOT deployment: Groovy script does not load dynamically from applicationContext.xml when tomcat starts at run time

I am trying to convert an existing Java application to a RESTful web application using Spring MVC and Groovy. One of the main features that I wanted to achieve was HOT ACCOMMODATION. I chose groovy because I did not want to make changes to the already implemented business logic (handlers), and also, if I ever had to make changes to the groovy code after deployment, I could easily do this without restarting the server (i.e. e. at runtime). This can be done because Spring supports dynamic reloading of groovy scripts (beans). It reloads the classes of dynamic languages ​​if they are changed.

I am using Spring annotations to map the request URL to controller methods, and the application is deployed to tomcat 6.0.35.

This is the web.xml file

//web.xml <?xml version = "1.0" encoding = "UTF-8"?> <web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5"> <!-- Spring Dispatcher --> <servlet> <servlet-name>rest</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>rest</servlet-name> <url-pattern>/service/*</url-pattern> </servlet-mapping> <!-- Loads application context files in addition to ${contextConfigLocation} --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- Set session timeout to 30 minutes --> <session-config> <session-timeout>30</session-timeout> </session-config> </web-app> 

This groovy file is the controller to which the DispatcherServlet maps the request.

 // UserController.groovy @Controller class UserController { // This is the method to which the HTTP request is submitted to based on the mapping of the // action field of the form ie. /service/user/login/auth.json @RequestMapping(value="/user/login/auth.{extension:[a-zA-Z]+}", method=RequestMethod.POST) @ResponseBody public String authenticate( @PathVariable String extension, @RequestParam(value="username", required=true) String username, @RequestParam(value="password", required=true) String password) { // UserResource makes the backend calls, authenticates a user and returns the result. def user = new UserResource() def result = user.login(name:username, userPassword:password) // Output the result of the query. Method makeView makes a JSON response of the result // and sends to the client(browser) def builder = makeView(extension) { it.login(action:result.action, message:result.message) } } } 

The Spring configuration file is as follows, where I used the "lang: groovy" tag, which supports dynamic languages. I also mentioned that the update time is 5 seconds, so any changes made to these groovy files at runtime can be seen every 1 second and the classes are reloaded.

 //applicationContext.xml <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:lang="http://www.springframework.org/schema/lang" xmlns:p="http://www.springframework.org/schema/p" xmlns:c="http://www.springframework.org/schema/c" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-3.1.xsd"> <context:annotation-config/> <context:component-scan base-package="app.controller,app.resource" /> <lang:groovy id="user" script-source="classpath:controller/UserController.groovy" refresh-check-delay="1000"></lang:groovy> <!-- To enable @RequestMapping process on type level and method level --> <bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" /> <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" /> <!-- Resolves view names to template resources within the directory --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/"/> <property name="suffix" value=".html"/> </bean> </beans> 

I configured my Buildpath and groovy compiler, respectively, so that all groovy scripts are directly copied to the destination folder instead of being compiled into class files.

MAIN PROBLEM
When I deploy this project to the tomcat server, it loads all the required Spring beans, including the ScriptProcessor. Now, when I go to my browser, download the form and try to submit the authentication form, I get the following error in the Tomcat log:

 15:20:09 WARN - No mapping found for HTTP request with URI [/service/user/login/auth.json] in DispatcherServlet with name 'rest' 

I also made changes to $ TOMCAT_DIR / conf / context.xml in anti-lock resources and JARS

 <Context antiResourceLocking="true" antiJARLocking="true" reloadable="true" privileged="true"> . . .</Context> 

However, if I configured my project to compile these groovy scripts into bytecode classes, comment out the lang: groovy tag in applicationContext.xml and then restart the server, groovy scripts compile into class files and the request is served fine. Authentication takes place.

In addition, if I configure dynamic beans in my applicationContet.xml using the following two lines instead of a tag, my DO beans are created dynamically at runtime, and the URLs become mapped to the corresponding controller methods, annotations.

 <bean class="org.springframework.scripting.support.ScriptFactoryPostProcessor" /> <bean id ="User" class="org.springframework.scripting.groovy.GroovyScriptFactory"> <constructor-arg value="classpath:controller/UserController.groovy" /> </bean> 

But I do not know how to create a bean update functionality with this style. Therefore, I assume that there is a problem with the way the tag handles groovy scripts.

I would really appreciate help on this. I searched all over the Internet and read an infinite number of textbooks, and followed the exact procedure mentioned here. But I can’t understand what is going wrong.

Please help me solve this problem.

Thanks.

+6
source share
1 answer

Try creating a controller with Java / Groovy that compiled, and let it introduce Groovy 'script' as a dependency to do the actual work. I seem to remember how it was done before, and it can be annotations or the Spring path loads the controllers, which makes the "script" not work for you properly.

0
source

Source: https://habr.com/ru/post/948023/


All Articles