How to instantiate Spring bean with custom scope and @Autowired dependencies?

2.4k views Asked by At

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

1

There are 1 answers

1
Gary Russell On

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.