groovy 中的 Spring MVC 注释控制器 [英] Spring MVC annotated controller in groovy

查看:29
本文介绍了groovy 中的 Spring MVC 注释控制器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在 src/main/groovy/...

I have this in src/main/groovy/...

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

@Controller
class GroovyController {

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

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

Using maven 3 and spring 3.1 (Milestone). Spring MVC works perfectly well for java controllers and everything is set up fine. The groovy class compiles fine and can be found in the classes directory along with the java controller classes.

我在同一个包中用 java (JavaController) 编写了类似的控制器,但在 src/main/java 下,它被 spring 正确拾取并映射,当我点击 url 时,我可以在屏幕上看到响应.

I have similar controller written in java (JavaController) in same package but under src/main/java and its getting picked up properly by spring and mapped and I can see the response on screen when I hit the url.

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

@Controller
class JavaController {

    @RequestMapping("/status")
    public @ResponseBody String getStatus() {
        return "Hello World!";
    }
}

Jetty 正常启动,日志中没有错误,但我没有看到 groovy url 被映射,而我可以看到 java 一个.

Jetty starts normally with no error in log but in I dont see groovy url getting mapped whereas i can see the java one.

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()

所有设置都很好,因为应用程序的其他部分在使用注释(组件扫描等)时都可以正常工作,只是我无法在 GroovyController

All the setting are fine as other parts of app are working just fine with annotations (component-scan etc.), Just that I can not get the url mapped in GroovyController

谁能解释一下需要做什么才能使 Controller 用 groovy 编写?

Can anyone explain what needs to be done in order to get Controllers written in groovy working?

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

PS: I am avoiding GroovyServlet to run the scripts because it has major downside when it comes to bean injection and url path mappings.

推荐答案

在此向 Ben(与我一起工作的人)致以崇高的敬意,这里的问题不在于 Spring 正在创建一个 cglib 代理.相反,它正在创建一个动态 JDK(或基于接口的)代理.这种创建代理的方法只能实现目标实现接口中声明的方法.您实际上希望 Spring 创建一个 cglib 代理,它创建一个代理,该代理是目标对象的子类,因此可以重新创建其所有公共方法.除非你另外指定,如果目标对象没有实现任何接口,Spring 将创建一个 cglib 代理,否则创建一个基于接口的代理.由于所有 Groovy 对象都实现了 GroovyObject,因此您将获得一个基于接口的代理,即使您没有在 Groovy 控制器中明确实现任何接口.Ben 的解决方案是正确的,因为如果您使用所有控制器方法创建一个接口,您将获得预期的行为.另一种方法是创建一个 BeanFactoryPostProcessor,它指示 Spring 为实现 GroovyObject 且仅实现 GroovyObject 的类创建 cglib 代理.代码如下:

With all due respect to Ben (whom I work with), the problem here isn't that Spring is creating a cglib proxy. Rather, it's creating a dynamic JDK (or interface-based) proxy. This method of creating proxies can only implement methods declared in the target's implemented interfaces. You actually want Spring to create a cglib proxy, which creates a proxy that is a subclass of the target object and can therefore recreate all of its public methods. Unless you specify otherwise, Spring will create a cglib proxy if the target object doesn't implement any interfaces, and an interface-based proxy otherwise. Since all Groovy objects implement GroovyObject, you're getting an interface-based proxy, even though you didn't explicitly implement any interfaces in your Groovy controller. Ben's solution is correct in that if you create an interface with all your controller methods, you'll get the expected behavior. An alternative is to create a BeanFactoryPostProcessor which instructs Spring to create cglib proxies for classes that implement GroovyObject and only GroovyObject. Here's the code:

/**
 * 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);
            }
        }
    }
}

只需在您的上下文中包含一个这种类型的 bean,瞧!您可以拥有 Groovy 控制器而无需定义接口.

Just include a bean of this type in your context, and voila! You can have Groovy controllers without needing to define interfaces.

这篇关于groovy 中的 Spring MVC 注释控制器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