1
  1. @EnableZuulProxy doesn't work under a servlet 2.5 container. Is there any workaround to get spring-cloud zuul work under a servet 2.5 container?

  2. Also I could not find the annotation processor of @EnableZuulProxy. Please provide the class which propesses @EnableZuulProxy so that I can better understand what this annotation really does.

Fahim Farook
  • 1,482
  • 2
  • 14
  • 38

2 Answers2

2

@EnableZuulProxy is from Spring Cloud which is based on Spring Boot which is Servlet 3.0 and above. If you need to use Servlet 2.5 you can use the Netflix APIs directly.

@EnableZuulProxy is meta-annotated with @Import(ZuulProxyConfiguration.class) so I guess that's what you mean when you say "propesses"? If you don't know what an @Import is, go and read up on Spring.

Dave Syer
  • 56,583
  • 10
  • 155
  • 143
  • Thx. I could get spring-boot run with servlet 2.5 following the instructions here. https://docs.spring.io/spring-boot/docs/current/reference/html/howto-traditional-deployment.html - so wondering whether a similar workaround exists for zuul as well? – Fahim Farook Dec 22 '15 at 16:21
2

Spring Cloud is meant to be run on servlet 3.0. That being said, it is possible to get @EnableZuulProxy running on servlet 2.5. I had to figure out a hack for this as I had to get this working in Tomcat 6.

The main issue is due to the ZuulConfiguration.class, which has the method:

@Bean
@ConditionalOnMissingBean(name = "zuulServlet")    
public ServletRegistrationBean zuulServlet() { ... }

The issue here is that ServletRegistrationBean uses javax.servlet.Registration$Dynamic, which is not available until Servlet 3.0. This results in a NoClassDefFoundError.

To work around this, use the spring-boot-legacy project to first register a DispatcherServlet. Secondly, you'll have to manually create a zuul servlet.

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" 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">

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>com.dm.gateway.microservicegateway.Application</param-value>
    </context-param>

    <listener>
        <listener-class>org.springframework.boot.legacy.context.web.SpringBootContextLoaderListener</listener-class>
    </listener>

    <filter>
        <filter-name>ContextLifecycleFilter</filter-name>
        <filter-class>com.netflix.zuul.context.ContextLifecycleFilter</filter-class>
    </filter>


    <filter-mapping>
        <filter-name>ContextLifecycleFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <servlet>
        <servlet-name>appServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextAttribute</param-name>
            <param-value>org.springframework.web.context.WebApplicationContext.ROOT</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet>
        <servlet-name>zuul</servlet-name>
        <servlet-class>com.netflix.zuul.http.ZuulServlet</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>appServlet</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>

</web-app>

I found the best way to remove the auto servlet registration, is to just make a verbatim copy of ZuulConfig called ZuulOverrideConfig, and remove the zuulServlet() method. This is because the ZuulProxyConfiguration extends ZuulConfiguration, and it seemed to create the bean even when i tried to override it. I'm not 100% on the mechanics behind this, so there may be a better way.

The second change I made in ZuulOverrideConfig was to call an extended implementation of ZuulFilterInitializer, called 'LegacyZuulFilterInitializer`. This is because for some reason, the Zuul servlet was being crated, and able to be invoked, but no filters were bootstrapped. This extension is a hacky way to get the filters to bootstrap.

Next, I created a copy of ZuulProxyConfiguration called ZuulLegacyProxyConfiguraiton, and had it extend ZuulOverrideConfig.class.

Finally, I annotated the Application class as follows.

@EnableCircuitBreaker
@EnableDiscoveryClient
@Import(ZuulLegacyProxyConfiguration.class)
@SpringBootApplication
public class Application {....}

After all these hacks, the implementation finally worked as expected. I wouldn't suggest using this for long, as it's pretty hacky. You won't get configuration class updates automatically when moving to new versions, and I can't guarantee that something won't break randomly!

This is using Spring Cloud 1.1.4.RELEASE

Gist of all the code.

aglassman
  • 2,643
  • 1
  • 17
  • 30