Clean up a RequestScoped Object

185 views
Skip to first unread message

cowwoc

unread,
Jan 21, 2011, 3:36:00 PM1/21/11
to google-guice
Hi,

Following up on this earlier discussion:
http://groups.google.com/group/google-guice/browse_frm/thread/7252f908ef00638a/9a59803c16a9583e?lnk=gst&q=clean+%40requestscoped#9a59803c16a9583e

What is the best way to clean up a @RequestScoped JDBC connection? Am
I supposed to register a second ServletFilter after GuiceFilter (shown
below) or is there an easier way?

public class ConnectionFilter implements Filter
{
private ServletContext context;

@Override
public void init(FilterConfig filterConfig) throws ServletException
{
this.context = filterConfig.getServletContext();
}

@Override
public void doFilter(ServletRequest servletRequest, ServletResponse
servletResponse,
FilterChain chain)
throws IOException, ServletException
{
Injector injector = (Injector)
context.getAttribute(Injector.class.getName());
Connection connection = injector.getInstance(Connection.class);

try
{
chain.doFilter(servletRequest, servletResponse);
}
finally
{
connection.close();
}
}

@Override
public void destroy()
{
}
}


Thanks,
Gili

Willi Schönborn

unread,
Jan 21, 2011, 3:38:39 PM1/21/11
to google...@googlegroups.com
You should be aware that this might create and open
a jdbc connection just to close it right away.

cowwoc

unread,
Jan 21, 2011, 3:49:35 PM1/21/11
to google...@googlegroups.com

Good point. Is there a way to check if a Connection has already
been instantiated?

Also, is there a cleaner way of passing an Injector to
ConnectionFilter? Right now I am depending upon the fact that
GuiceServletContextFilter sets an attribute with the name
"Injector.class.getName()". This is an implementation detail that may
change in the future. Is there a way for me to pass an Injector from
GuiceServletContextFilter as a filter parameter? I saw thought of
passing parameters using:

filter("/*").through(ConnectionFilter.class, param);

but the Injector hasn't been instantiated at that point.

Thanks,
Gili

Willi Schönborn

unread,
Jan 21, 2011, 3:52:45 PM1/21/11
to google...@googlegroups.com
I successfully used custom scope implementations which check for
instances which require proper destruction (Closeables, @PreDestroy, ...).
This requires of course some kind of a strictly defined exit point.

cowwoc

unread,
Jan 21, 2011, 4:10:38 PM1/21/11
to google...@googlegroups.com
Hi Willi,

How do you do that? Can you please post some code that shows
cleaning up Closeables on scope shutdown?

Thank you,
Gili

Christopher Currie

unread,
Jan 21, 2011, 4:15:14 PM1/21/11
to google...@googlegroups.com
My $0.02 which are somewhat not guice related:

I would assume that in production at least you are using a connection
pool for which the cost of "opening a connection" is mitigated. When
you do this, you can effectively open/close connections on a
per-statement or per-transaction basis without the performance cost
that would normally imply, instead of using request scoped connection.

One thing your filter does which is convenient, though, is ensure that
your connections are "closed" (i.e., returned to the connection pool)
without having to rely on remembering to do so. A useful library that
provides an alternative is JDBI:

https://github.com/brianm/jdbi

With this you can inject a @Singleton instance of DBI and use it thusly:

dbi.withHandle( new HandleCallback<Void>() {
// the DBI instance will open a connection, wrap in a Handle object and pass
// it to the callback:

public Void withHandle(Handle handle) throws Exception {
// Do your SQL operations using the handle

return null;
}

// Handle is closed by the DBI before returning.
});

It's slightly more code than you'd normally need when using a
Connection object directly, but you can hide all that within a DAO
wrapper object of some kind and inject that instead.

YMMV,
Christopher


2011/1/21 Willi Schönborn <w.scho...@googlemail.com>:


> I successfully used custom scope implementations which check for
> instances which require proper destruction (Closeables, @PreDestroy, ...).
> This requires of course some kind of a strictly defined exit point.
>
> On 21/01/11 21:49, cowwoc wrote:
>>
>>    Good point. Is there a way to check if a Connection has already been
>> instantiated?
>>
>>    Also, is there a cleaner way of passing an Injector to
>> ConnectionFilter? Right now I am depending upon the fact that
>> GuiceServletContextFilter sets an attribute with the name
>> "Injector.class.getName()". This is an implementation detail that may change
>> in the future. Is there a way for me to pass an Injector from
>> GuiceServletContextFilter as a filter parameter? I saw thought of passing
>> parameters using:
>>
>> filter("/*").through(ConnectionFilter.class, param);
>>
>>    but the Injector hasn't been instantiated at that point.
>>
>> Thanks,
>> Gili
>>

> --
> You received this message because you are subscribed to the Google Groups
> "google-guice" group.
> To post to this group, send email to google...@googlegroups.com.
> To unsubscribe from this group, send email to
> google-guice...@googlegroups.com.
> For more options, visit this group at
> http://groups.google.com/group/google-guice?hl=en.
>
>

Willi Schönborn

unread,
Jan 21, 2011, 6:56:42 PM1/21/11
to google...@googlegroups.com
On 21/01/11 22:10, cowwoc wrote:
> Hi Willi,
>
> How do you do that? Can you please post some code that shows
> cleaning up Closeables on scope shutdown?
Take a look at some classes in https://github.com/palava/palava-scope.
Note that these are totally custom made scopes,
i have no idea how to do that with the RequestScope. I think guiceyfruit
supports that but they rely
on a patched version of Guice, so that is not really an option (for me).

Willi Schönborn

unread,
Jan 21, 2011, 7:04:56 PM1/21/11
to google...@googlegroups.com
On 21/01/11 21:49, cowwoc wrote:
>
> Good point. Is there a way to check if a Connection has already
> been instantiated?
>
> Also, is there a cleaner way of passing an Injector to
> ConnectionFilter? Right now I am depending upon the fact that
> GuiceServletContextFilter sets an attribute with the name
> "Injector.class.getName()". This is an implementation detail that may
> change in the future. Is there a way for me to pass an Injector from
> GuiceServletContextFilter as a filter parameter? I saw thought of
> passing parameters using:
>
> filter("/*").through(ConnectionFilter.class, param);
Just add the following constructor to your filter:

@Inject
ConnectionFilter(Injector injector) {
// save injector for later use in an instance field
this.injector = injector;
}

I think the cleaner approach would be rely on Provider<Connection>.
Same problem as before though (connection might be opened just to get
closed).

What you might can do is looking at the current request using:

request.getAttribute(Key.get(Connection.class).toString())

But this relies heavily on the implementation details of
ServletScopes.REQUEST.

Reply all
Reply to author
Forward
0 new messages