Spring MVC注释控制器在groovy中

kda*_*bir 5 java groovy spring-mvc

我在src/main/groovy /中有这个...

package com.mycompany.web;
// imports....

@Controller
class GroovyController {

    @RequestMapping("/status_groovy")
    public @ResponseBody String getStatus() {
        return "Hello World from groovy!";
    }
}
Run Code Online (Sandbox Code Playgroud)

使用maven 3和spring 3.1(里程碑).Spring MVC非常适合java控制器,一切都设置得很好.groovy类编译得很好,可以在classes目录中找到java控制器类.

我在java(JavaController)中用相同的包编写了类似的控制器,但是在src/main/java下,它被spring和map正确选中,当我点击url时,我可以在屏幕上看到响应.

package com.mycompany.web;
// imports....

@Controller
class JavaController {

    @RequestMapping("/status")
    public @ResponseBody String getStatus() {
        return "Hello World!";
    }
}
Run Code Online (Sandbox Code Playgroud)

Jetty通常在日志中没有错误,但在我看不到groovy url被映射,而我可以看到java.

2011-09-23 16:05:50,412 [main] INFO  org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped "{[/status],methods=[],params=[],headers=[],consumes=[],produces=[]}" onto public java.lang.String com.mycompany.web.JavaController.getStatus()
Run Code Online (Sandbox Code Playgroud)

所有设置都很好,因为应用程序的其他部分正常工作与注释(组件扫描等),只是我不能得到映射的URL GroovyController

任何人都可以解释为了Controller在常规工作中写下需要做些什么吗?

PS:我正在避免使用GroovyServlet来运行脚本,因为它涉及bean注入和url路径映射时有很大的缺点.

sim*_*bim 6

尽管Ben(我与之合作)充分尊重,但问题不在于Spring正在创建一个cglib代理.相反,它正在创建一个动态JDK(或基于接口的)代理.这种创建代理的方法只能实现在目标实现的接口中声明的方法.实际上,您希望 Spring创建一个cglib代理,该代理创建一个代理,该代理是目标对象的子类,因此可以重新创建其所有公共方法.除非另外指定,否则Spring将在目标对象未实现任何接口时创建cglib代理,否则创建基于接口的代理.由于所有Groovy对象都实现了GroovyObject,因此即使您没有在Groovy控制器中显式实现任何接口,也会获得基于接口的代理.Ben的解决方案是正确的,因为如果您使用所有控制器方法创建一个接口,您将获得预期的行为.另一种方法是创建一个BeanFactoryPostProcessor,它指示Spring为实现GroovyObject和只有GroovyObject的类创建cglib代理.这是代码:

/**
 * Finds all objects in the bean factory that implement GroovyObject and only GroovyObject, and sets the
 * AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE value to true.  This will, in the case when a proxy
 * is necessary, force the creation of a CGLIB subclass proxy, rather than a dynamic JDK proxy, which
 * would create a useless proxy that only implements the methods of GroovyObject.
 *
 * @author caleb
 */
public class GroovyObjectTargetClassPreservingBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    private static final Logger logger = LoggerFactory.getLogger(GroovyObjectTargetClassPreservingBeanFactoryPostProcessor.class);

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        for (String beanDefName : beanFactory.getBeanDefinitionNames()) {
            BeanDefinition bd = beanFactory.getBeanDefinition(beanDefName);
            //ignore abstract definitions (parent beans)
            if (bd.isAbstract())
                continue;
            String className = bd.getBeanClassName();
            //ignore definitions with null class names
            if (className == null)
                continue;
            Class<?> beanClass;
            try {
                beanClass = ClassUtils.forName(className, beanFactory.getBeanClassLoader());
            }
            catch (ClassNotFoundException e) {
                throw new CannotLoadBeanClassException(bd.getResourceDescription(), beanDefName, bd.getBeanClassName(), e);
            }
            catch (LinkageError e) {
                throw new CannotLoadBeanClassException(bd.getResourceDescription(), beanDefName, bd.getBeanClassName(), e);
            }

            Class<?>[] interfaces = beanClass.getInterfaces();
            if (interfaces.length == 1 && interfaces[0] == GroovyObject.class) {
                logger.debug("Setting attribute {} to true for bean {}", AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, beanDefName);
                bd.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, true);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

只需在您的上下文中包含此类型的bean,瞧!您可以使用Groovy控制器而无需定义接口.


Ben*_*hko 1

不幸的是,如果您想在 Groovy 中运行它,您必须为您的 Controller 类创建一个接口并注释方法定义。Spring 使用 Cglib 为您的类创建一个代理。但是,如果不为控制器创建自定义接口,Spring 就会进行代理,groovy.lang.GroovyObject因为默认情况下所有 Groovy 对象都实现该接口。

interface GroovyControllerInterface {
    @RequestMapping("/status_groovy")
    @ResponseBody String getStatus()
}

@Controller
class GroovyController implements GroovyControllerInterface {
    @RequestMapping("/status_groovy")
    public @ResponseBody String getStatus() {
        return "Hello World from groovy!";
    }
}
Run Code Online (Sandbox Code Playgroud)