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

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

问题描述

  package com.mycompany.web; 
//进口....

@Controller
类GroovyController {

@RequestMapping(/ status_groovy)
public @ ResponseBody String getStatus(){
return来自groovy的Hello World!;


$ / code $ / pre

使用maven 3和spring 3.1(里程碑)。 Spring MVC对于java控制器来说工作得非常好,一切都很好。 groovy类编译得很好,可以在 classes 目录以及java控制器类中找到。



我有类似的控制器用java编写(JavaController)在同一个包中,但在src / main / java下,并且它在spring和mapped中被正确拾取,我可以在屏幕上看到响应。

  package com.mycompany.web; 
//进口....

@Controller $ b $ class JavaController {

@RequestMapping(/ status)
public @ ResponseBody String getStatus(){
returnHello World!;






Jetty正常启动时没有记录错误,但在I没有看到groovy url被映射,而我可以看到java的一个。

  2011-09-23 16:05:50,412 [main ] INFO org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping  - 映射{[/ status],methods = [],params = [],headers = [],consumes = [],产生= [] }to public java.lang.String com.mycompany.web.JavaController.getStatus()

全部该设置是正常的,因为应用程序的其他部分工作得很好,使用注释(组件扫描等),只是我无法获得映射在 GroovyController



任何人都可以解释为了得到 Controller 用groovy编写工作需要做些什么?



PS:我在避免GroovyServlet运行这些脚本,因为它涉及到bean注入和url路径映射时存在重大缺陷。

解决方案

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

  / ** 
*在bean工厂中查找实现GroovyObject的所有对象,并且仅查找GroovyObject,并将
* AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE值设置为true。在需要代理
*的情况下,这将会强制创建一个CGLIB子类代理,而不是一个动态的JDK代理,其中
*会创建一个无用代理,该代理仅实现GroovyObject对象。
*
* @author caleb
* /
public class GroovyObjectTargetClassPreservingBeanFactoryPostProcessor实现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);
//忽略抽象定义(父bean)
if(bd.isAbstract())
continue;
String className = bd.getBeanClassName();
//忽略具有空类名称的定义
if(className == null)
continue;
Class<?> beanClass;
尝试{
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&& interface [0] == GroovyObject.class){
logger.debug(将属性{}设置为true},AutoProxyUtils。 PRESERVE_TARGET_CLASS_ATTRIBUTE,beanDefName);
bd.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE,true);
}
}
}
}

只是在你的上下文中包含这种类型的bean,瞧!您可以拥有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!";
    }
}

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.

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

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

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

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

解决方案

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

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

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

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