Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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 ?

like image 658
temsa Avatar asked Jan 26 '10 11:01

temsa


3 Answers

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.

like image 88
skaffman Avatar answered Sep 24 '22 01:09

skaffman


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 (i.e. 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.

like image 37
Bozho Avatar answered Sep 24 '22 01:09

Bozho


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); %>
like image 39
Dmytro Plekhotkin Avatar answered Sep 26 '22 01:09

Dmytro Plekhotkin