Why beans (with request scope) are not initialized in every request in controllers? - spring

My ActionResponse code is :
#Component
#Scope(value = "request",proxyMode = ScopedProxyMode.TARGET_CLASS)
public class ActionResponse{
public int a;
//body
}
My Controller:
#Controller
#RequestMapping(value="/ajax/discussion")
public class DiscussionController extends AbstractController {
#Autowired
private ActionResponse actionResponse;
public void setActionResponse(ActionResponse actionResponse) {
this.actionResponse = actionResponse;
}
#RequestMapping("/test")
public #ResponseBody String test(){
String response=this.actionResponse.a+"";
if(this.actionResponse.a==0)
this.actionResponse.a=10;
return response;
}
}
I start the project and then the first time I request /ajax/discussion/test it shows 0
but after that for other requests it shows 10
It has to show 0 in every request because of request scope for ActionResponse
The question is:
Why the bean(ActionResponse) is created once not in every request?!!!

CGLIB works on class level.
CGLIB proxy is still a singleton, so it inherits the fields from the base class. When you change its public properties you change the values of the singleton.
You should encapsulate your data changes in public getters and setters.

Was a little late - Just adding on to Boris Treukhov's answer(have +1'd it):
The reason is that since you have annotated ActionResponse with #Scope(proxyMode=..) Spring ends up creating a CGLIB subclass of this ActionResponse which internally handles the scope appropriately.
Now when you inject ActionResponse into the DiscussionController it is the CGLIB proxy that gets injected, and since you are setting the fields directly with going through the setter, it just modifies the fields of the proxy and not the underlying scoped proxied object. The fix is simply to make state changes via the getters and setters not through fields.

Related

Quarkus encapsulation behavior

I have this class:
#ApplicationScoped
public class BookService {
public boolean doorClosed;
public boolean isDoorClosed() {
return doorClosed;
}
}
And I have this test class:
#QuarkusTest
public class BookServiceTest {
#Inject BookService bookService;
#Test
public void testBookServiceDoor() throws InterruptedException {
bookService.doorClosed=true;
assertTrue(bookService.doorClosed);
assertTrue(bookService.isDoorClosed());
}
}
I am surprised that the last test assertion fails. The first passes but the last fails. It almost seems like that the getter/setters are using different variables than the one I am accessing directly.
I did the same test with Spring Boot and got the two assertions passing:
#Service
public class BookService {
public boolean doorClosed;
public boolean isDoorClosed() {
return doorClosed;
}
}
And the test:
#SpringBootTest
public class BookServiceTest {
#Autowired BookService bookService;
#Test
public void testBookServiceDoor() throws InterruptedException {
bookService.doorClosed=true;
assertTrue(bookService.doorClosed);
assertTrue(bookService.isDoorClosed());
}
}
Using the #ApplicationScoped annotation makes the class a normal scoped bean. This means that the container never injects an actual instance of the class; instead, you get a proxy that will lookup the correct instance on each method invocation.
This is most commonly useful for example with #RequestScoped beans, where you get a single proxy, which will dispatch method invocations to instances that belong to the "current request" (typically an HTTP request). However, there are good reasons why you might want this for application scoped beans as well (e.g. when you want lazy initialization).
The rule is: never access fields directly on normal scoped beans, only call methods.
If you want, you can make the class #Singleton. That is a pseudo scope, and you get no proxy, you get the actual instance that you can work with directly.

Spring #Cachable method within the same class (self-invocation, proxy issue) - What is the best way to solve it?

