Generisches Spring-Servlet

de

Manchmal braucht man neben den MVC Mechanismen von Spring-Web auch ein ganz normales Servlet, welches nicht einem Handler entspricht, der ModelAndView zurückgibt. Leider ist so ein Servlet dann aber selbst keine Spring-Bean, sondern muss sich selbst des Spring-Contexts bedienen, um an die Spring-Beans heranzukommen und Dependencies zu setzen.

Ein generisches Spring-Servlet, welches auf eine Servlet-Spring-Bean delegiert, schafft Abhilfe …

Alles was es braucht ist eine Servlet-Deklaration in der web.xml:

<servlet> <servlet-name>test</servlet-name> <servlet-class> com.rinke.solutions.spring.servlet.GenericSpringServlet </servlet-class> </servlet> 

eine Bean Definition im Spring-Context:

<!-- define a servlet a spring bean, will be called from generic spring servlet --> <bean id="test" class="com.rinke.solutions.TestServlet" scope="prototype"> <property name=".." ref=".."/> </bean> 

Und ein Servlet wie dieses:

package com.rinke.solutions.spring.servlet; import java.io.IOException; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServlet; import org.springframework.web.context.support.WebApplicationContextUtils; /** * generic servlet class that holds the springs WebApplicationContext in * its init method. it delegates to another servlet defines in the spring * context and injected through spring. * a servlet used a delegate should defined with scope 'prototype' otherwise when * the container tries to instanciate more than one instance of the generic * servlet the delegate still remain one singleton. * * @author ster */ public class GenericSpringServlet extends HttpServlet { private HttpServlet delegate; /** * just delegate to the "spring" servlet. * @inheritDoc * @see javax.servlet.Servlet#service(javax.servlet.ServletRequest, javax.servlet.ServletResponse) */ @Override public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { delegate.service(req,res); } /** * retrieves a servlet bean from the context with the same name that the generic * servlet is configured. if one instance of the generic servlet is named 'test', * a spring bean with id 'test' is searched and used as delegate. * @inheritDoc * @see javax.servlet.Servlet#init(javax.servlet.ServletConfig) */ @Override public void init() throws ServletException { ServletConfig config = getServletConfig(); delegate = (HttpServlet) WebApplicationContextUtils .getRequiredWebApplicationContext(config.getServletContext()).getBean( config.getServletName()); delegate.init(config); delegate.init(); } }

Per Konvention wird als Servlet “Bean” immer eine Bean, die so heißt wie der ServletName als Delegate benutzt.

en

Sometimes you need a simple servlet, which does not use spring mvc of the spring web package that does not deal with "ModelAndView". Unfortunately such a servlet isn’t itself a spring bean and hence must use the WebApplicationContext to resolve dependencies and get to its "worker" spring beans.

A generic spring servlet, which delegates to a spring bean, puts things right …

All you need is a servlet declaration in web.xml:

<servlet>
   <servlet-name>test</servlet-name>
   <servlet-class>
     com.rinke.solutions.spring.servlet.GenericSpringServlet
   </servlet-class>
</servlet>

a bean definition in the spring context:

<!-- define a servlet a spring bean, 
       will be called from generic spring servlet -->
<bean id="test" class="com.rinke.solutions.TestServlet" scope="prototype">
    <property name=".." ref=".."/>
</bean>

and a servlet like this:

package com.rinke.solutions.spring.servlet;

import java.io.IOException;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;

import org.springframework.web.context.support.WebApplicationContextUtils;

/**
 * generic servlet class that holds the springs WebApplicationContext in
 * its init method. it delegates to another servlet defines in the spring
 * context and injected through spring.
 * a servlet used a delegate should defined with scope 'prototype' otherwise when
 * the container tries to instanciate more than one instance of the generic
 * servlet the delegate still remain one singleton.
 *
 * @author ster
 */
public class GenericSpringServlet extends HttpServlet {

    private HttpServlet delegate;
    /**
     * just delegate to the "spring" servlet.
     * @inheritDoc
     * @see javax.servlet.Servlet#service(javax.servlet.ServletRequest, javax.servlet.ServletResponse)
     */
    @Override
    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
        delegate.service(req,res);
    }

    /**
     * retrieves a servlet bean from the context with the same name that the generic
     * servlet is configured. if one instance of the generic servlet is named 'test',
     * a spring bean with id 'test' is searched and used as delegate.
     * @inheritDoc
     * @see javax.servlet.Servlet#init(javax.servlet.ServletConfig)
     */
    @Override
    public void init() throws ServletException {
        ServletConfig config = getServletConfig();
        delegate = (HttpServlet) WebApplicationContextUtils
                .getRequiredWebApplicationContext(config.getServletContext()).getBean(
                        config.getServletName());
        delegate.init(config);
        delegate.init();
    }

}

The convention is simple: use a spring "servlet" bean with the same name as the servlet name as delegate.

Dieser Beitrag wurde unter Java veröffentlicht. Setze ein Lesezeichen auf den Permalink.

2 Antworten auf Generisches Spring-Servlet

  1. Stefan Fleiter sagt:

    Ich etwas ähnliches implementiert und mich dabei an DelegatingFilterProxy orientiert, was für Servlet-Filter das gleiche tut.
    Dabei habe ich den gleichen Fehler eingebaut wie Du.
    Da GenericServlet#init(ServletConfig) schon GenericServlet#init() ruft wird letzteres durch Deinen Code zwei mal gerufen.

    Ich habe meine Variante in Jira http://jira.springframework.org/browse/SPR-4299 als Contribution angeboten:

    Der zweite Patch korrigiert den Fehler.
    So wie es aussieht könnte das Teil von Spring 2.5.2 werden.

    Meine Variante übernimmt auch die Servlet-Prameter für
    gleichnamige Properties der DelegatingHttpServletProxy-Instanz.

    Viele Grüße,
    Stefan

  2. The convention is simple: use a spring “servlet” bean with the same name as the servlet name as delegate.

Hinterlasse eine Antwort

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind markiert *

Du kannst folgende HTML-Tags benutzen: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>