Need some help with Spring autowiring, and scopes.
Here is the basic app structure:
I have an CustomHttpClient, annotated as #Component, and also pulling some config-related properties from application.properties file (via #Value annotation).
CustomHttpClient is used by several services in my application. Whenever I'm using the CustomHttpClient, I autowire an instance of that via:
#Autowired
private CustomHttpClient httpClient;
I use interceptor to modify some of the variables inside CustomHttpClient, like so:
public class MyInterceptor extends HandlerInterceptorAdapter {
#Autowired CustomHttpClient httpClient;
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
httpClient.setSomeProperty(newValue);
...
Now, here is the problem. If I have everything set up as described above, then whenever I change any setting of the CustomHttpClient via interceptor, that new value is persisted for all other clients, as long as VM is running. So when I run httpClient.setSomeProperty() - that setting is now permanently saved. Even if I connect to the application from another client.
Basically what I need to have are two things:
Still being able to override default settings of the CustomHttpClient via interceptor (request interceptor, configured via ).
Make sure a new instance of CustomHttpClient is created for every request (after the interceptor does its' magic).
I tried changing the scope of CustomHttpClient to #Scope("prototype"), but that way I can no longer change settings of CustomHttpClient with an interceptor.
By default when you use #Autowired spring bean scope is singleton. That means spring injects the same singleton object where ever you use #Autowired. By making scope prototype you are instructing Spring to create new objects for each #Autowired injection, and so in your interceptor will have its own copy of HttpClient and cant see other HttpClient objects.
So better approach is use the singleton scope, Use request attributes or threadlocal to carry around your custom properties down the request thread. ie instead of modifying HttpClient properties in interceptor, just set some request attributes or threadlocals and handle these custom settings within CustomHttpClient class methods.
If your interceptor is only addding some properties then using thread local should be a better option. You can call ThreadLocal.set(custom Map) and use it wherever you want for the running thread and when your program is going to leave your controller you can call ThreadLocal.Unset which will clear the value stored.
This way you wont need a new instance of HttpcLient everytime, also a new instance every time would be a serious flaw. And you will be able to use your custom map anywhere you want in the running thread.
All beans declared in the Spring container enther by XML or by annotation support are by default singletons. If you inject a bean with scope set to prototype into a singleton e.g. a controller it will inject it only once. There is a way to achieve this goal. This is how you should declare a bean scoped as a prototype. This means that the container will always give you a new instance each time this bean is called upon from the container.
<bean id="shoppingCart" class="example.ShoppingCart" scope="request">
<aop:scoped-proxy />
</bean>
Related
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).
I have a question about #Service in spring, but i didn't find any response about it.
Situation :
I have a web application with #RestController using spring
Now for my service layer, I saw on some project two way of processing
#Service on service class and #Autowired on controller class (Create a bean that is a singleton excepted if we change the scope)
Create a object like a service
MyService service = new MySerivce()
So my questions are :
Create a object each time for each call of controller will not be a issue for memory ? If i create a load test (with Apache Jmeter) and send 1000 requests, it will create 1000 object my service so could be a problem no ?
Create a singleton with #Service will not be a issue for memory but, how spring will handle 1000 requests on 1 seconds for example. Will he push requests on a sort of queue and execute one at a time ?
What is the best practice for Service declaration and why ?
Thank in advance for any response
The whole point of dependency injection (using annotations such as #Autowired and #Service, #Component etc.) is to let Spring manage instances of service classes for you, instead of manually creating an instance with new MyService() each time you need it.
Letting Spring manage service class instances (and other Spring beans) has a number of advantages. For example, it makes it a lot easier to replace a service with a different implementation; you only need to change the Spring configuration for that. Also, it makes it easy to inject a mock version of a service for unit testing. Replacing real services with mocks would be really hard if the class you are trying to test is directly instantiating a specific implementation of the service class using new MyService().
how spring will handle 1000 requests on 1 seconds for example. Will he push requests on a sort of queue and execute one at a time ?
No. Calling a method on a service is just like any other method call. There is no invisible queue and there is also no reason why that would be necessary, as long as the methods in the service are thread-safe.
What is the best practice for Service declaration and why ?
When you use Spring, use Spring's dependency injection and never instantiate service classes using new in your code.
Spring Controller uses IOC mechanism like where Singleton objects are created, like in example you described #Service,
Application Server manages requests client, It uses thread pooling to handle request and generated or use same thread for request or response,
Spring applications are it self uses container mechanism where objects are created using #Service and #Autowired annotations.
When ever we are using #Service, this means we are telling spring
to create a object of that class and keep in Spring container, By
default its Singleton. Wherever we are using #Autowired then spring
handover that object to the Service/caller.
Whenever we are calling MyService service = new MySerivce()
java
creates new object of MyService every time. If that service called
1000 times then MyService object will get created 1000 times, and Spring
has no control on this.
Best Practice is :
Use Spring #Service annotation to create object and use annotation #Autowired to get that class object.
Handling 1000 Requests
Spring will not create 1000 new service object, it will use same service object (which is autowired) if object scope is Singleton which is default scope
but incase of Prototype, it is same as creating a object with new keyword.
SO in this case it will create 1000 objects.
For handling huge requests we need to make thread safe, pooling separately, in this case Spring will use its container pooling which is not very efficient.
I'm wondering if there is possibility to recreate a bean which was already created in java configuration on web app startup.
What I want to do is to reconfigure bean settings.
For example I create new bean with path to database:
#Bean
public TestBean getTestBean() {
TestBean tb = new TestBean("some_path_taken_from_external_point");
return tb;
}
During runtime I want to change the path. Let's assume that this bean doesn't have the setter method for database path.
I will have some kind of event and a listener for this event. Listener should reinitialize TestBean with new path.
Is this possible?
I was thinking of some kind of wrapper. In such case I would have class TestBeanWrapper which will have method get() which will return TestBean instance and recreate(String path) which will create new object with given path.
I'm not sure exactly if such wrapper would work for me, as the TestBean is a class from external library, and I'm not sure if it's not injected somewhere (but probably it's not injected).
More possible is that the other beans may rely on TestBean, so they also must be reinitialized (in case if they won't have setters for my TestBean).
Is this even possible in Spring (4.1) ? What is the best approach for such cases?
So I'm still unsure why you would want to change the path but I have 2 suggestions:
1. Look at setting the scope on the Bean.
By setting the scope on the bean, you can regenerate the bean based on context. Look at Bean Scopes for more information.
2. Look at maybe using a controller or a service.
Controllers and services allow getters and setters which may give you more control.
I created a bean instance with
Type instance = new Type();
and autowired it using
ctx.getAutowireCapableBeanFactory().autowireBean(instance);
The beans run method is executed by a ThreadPoolTaskExecuter and is annotated with the
#Transactional annotation which has no effect in this case. Since lazy loading problems occur. I need a transaction here.
How can I create a transactional proxy and wrap my instance?
Is there a way other than using transaction-manager manually?
You should get the correct proxy if you apply BeanPostProcessors from the context:
instance = ctx.getAutowireCapableBeanFactory().applyBeanPostProcessorsAfterInitialization(instance);
You can certainly create a PlatformTransactionManager subclass manually and use its methods to create and commit or rollback transactions.
If you want to proxy an object, the class you probably want is org.springframework.transaction.interceptor.TransactionProxyFactoryBean. Setup an instance of that and call getObject() to get your proxied class.
I'm pretty new to the Springframework (as you will guess) and ran into a situation, where help is desperatly needed.
I do hava a J2EE application here, running on tomcat with lots of old code. Anyway, we decided to use the Spring framework for certain tasks. For example we want to store a security object (containing the username and other authentication related properties) as a session scoped bean.
As there is plenty of old code calling the constructor of this "security object" my question is as following:
Will that object be obtained from the session (in any magic way spring is capable of) or will the constructor call generate a completely new object?
I've read something about "autowire mechanism"... would that help me any further?
Thanks for your answers and time!
If you use the new operator, then you are constructed the object yourself and the constructor is called. Spring is not involved when creating an object via new.
If your code creates an instance of the security object by calling the constructor of the class i.e. by calling new Security(), it will get a new instance everytime.
Declare a bean for your security object in your spring applicationContext.xml file. To make the security object session scoped, you'll need to declare its scope as session and make it a proxy:
<bean id="securityObject" class="com.xyz.Security" scope="session">
<aop:scoped-proxy /> <!-- important -->
</bean>
Now, instead of calling new Security(), the client will get the Security object from Spring application context (see line 1):
void someMethod() {
//...
Security securityObject = applicationContext.getBean("securityObject"); // 1
securityObject.doSomething(); // 2
//...
}
Spring will take care of creating instances of Security for each session. The object returned by the call at line 1 is not an actual Security object but instead it is a proxy object. When securityObject.doSomething() is called on line 2, the proxy object will look up the actual object created for that session and delegate the call to it. This will be managed by Spring.
Note that to get the bean at line 2, you will first need a handle to the ApplicationContext object. How you will get that object will depend on where the calling code is. Edit: An easy way to get it uniformly is by implementing the ApplicationContextAware interface.
Note: Instead of getting the bean from application context, you can get it wired by Spring, but that will require you to declare beans for all the clients that need the security object. Since you are modifying an existing application, I think the above approach is better.