I'm trying to call a #Cacheable method from within the same class.
And it didn't work. Because of:
In proxy mode (the default), only external method calls coming in through the proxy are intercepted. This means that self-invocation (in effect, a method within the target object that calls another method of the target object) does not lead to actual caching at runtime even if the invoked method is marked with #Cacheable. Consider using the aspectj mode in this case. Also, the proxy must be fully initialized to provide the expected behavior, so you should not rely on this feature in your initialization code (that is, #PostConstruct).
It means, #Cachable(also #Transactional) works by proxy classes which is Spring AOP in. a internal call in the same class make call by 'this' instead of proxy classes.
To solve the problem, I should call a method by proxy or using AspectJ(another AOP).
So, I found 4 solutions.
What is your choice? and why others are not recommended?
Please, share your opinion!
using AspectJ (another AOP)
get the Bean from ApplicationContext and use it
#Service
public class UserService implements Service {
#Autowired
private ApplicationContext applicationContext;
private Service self;
#PostConstruct
private void init() {
self = applicationContext.getBean(UserService.class);
}
}
self-autowiring using #Resource //since Spring 4.3
#Component
#CacheConfig(cacheNames = "SphereClientFactoryCache")
public class CacheableSphereClientFactoryImpl implements SphereClientFactory {
/**
* 1. Self-autowired reference to proxified bean of this class.
*/
#Resource
private SphereClientFactory self;
#Override
#Cacheable(sync = true)
public SphereClient createSphereClient(#Nonnull TenantConfig tenantConfig) {
// 2. call cached method using self-bean
return self.createSphereClient(tenantConfig.getSphereClientConfig());
}
#Override
#Cacheable(sync = true)
public SphereClient createSphereClient(#Nonnull SphereClientConfig clientConfig) {
return CtpClientConfigurationUtils.createSphereClient(clientConfig);
}
}
make the Bean scope of the class as 'prototype' instead of 'singleton'
#Service
#Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
class AService {
private final AService _aService;
#Autowired
public AService(AService aService) {
_aService = aService;
}
#Cacheable("employeeData")
public List<EmployeeData> getEmployeeData(Date date){
..println("Cache is not being used");
...
}
public List<EmployeeEnrichedData> getEmployeeEnrichedData(Date date){
List<EmployeeData> employeeData = _aService.getEmployeeData(date);
...
}
}
I'm a newbie in spring :)
Actually, I choose the 4th solution, but I felt it isn't a good way. because I just need to call the caching method by proxy, and it make several beans to achieve it.
After reading articles, I think AspectJ is the best choice. It looks cool, Spring recommends it, and many people also recommend too.
But I don't understand how to AspectJ works (I will study) and I also don't know why others is not recommended.
references
Spring Cache #Cacheable - not working while calling from another method of the same bean
Spring cache #Cacheable method ignored when called from within the same class
https://spring.io/blog/2012/05/23/transactions-caching-and-aop-understanding-proxy-usage-in-spring
https://docs.spring.io/spring/docs/current/spring-framework-reference/integration.html#cache

Spring - Is it good to register request scoped bean at every request though code?

In Spring Web application, I have to use specific value from request object in another spring classes within application. Value is request specific value.
In the following example, is it good way to register value coming from Request Body every time and use #Autowired with #RequestScope annotation to use value in another spring(e.g. #Service) classes? Is it good to register RequestScopedType bean value for each request through BeanFactory?
#RestController
#RequestMapping("/")
public class VehicleServiceController {
#Autowired
private BeanFactory beanFactory;
#Autowired
private ServiceClass serviceClass;
#PostMapping(path = "/postDetails", consumes = MediaType.APPLICATION_JSON_VALUE)
public OutputPayload postDetails(
#RequestBody InputPayload inboundPayload) throws Exception {
beanFactory.getBean(RequestScopedType.class).setValue(inboundPayload.getType());
return serviceClass.methodToCall();
}
}
Will there be any impact on performance as load is very huge? Is there any another way to inject/get RequestBody object value(inboundPayload.getType())?
You don't have to do beanFactory.getBean(RequestScopedType.class). You can just simply autowire it #Autowired RequestScopedType requestScopedType.
Just don't forget to change the scope of the bean as Request.
#Component
#Scope(scopeName = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class RequestScopedType {
But this begs another question, why over complicate things, why can't you pass inboundPayload.getType() to the serviceClass.methodToCall(); ?
What is stopping you from using it this way return serviceClass.methodToCall(inboundPayload.getType());

Check the state validity of a Spring proxied bean without try-catch

