【问题标题】:What is the cleanest way to autowire Spring Beans in a JSP?在 JSP 中自动装配 Spring Bean 的最简洁方法是什么?
【发布时间】:2011-01-09 11:52:05
【问题描述】:

我们目前正在向一个仅使用 JSP 且前端没有任何框架的旧 Web 应用程序添加一些新功能。我们最近添加了 Spring,我们希望在修改后的 JSP 中自动装配 bean,而不是重写所有内容以使用 SpringMVC、Struts2 或 Tapestry5。

我们使用按类型自动装配,因此它会导致在 JSP 中获取一些类似这样的代码,而之前获取 Web 应用程序上下文(如“wap”):

MyDao myDao = (MyDao) wap.getBeansOfType(MyDao.class).values().toArray()[0];

我们不想使用这样的代码,而是像使用 @Autowired 注解在业务 bean 中一样,自动将 bean 直接注入到 JSP 中。

事实上,我们正在寻找将 bean 注入 JSP 的最干净的方法。你用什么?

【问题讨论】:

  • SpringMVC 的好处是您不必吞下整个药丸。您可以选择要使用的弹簧部件。按照 Stephen C 的指示进行重构可能会更干净。

标签: java spring jsp autowired


【解决方案1】:

你可以使用Spring的ContextExposingHttpServletRequest

HttpServletRequest 装饰器 在给定的情况下制作所有 Spring bean WebApplicationContext 可访问为 请求属性,通过lazy 属性获取后检查 访问。

这将需要您的控制器代码将原始 HttpServletRequest 包装在 ContextExposingHttpServletRequest 中,然后将 转发到 JSP。它可以公开特定的命名 bean,也可以公开上下文中的每个 bean。

当然,这只是将问题从您的 JSP 转移到您的控制器代码,但这可能是一个更易于管理的问题。

【讨论】:

  • 您如何看待将其更改为 JSP 之上的过滤器(而不是 servlet),该过滤器从 Spring 上下文中获取所有 bean 并将它们放在请求范围内,按预期的接口按顺序命名有一个类似的 getByType ?
  • (+1) request-wrapper 不错。尽管如此,@Autowired 还是不能这样使用?
  • @Bozho:不会,不,但是可以在 JSP 中引用 bean,无需任何显式连接。
  • 我们或许可以使用static.springsource.org/spring/docs/2.5.x/api/org/… 作为过滤器的基础
【解决方案2】:

您不能直接使用@Autowired,因为您的jsps 和servlet 都是由servlet 容器实例化的。因此它们不是 spring 上下文的一部分,因此它们的依赖项不会被注入。

你可以:

  1. 将所有代码移至纯 servlet,而不是 jsps - 仅在 jsps 中保留演示文稿。
  2. 在您的 servlet 上使用 @Configurable(并添加一个 javaagent,如链接文档中所述)

另一种方法是手动使 servlet 成为当前上下文的一部分。这在 jsps 和 servlet 中都是可能的:

public void init() {
    WebApplicationContext ctx = WebApplicationContextUtils
         .getRequiredWebApplicationContext(getServletContext());

    AutowireCapableBeanFactory bf = ctx.getAutowireCapableBeanFactory();

    bf.autowireBean(this);
}

这将解决 @Autowired 注释的依赖关系。

现在,我不确定servlet 容器是否需要只使用一个 servlet 类的实例。如果不是,您最好将上述代码放在依赖项的 getter 方法中(getDao()),如果@Autowired 属性为null(即容器使用另一个servlet 类实例) - 执行上述操作。


话虽如此,真的考虑使用网络框架(您列出的任何框架)。 jsps中的逻辑是完全错误的,难以支持,难以阅读等等。

【讨论】:

  • 我肯定知道,但你不可能在 5 天内重写整个软件(包括拆分前端和业务逻辑),同时添加新功能。实际上我们应该避免在那里使用DAO,然后编写也只依赖业务对象,但这只是一些已经编写好的代码,我无法在这么多时间重写。说服经理将应用程序转换为 Spring/Hibernate/Jpa 而不是自制的单例和公司制造的 ORM 工具已经是一个巨大的痛苦。他们只认为这是一种成本......
【解决方案3】:

如何重写 jspInit() 方法并添加自动装配支持:

<%@ page import="com.example.ExampleService"%>
<%@ page import="org.springframework.beans.factory.annotation.Value"%>
<%@ page import="org.springframework.beans.factory.annotation.Autowired"%>
<%@ page import="org.springframework.web.context.support.SpringBeanAutowiringSupport"%>
<%!
    public void jspInit() 
    {
        SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this,
        getServletContext());
    }

    @Value("${example.property}")
    private String someField;

    @Autowired
    private ExampleService exampleService;
%>

<% final Object data = exampleService.getSomething(someField); %>

【讨论】:

    【解决方案4】:

    我怀疑是否有一种干净的方法可以将依赖项注入 JSP。

    我认为干净的解决方案是使用 SpringMVC 或您引用的替代方案之一开始重构您的代码以从 JSP 中获取业务逻辑。

    从一个或多个极简控制器开始,这些控制器简单地将请求传递给 JSP,并将注入的 bean 作为属性; @skaffman 的回答提供了一种方法来做到这一点,或者你可以更有选择性地做到这一点。然后逐步将代码从 JSP 迁移到控制器中。

    【讨论】:

      【解决方案5】:

      这不是自动装配的,但 Spring 可以将您的 bean 名称公开到请求上下文中,您只需在 viewResolver 中配置它。

      发件人:https://raibledesigns.com/rd/entry/spring_mvc_jstlview_and_exposecontextbeansasattributes

      <bean id="viewResolver" 
          class="org.springframework.web.servlet.view.InternalResourceViewResolver">
          <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
          <property name="exposeContextBeansAsAttributes" value="true"/>
          <property name="prefix" value="/"/>
          <property name="suffix" value=".jsp"/>
      </bean>
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-08-19
        • 2016-09-27
        • 2017-05-21
        • 1970-01-01
        • 2011-04-10
        • 2012-12-04
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多