I need to create a Spring bean so that it stores serverName, serverPort, contextPath properties of a HttpServletRequest object so that I can inject this bean to other beans as I need.
In my opinion, those properties do not change with any URI so that it is good to initialize this once (anyway, passing request instance many times is not so expensive at all).
The problem is, how can I inject HttpServletRequest instance to my configuration bean? I prefer xml based injection. Most probably we need to inject it as a <property> but I do not know what will be name or ref for this ServletRequest object.
The aim is to hold those variables in a bean so that they will be accessible from any bean and I won't need to pass request object to many methods as an argument when I need to obtain serverName etc.
Any ideas how to create such a bean and its configuration?
You can do this using a request-scoped bean, and autowiring the current request into your bean:
public class RequestHolder {
private #Autowired HttpServletRequest request;
public String getServerName() {
return request.getServerName();
}
}
And then in the XML:
<bean id="requestHolder" class="com.x.RequestHolder" scope="request">
<aop:scoped-proxy/>
</bean>
You can then wire the requestHolder bean into wheiever business logic bean you choose.
Note the <aop:scoped-proxy/> - this is the easiest way of injecting a request-scoped bean into a singleton - see Spring docs for how this works, and how to configure the aop namespace.
Related
This question already has answers here:
How does a ScopedProxy decide what Session to use?
(3 answers)
Closed 7 years ago.
I am trying to use session scope bean in spring mvc with following bean definitions
<bean id="test" class="com.gk.testScope.Test" scope="session">
<property name="name" value="mytest"></property>
<aop:scoped-proxy/>
</bean>
Code for controller
#Controller
public class MyController
{
#Autowired
Test t;
#RequestMapping(value="test1",method=RequestMethod.GET)
public String test1(HttpServletRequest request) {
System.out.println("name"+t.getName());
request.getSession();
return "test1";
}
}
on running above code it prints mytest even before starting any session. Can some one explain what session scope doing here?
Below line of code does not actually create session, it gets the session already created by the servlet container.
request.getSession();
Now comes the important stuff. Bit tricky to get at first if you are new to Spring scopes.
Injecting a singleton bean in another singleton bean is intuitive and makes sense. How about you want to inject a bean which is not Singleton into a Singleton bean? The injection should happen on demand right ? So to configure this, we cant directly inject the bean which is not singleton. We inject a proxy for a non singleton bean, which in turn gets a new bean injected on demand.
<aop:scoped-proxy/>
The above tag helps create a new bean for every session(because the scope is "session") created on the server and injects in the controller on demand.
I am sure someone can explain in much simpler manner. Hope this helps.
The spring framework provides an inversion-of-control coding framework; that means you only has to concern your business logic and write down it as handler function, the spring framework would take care the rest of things and call your handler function.
For example, in a mvc spring framework, the http request handling, http session handling, the beans life-cycle management are all done in spring-framework and you only needed to write the "test1()" function that is called when client hit the URL "/test1".
When client start a HTTP session with spring web server, the framework will create a session scope, and all session scope beans will be created. When client sends a HTTP request, the framework will create a Request scope and all create request level scope beans.
Please see 6.5 Bean scopes from spring reference doc.
I have a common situation: I have a scenario where object creation is handled by a builder.
e.g.
Class Client; // Creates a builder object.
Class Builder; // Can be used to set the desired params and then invoke build on it to return Service object.
e.g.-
client.createBuilder().withDefaultBinding(new StandardBinder())
.withDefaultMetricsFactory(new StandardMetricsFactory())
.withCacheSolution(cacheSolution)
.build();
However, Builder doesn't have standard setters. It performs some tasks and then sets the result into an internal object of Builder, so they can't be treated as properties as is.
I've read through: Spring: Using builder pattern to create a bean
I want to invoke the builder to retrieve the final object completely using Spring XML configuration.
I don't want to create a factory myself - I want to know if there is a way I can use an out-of-the-box Spring XML configuration to generate a service object in the above scenario? My understanding of Spring gives me the impression that this can be done by invoking a chain of setter methods (not setting the properties explicitly) on the builder objects and finally invoking a build to get the service object. If this is possible how would it be achieved?
There's no way to do this out-of-the-box with XML. Define a FactoryBean with appropriate properties (setters) for all the values you need and declare a bean of that custom FactoryBean type.
I've made it work when I wasn't able to "fix" the builder, and was only able to adjust config, not code.
Define a bean that uses "client" as a factory bean and "createBuilder" as the factory method.
Define another bean that uses that bean as a factory bean and "withDefaultBinding" as the factory method.
Define another bean that uses that bean as a factory bean and "withDefaultMetricsFactory" as the factory method.
Define another bean that uses that bean as a factory bean and "withCacheSolution" as the factory method.
Finally define your built bean that uses that bean as a factory bean and "build" as the factory method.
All but the last bean will actually point to the same object in memory, but that doesn't really matter.
I did have a similar case:
#Value("${some.property}")
String someProperty
#Bean
public JwtDecoder jwtDecoder() {
NimbusJwtDecoder.withJwkSetUri(someProperty).build();
}
Here's what I've done:
<bean id="jwtDecoder" class="org.springframework.security.oauth2.jwt.NimbusJwtDecoder" factory-bean="jwtDecoderBuilder" factory-method="build"/> <!-- factory-bean -->
<bean id="jwtDecoderBuilder" class="org.springframework.security.oauth2.jwt.NimbusJwtDecoder" factory-method="withJwkSetUri"> <!-- NO factory-bean -->
<constructor-arg name="jwkSetUri" value="${some.property}"/>
</bean>
NimbusJwtDecoder source code:
https://github.com/spring-projects/spring-security/blob/5.2.2.RELEASE/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusJwtDecoder.java
I'm trying to inject a Spring-managed bean and a string value into a servlet. The servlet is defined in context.xml as following:
<bean name="gwtlogging" class="com.somepackage.MyRemoteLogger">
<property name="symbolMapsDirectory" value="/WEB-INF/deploy/gwt/symbolMaps/"/>
<property name="serializationPolicyResolver" ref="serializationPolicyResolver"/>
</bean>
I came across using this method:
#Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this,
config.getServletContext());
}
This works, but has some disadvantages:
I want to inject beans as defined in context.xml and not per autowiring
I need to inject a string value (not a bean), which seems impossible this way
Ideally I want that all values defined in xml will be somehow injected into servlet instance.
If it's available to you, you can declare a Servlet bean in your XML configuration file, use Spring's WebApplicationInitializer (or write your own ServletContainerInitializer) to load the XML file in a WebApplicationContext, retrieve the Servlet bean, and add it to the ServletContext with add(String, Servlet).
The Servlet instance will have been completely prepared through Spring and will be used by your Servlet container.
As I know per default are controllers in Spring MVC singletons. HttpServletRequest passed offen to the controller handler method. And its ok, while HttpServletRequest is request-scoped, but I see often HttpServletRequest gets #Autowired into the controller field, like this:
#Controller("CMSProductComponentController")
#RequestMapping(CMSProductComponentController.CONTROLLER_PATH)
public class CMSProductComponentController {
#Autowired
private HttpServletRequest request;
}
Could be this a problem? And more general question: What happens if inject a reqeust-scoped component into a singleton?
No, for HttpServletRequest it will not be a problem and it shouldn't for other request scoped beans. Basically, Spring will generate a proxy HttpServletRequest that wraps some kind of ObjectFactory (RequestObjectFactory for HttpServletRequest) (YMMV) that knows how to retrieve the actual instance. When you use any of the methods of this proxy, they will delegate to that instance.
What's more, this is done lazily, so it won't fail at initialization. It will however fail if you try to use the bean when there is no request available (or if you haven't registered the RequestScope).
The following is in response to the comments and to clarify in general.
Regarding the proxy-mode attribute of #Scope or the XML equivalent, the default is ScopedProxyMode.NO. However, as the javadoc states
This proxy-mode is not typically useful when used with a non-singleton
scoped instance, which should favor the use of the INTERFACES or
TARGET_CLASS proxy-modes instead if it is to be used as a dependency.
With request scoped beans, this proxy-mode value will not work. You'll need to use INTERFACES OR TARGET_CLASS depending on the configuration you want.
With scope set to request (use the constant WebApplicationContext.SCOPE_REQUEST), Spring will use RequestScope which
Relies on a thread-bound RequestAttributes instance, which can be
exported through RequestContextListener, RequestContextFilter or
DispatcherServlet.
Let's take this simple example
#Component
#Scope(proxyMode = ScopedProxyMode.INTERFACES, value = WebApplicationContext.SCOPE_REQUEST)
public class RequestScopedBean {
public void method() {}
}
...
#Autowired
private RequestScopedBean bean;
Spring will generate two bean definitions: one for your injected bean, a singleton, and one for the request scoped bean to be generated on each request.
From those bean definitions, Spring will initialize the singleton as a proxy with the types of your target class. In this example, that is RequestScopedBean. The proxy will contain the state it needs to produce or return the actual bean when it is needed, ie. when a method is called on the proxy. For example, when
bean.method();
is called.
This state is basically a reference to the underlying BeanFactory and the name of the request-scoped bean definition. It will use these two to generate a new bean and then call method() on that instance.
The documentation states
The Spring IoC container manages not only the instantiation of your
objects (beans), but also the wiring up of collaborators (or
dependencies). If you want to inject (for example) an HTTP request
scoped bean into another bean, you must inject an AOP proxy in place
of the scoped bean. That is, you need to inject a proxy object that
exposes the same public interface as the scoped object but that can
also retrieve the real, target object from the relevant scope (for
example, an HTTP request) and delegate method calls onto the real
object.
All eagerly loaded request scoped beans, if implemented correctly, will be proxies. Similarly, request scoped beans that aren't eagerly loaded will either be proxies themselves or be loaded through a proxy. This will fail if there is no HttpSerlvetRequest bound to the current thread. Basically, a proxy is necessary somewhere in the bean dependency chain for request scoped beans.
What happens if inject a reqeust-scoped component into a singleton?
Try it and you'll get a BeanCreationException¹ during application context initialization. The error message clearly explains why this doesn't happen with HttpServletRequest:
Scope 'request' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton;
So obviously HttpServletRequest is a scoped proxy. If you want to use beans of smaller scopes in singletons they have to be proxies. The documentation elaborates about smaller scoped dependencies in Scoped beans as dependencies.
[1]: unless you didn't change the default behaviour for proxyMode, which is NO or try to inject it with #Lazy. The latter might result into a valid application context but might lead to request scoped beans acting like singletons (e.g. if a request scoped bean is injected into a singleton).
Can someone explain the usage of the spring #ScopedProxy annotation? I thought it had something to do with session scoped beans, but I'm not quite sure what.
In my usage of scopes, I've used session scoped beans without the #ScopedProxy annotation (or without aop scoped proxies), so I'm really sure how to use it properly.
Section 3.4.4.5 of the spring docs explains it pretty well:
(please note that the following 'userPreferences' bean definition as it stands is incomplete):
<!-- an HTTP Session-scoped bean -->
<bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/>
<!-- a singleton-scoped bean -->
<bean id="userManager" class="com.foo.UserManager">
<property name="userPreferences" ref="userPreferences"/>
</bean>
From the above configuration it is evident that the singleton bean 'userManager' is being injected with a reference to the HTTP Session-scoped bean 'userPreferences'. The salient point here is that the 'userManager' bean is a singleton... it will be instantiated exactly once per container, and its dependencies (in this case only one, the 'userPreferences' bean) will also only be injected (once!).
This means that the 'userManager' will (conceptually) only ever operate on the exact same 'userPreferences' object, that is the one that it was originally injected with.
This is not what you want when you inject a HTTP Session-scoped bean as a dependency into a collaborating object (typically). Rather, what we do want is a single 'userManager' object per container, and then, for the lifetime of a HTTP Session, we want to see and use a 'userPreferences' object that is specific to said HTTP Session.
Rather what you need then is to inject some sort of object that exposes the exact same public interface as the UserPreferences class (ideally an object that is a UserPreferences instance) and that is smart enough to be able to go off and fetch the real UserPreferences object from whatever underlying scoping mechanism we have chosen (HTTP request, Session, etc.). We can then safely inject this proxy object into the 'userManager' bean, which will be blissfully unaware that the UserPreferences reference that it is holding onto is a proxy.
In our case, when a UserManager instance invokes a method on the dependency-injected UserPreferences object, it will really be invoking a method on the proxy... the proxy will then go off and fetch the real UserPreferences object from (in this case) the HTTP Session, and delegate the method invocation onto the retrieved real UserPreferences object.
That is why you need the following, correct and complete, configuration when injecting request-, session-, and globalSession-scoped beans into collaborating objects:
<bean id="userPreferences" class="com.foo.UserPreferences" scope="session">
<aop:scoped-proxy/>
</bean>
<bean id="userManager" class="com.foo.UserManager">
<property name="userPreferences" ref="userPreferences"/>
</bean>
After trying out various different options specified here and spring documentation, i have figured out for some reason Spring MVC, is wierdly autowiring controller when you use #Controller annotation and where you have more than one such controller in your webapp. Modified the annotation to #RestController (value="UniqueControllerv1"), the issue is resolved.