3

在将依赖注入作为一种风格变得非常熟悉之后,我发现自己编写了一个类似这样的 HTTP servlet:

public class FooServlet extends HttpServlet {

private Dependency dependency;

public void setDependency(Dependency dependency) {
    this.dependency = dependency;
}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        ...
        Result r = dependency.doSomething(...);
        ...
}

这非常容易进行单元测试,而且我很想保留这个模型——但是现在我将它部署在 Tomcat 中,我意识到我不知道我可以从哪里调用 setDependency()。

想到一些模糊的可能性:

  • 在 init() 中获取 servlet 参数。这些只是字符串,所以我必须做一些反射来创建。这不是真正的 DI。刚刚配置了依赖创建。
  • JNDI 的一些东西
  • 不知何故,从嵌入 Tomcat 的 Java 程序中,让 Tomcat 给我一个 Servlet 对象的引用,让我可以调用它的 setter。
  • 使用弹簧。如果我使用 Spring,我会寻找保持它轻量级的方法。这个应用程序不够复杂,不足以保证 Spring MVC。
4

3 回答 3

2

我会使用 Spring,因为它提供了一个庞大的特性和功能生态系统,您的项目可以使用它来增强它。但前提是你真的会使用它们。加载如此庞大的框架只是为了在一个地方使用一个小功能是没有意义的。

也就是说,您还应该小心,因为该doPost()方法将由不同的线程调用,而您的dependency对象是成员变量。这将使您的代码线程不安全,因为dependency如果它是单例,则不同的线程可以同时使用相同的实例。

于 2013-03-06T10:50:28.207 回答
2

实际上只需要两行代码就可以@Autowire在 servlet 中工作:

ApplicationContext appContext = WebApplicationContextUtils.getRequiredWebApplicationContext( getServletContext() );
appContext.getAutowireCapableBeanFactory().autowireBean( this );

但是有一个缺点:Servlet 是单例,它们不是由 Spring 创建的,因此您不能注入原型 bean。因此,只要所有注入的 bean 都是单例,这将起作用。当您稍后添加原型 bean 时,代码将开始失败并出现奇怪的错误。

出于这个原因,我通常创建处理程序 bean(请参阅参考资料HttpRequestHandler)并在其中创建它们,doPost()而不是自动装配 servlet 本身。

于 2013-03-06T10:53:05.130 回答
0

感谢 Aaron 和 Filipe,我发现 Spring 似乎是最轻量级的用法。

在 WEB-INF/web.xml 中配置一个 Dispatching servlet:

    <servlet>
            <servlet-name>
                    myDispatcher
            </servlet-name>
            <servlet-class>
                    org.springframework.web.servlet.DispatcherServlet
            </servlet-class>
            <init-param>
                    <param-name>contextConfigLocation</param-name>
                    <param-value>/WEB-INF/spring/myDispatcher-context.xml</param-value>
            </init-param>
    </servlet>

在 WEB-INF/spring/myDispatcher-context.xml 中,显式配置应用程序上下文,以便 BeanNameUrlHandlerMapping 将请求映射到您的处理类,并注入您的依赖项。

    <bean id="/*" class="org.me.MyHandler">
        <property name="dependency" ref="dependency"/>
    </bean>
    <bean id="dependency" class="org.me.myDependency"/>

将 MyHandler 编写为一个实现HttpRequestHandler- 它非常类似于 Servlet。

这给了你依赖注入。它避免了类路径扫描,并且不加载几十个类——但如果你以后想采用更高级的 Spring MVC 特性,机会就在那里。

于 2013-03-06T12:41:11.990 回答