1

In our project, we use Spring request scoped beans. Now we've a requirement to support async requests and request scoped beans don't work for child threads. I'm aware of RequestContextFilter and it's "support" for async but it appears that RequestContextFilter expects the main thread to wait for the child threads to finish, which isn't the case for us. Our main thread immediately returns after spawning new threads using @Async annotation and DispatcherServlet clears out the RequestContextHolder. Thus when the child threads get to the point where they need a request scoped bean, @Autowired fails.

I'm also aware of SimpleThreadScope but it doesn't clean up thread-local attributes and in a thread-pooling situation, is not only dangerous to use but downright useless.

What I need is a custom scope. So far, I've found 3 useful examples but all of them fall short in that the beans they instantiate as part of the custom scope are plain POJOs without any dependencies. Needless to say that's non-existent in a real life application. Can anyone suggest a way to instantiate custom scoped beans that have @Autowired dependencies on beans from other scopes?

What I found so far:

https://github.com/spring-by-example/spring-by-example/tree/master/modules/sbe-thread-scope/src/main/java/org/springbyexample/bean/scope/thread

https://github.com/billkoch/spring-async-mdc

Spring Bean Custom Scope JMS

Community
  • 1
  • 1
Abhijit Sarkar
  • 21,927
  • 20
  • 110
  • 219
  • async support on the web layer and just slapping `@ASync` are different things. Instead you want to use a `DefferedResult` or `Callable` and return that from your controller. That way you can use the async capabilities of the servlet spec. When using `@Async` you basically get a background thread with no way of accessing the request scoped variables. – M. Deinum Jun 15 '15 at 10:51
  • @M.Deinum No we don't want to use a `DeferredResult` or `Callable` from the controller because our clients can't handle that. Our requirement is unique in the way described above. – Abhijit Sarkar Jun 15 '15 at 15:02
  • Then why even use a request scoped bean? Just pass the needed things as method arguments, no need for a custom scope that would only complicate things... – M. Deinum Jun 15 '15 at 18:34
  • Pass a dozen things as method arguments? No thanks. Even wrapping them in one object and passing through is objectionable design. – Abhijit Sarkar Jun 15 '15 at 19:06
  • That is an opinion, imho misusing scopes for something like that is questionable. You already have the object so you are already setting stuff in it, what would make it worse as passing that around as a single object instead of using a scope. – M. Deinum Jun 15 '15 at 19:19

1 Answers1

1

Continuing the discussion from the other question's answer here...

See the Spring Documentation about scoped beans as dependencies.

.

I'm referring to the <aop:scoped-proxy/> which is what the link points to. Each time the autowired field is referenced, your custom scope's get() method is called to lookup the instance based on some criteria.

.

I understand I can look up the dependencies (though unsure how, a scope isn't a bean, perhaps I need to pass application context during instantiation?). What I don't understand is how to inject those dependencies into my bean if those're marked @Autowired? Or are you saying the custom scoped bean shouldn't have @Autowired dependencies?

It works automatically; Spring injects a proxy for the bean and the scope.get() is invoked on every method call on that bean, returning the specific instance you want in the context of the current invocation.

Take a look at the AbstractRequestAttributesScope to see how it works (in that case, gets the instance from the HTTP Request and, if it doesn't exist, creates it).

So, your code calls foo() on the proxy; the framework calls the scope to get the desired instance and then calls foo() on that instance.

The exposed methods you wish to call must either be on an interface or not declared final.

Community
  • 1
  • 1
Gary Russell
  • 166,535
  • 14
  • 146
  • 179
  • I made a small project trying to do 2 things: 1) Create a custom scope, works fine. 2) Make the custom scope work when `@Async` is used, doesn't work. The class that spins up new threads is `AnnotationAsyncExecutionInterceptor` that I subclassed and then hacked around to have Spring call my class instead of it's own. Somehow it keeps calling `AnnotationAsyncExecutionInterceptor.invoke` and not mine. The following maven project may be checked out and a `mvn clean test` would show the problem. https://github.com/abhijitsarkar/java-ee/tree/master/spring-custom-scope – Abhijit Sarkar Jun 17 '15 at 09:19