I have a bean being created by a service with the following class:
#Configuration
public class AccessManager {
#Bean(name="access", destroyMethod="destroy")
#Scope(value="session", proxyMode=ScopedProxyMode.TARGET_CLASS)
#Autowired
public Access create(HttpServletRequest request) {
System.out.println(request.getRemoteAddr());
return new Access();
}
}
Everything works as expected, except that when the application is starting, this method is being called, probably because I have some other singleton beans that use the Access bean. At the start up there is no request bound to the Thread, and it's expected to get a java.lang.IllegalStateException when trying to access any property of the request parameter.
No problem. The question is, is it possible to check if the underlying HttpServletRequest of the proxy request is null before calling a property that raises the exception?
You probably want to take a look at RequestContextHolder#getRequestAttributes(). That will return null if you're not currently in a context where request scope could be used.
#Configuration
public class AccessManager {
#Bean(name="access", destroyMethod="destroy")
#Scope(value="session", proxyMode=ScopedProxyMode.TARGET_CLASS)
#Autowired
public Access create(HttpServletRequest request) {
if (RequestContextHolder.getRequestAttributes() != null) {
System.out.println(request.getRemoteAddr());
}
return new Access();
}
}
I think the issue here is with separation of concerns. Usually your service layer should not have any dependency on the servlet classes. This is very much a controller/UI concern.
Your service class should be provided with the properties which it needs to do its job. In this case a String. This service method should be called from a controller method which is injected with the servlet request.
Something like the following:
#Controller
public class MyController {
#Autowired
private AccessManager accessManager;
#RequestMapping
public void handleRequest(HttpServletRequest request) {
accessManager.create(request.getRemoteAddr());
}
}
and your service would then look like this:
#Service
public class AccessManager {
public Access create(String remoteAddress) {
return new Access();
}
}
To sum up, anything annotated as #Service shouldn't have access to the Request.

AspectJ autoproxy issues with Spring Controllers and Webflow Actions

I have two related issues regarding spring/AspectJ AOP. I have a typical logger aspect which logs exceptions thrown from any class in my application including services, daos, controllers and webflow actions...
#Aspect
public class AspectLogger {
#AfterThrowing(pointcut = "execution(* com.myapp..*.*(..))", throwing = "t")
public void logGustavoException(JoinPoint joinPoint, Throwable t) {
Log logger = LogFactory.getLog(joinPoint.getTarget().getClass());
logger.error(t.getMessage(), t);
}
}
In my application context I have an equally typical configuration...
<context:annotation-config />
<!-- AOP logging config -->
<aop:aspectj-autoproxy>
<aop:include name="aspectLogger" />
</aop:aspectj-autoproxy>
<bean id="aspectLogger" class="com.myapp.AspectLogger" />
This works fine for the most part, the issue I have is with the webflow actions and controllers which implement an interface.
1 - Controllers which implement an Interface...
One of our controllers implements an interface which defines one method, as well as defining several public methods which are used as #RequestMapping handlers...
#Controller
public class AmazingController implements OutstandingInterface {
// implements the method from OutstandingInterface
#Override
public Object doSomethingOutstanding(){
...
}
#RequestMapping(value="/amazingUrl.htm", method = RequestMethod.GET)
public String doSomethingAmazing(HttpSession session, ModelMap model) {
return "anAmazingViewName";
}
...
}
The issue here is that due to the fact that the controller implements an interface that doesn't define all its public methods (i.e. controller request mapping methods), a proxy is created for the controller which only proxies the 'doSomethingOutstanding' method from OutstandingInterface. As such, when a request comes in to /amazingUrl.htm, Spring does not route it to the appropriate request handler - it's as though the request mapping doesn't exist. I have solved this by defining an interface for the controller which extends OutstandingInterface and also defines the request handler methods required by the controller, but it seems odd/wrong to me to have to define an interface for a controller just so that the AspectJ stuff doesn't 'hide' the request handler...
#Controller
public interface IAmazingController extends OutstandingInterface{
#RequestMapping(value="/amazingUrl.htm", method = RequestMethod.GET)
public String doSomethingAmazing(HttpSession session, ModelMap model);
}
...
public class AmazingController implements IAmazingController {
#Override
public Object doSomethingOutstanding(){
...
}
#Override
#RequestMapping(value="/amazingUrl.htm", method = RequestMethod.GET)
public String doSomethingAmazing(HttpSession session, ModelMap model) {
return "anAmazingViewName";
}
...
}
2 - Webflow Actions
The second issue is very similar. After introducing the AspectJ configuration, none of my webflow Action classes were being autowired correctly - I kept getting 'cannot find bean of type FantasticAction' sort of errors. Again, I introduced interfaces for all of the Action classes and this solved the problem as it was the proxy that was being injected at runtime, not the actual action implementation class.
So finally... the question in both instances is - is there a way of getting around these AspectJ issues without having to define interfaces for every class I want to advise?
You should add CGLIB dependendy in your class path so you will not need to create interfaces for working with AOP
Take a look to the doc.

Resources