简体   繁体   中英

What is the cleanest way to autowire Spring Beans in a JSP?

We're currently adding some new features to an old webapp which was using only JSP without any framework for the front. We have added Spring recently, and we would like to autowire our beans in our modified JSP, while not rewriting everything to use SpringMVC, Struts2 or Tapestry5.

We're using autowiring by type, so it leads to get some code like this in the JSP, while previously getting the web application context ( as "wap") :

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

We would like not to use such a code but rather automagically inject our beans directly in our JSPs as we would in a business bean using @Autowired annotation.

In fact we're looking to the cleanest ways to inject our beans in our JSPs. What do you use ?

You can use Spring's ContextExposingHttpServletRequest :

HttpServletRequest decorator that makes all Spring beans in a given WebApplicationContext accessible as request attributes, through lazy checking once an attribute gets accessed.

This would require your controller code to wrap the original HttpServletRequest in a ContextExposingHttpServletRequest , and then forward that to the JSP. It can either expose specific named beans, or every bean in the context.

Of course, this just shifts the problem from your JSPs to your controller code, but that's perhaps a more manageable problem.

You can't use @Autowired directly because both your jsps and servlets are instantiated by the servlet conainer. So they are not part of the spring context and hence their dependencies aren't injected.

You can:

  1. move all code that to pure servlets, rather than in jsps - leave only presentation in the jsps.
  2. use @Configurable on your servlets (and add a javaagent, as described in the linked docs)

Another way, is to make the servlet part of the current context manually. This is possible in both jsps and servlets:

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

    AutowireCapableBeanFactory bf = ctx.getAutowireCapableBeanFactory();

    bf.autowireBean(this);
}

This will resolve the @Autowired annotated dependencies.

Now, I'm not sure whether servlet containers are required to use only one instance of a servlet class. If not, you'd better place the above code in a getter-method for the dependency ( getDao() ) and if the @Autowired property is null (ie another instance of the servlet-class is used by the container) - perform the above operation.


That all said, really consider using a web framework (any of the ones you listed). Having logic in jsps is completely wrong, hard to support, hard to read, etc.

What about overriding jspInit() method and adding Autowiring support:

<%@ 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); %>

I doubt that there is a clean way to inject dependencies into a JSP.

I think that the clean solution would be to start refactoring your code to get the business logic out of the JSPs, using either SpringMVC or one of the alternatives you cited.

Start with one or more minimalist controllers that simply pass the request to the JSPs with the injected beans as attributes; @skaffman's answer gives one way to do that, or you could do it more selectively. Then progressively migrate code out of the JSPs and into the controllers.

This isn't autowired, but Spring can expose your bean names into the request context, you just need to configure it in the viewResolver.

From: 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>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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