繁体   English   中英

Spring MVC注释控制器在groovy中

[英]Spring MVC annotated controller in groovy

我在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控制器类。

我在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!";
    }
}

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

所有设置都很好,因为应用程序的其他部分正常工作与注释(组件扫描等),只是我无法获取在GroovyController映射的url

任何人都可以解释为了让Controller在groovy中运行起来需要做些什么吗?

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

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

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

我不敢苟同。 无需实现接口。 这里的问题是默认的AnnotationMethodHandlerAdapter不会从代理中读取注释。 因此,我们必须创建这个代理感知的AnnotationMethodHandlerAdapter,它扩展了spring的默认AnnotationMethodHandlerAdapter 我们还需要在Spring Configuration xml文件中为此ProxyAwareAnnotationMethodHandlerAdapter实例化一个bean。 注意:此功能在Spring 3.x中不可用,但由于Spring 4.0将支持groovy bean,因此应该涵盖此功能。

//ProxyAwareAnnotationMethodHandlerAdapter.java

    package name.assafberg.spring;

    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;

    import org.springframework.aop.TargetSource;
    import org.springframework.aop.framework.Advised;
    import org.springframework.web.servlet.ModelAndView;
    import org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter;

    /**
     * Add proxy awareness to <code>AnnotationMethodHandlerAdapter</code>.
     * 
     * @author assaf
     */
    public class ProxyAwareAnnotationMethodHandlerAdapter extends AnnotationMethodHandlerAdapter {

        /**
         * @param request
         * @param response
         * @param handler
         * @return
         * @throws Exception
         * @see org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter#handle(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.Object)
         */
        @Override
        public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            handler = unwrapHandler(handler);

            return super.handle(request, response, handler);
        }

        /**
         * @param handler
         * @return
         * @see org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter#supports(java.lang.Object)
         */
        @Override
        public boolean supports(Object handler) {
            handler = unwrapHandler(handler);

            return super.supports(handler);
        }

        /**
         * Attempt to unwrap the given handler in case it is an AOP proxy
         * 
         * @param handler
         * @return Object
         */
        private Object unwrapHandler(Object handler) {
            if (handler instanceof Advised) {
                try {
                    TargetSource targetSource = ((Advised) handler).getTargetSource();
                    return targetSource.getTarget();

                } catch (Exception x) {
                    throw new RuntimeException(x);
                }

            } else {
                return handler;     
            }       
        }

    }

spring配置XML文件必须具有以下内容。 我们必须创建一个ProxyAwareAnnotationMethodHandlerAdapter bean,而不是创建AnnotationMethodHandlerAdapter的bean。

<beans .........
...
...
      <bean class="full.qualified.name.of.ProxyAwareAnnotationMethodHandlerAdapter" />
...
...
      <lang:groovy script-source="classpath:com/example/mysample.groovy refresh-check-delay="1000" />
</beans>

Spring还使用SAX解析器解析配置XML文件(基于事件发生)。 因此,为了使spring能够理解groovy脚本中的注释,必须在ProxyAwareAnnotationMethodHandlerAdapter之后创建groovy bean(使用标记)。

希望比帮助

参考: http//forum.springsource.org/showthread.php?47271-Groovy-Controller

不幸的是,如果你想在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!";
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM