JSF 2 Spring XRebel Huge session - java

I recently installed the XRebel plugin, which allows you to see current session size.
I discovered, that the session instantly gets to 10 mb on first page load(initialization of the auth session bean.).
To my setup:
I am using JSF 2.2, Spring 4 and Hibernate 4.
DAO Layer > Service Layer > Managed Bean
DAO Layer
#Named
#Singleton
#Repository
public class UserDao extends BaseDao<User>
{
...
}
Service Layer
#Service
#Named
#Singleton
public class UserService extends BaseService<User>
{
#Autowired
private UserDao dao;
...
}
My auth session bean, that gets loaded on first page load
#Named
#Component
#Scope("session")
public class Auth implements Serializable
{
#Autowired
private UserService userService;
...
}
In my applicationContext.xml I am using
<context:component-scan base-package="com.mypackage" />
This is a general issue I have when I autowire service beans in my session beans.
The Userservice only contains methods to retreive, save and delete user objects, there is no ArrayList containing users or anything else.
I have two #Autowired Services in my auth bean - UserService and SessionService.
If I commment out UserService, SessionService will reach the same size. If I comment out both there is a "DestructionCallbackBindingListener" from "org.springframework.web.context.request.ServletRequestAttribute..." that reaches 8mb instantly.
What am I doing wrong? How do I decrease the session size ?
I gladly accept any help.
Here is an image of XRebel showing that the userService takes about 8mb size in session. http://i.stack.imgur.com/TBXx3.png
Looking at XRebel, it seems that the beanFactory is saved in the user session.

I posted in the official forums regarding XRebel. This is the answer I received.
Indeed, the beanFactory is reachable from the session, through the
CGLIB proxy. We may need to improve to how we recognize objects that
are shared or should not be considered part of the session.
We try to show how much memory each session takes, but Spring
beanFactories are of course shared between sessions usually.
Often the fact that we filter out transient fields from the session
is enough, but we’ll take a look at the CGLIB/Spring proxies to see
how we can filter them out by a general rule or maybe we can just add
specific Spring classes to an ignore list.
In short: The beanfactory can be Ignored when looking at session size, optionally, if possible mark the autowired services transient.
Indeed you can ignore it mentally for now or if it’s possible then
yes, making the variables transient would exclude them.

Related

best practices of using bean scopes in spring mvc application

I have seen it written at many places that DAO and Service classes of a spring application should be singleton scoped.
In my application I have the following service class
#Service
public class CustomerServiceImpl implements CustomerService {
#Autowired
private CustomerDAO customerDAO;
.......
parameterised methods only....
}
and a DAO class
#Repository
public class CustomerDAOImpl implements CustomerDAO {
#Autowired
private SessionFactory sessionFactory;
...............
parameterised methods only....
}
Since I haven't defined any scope, the default scope is singleton.So both the CustomerService and CustomerDAO will be instantiated only once per the container.Also the DAO class will be autowired to the Service class only once at the beginning.Since it is going to be a heavy request web application, that means (OR does that mean ?) hundreds of threads are going to use the same instances of both the classes.
Then how thread safety is guaranteed in this case ?
And what about the scope of hibernate sessionfactory bean defined in the xml ?
I am very much confused about the bean scopes and thread safety in a spring mvc application. Springsource documentation doesn't clearly explain these for a web application.
Could anyone please explain me the best practises of using bean scopes(for DAO, Service, Controller and other beans) for a heavy request web application ?
Any link which explains these woulb be grateful for me.
Thanks for your suggestions in advance.
As long as your service and DAO singletons do not hold state (don't hold instance variables - other beans excepted - manipulated inside methods), there is no problem regarding thread safety. Regarding session factory, the default hibernate session scope in spring web-app is based on the "one hibernate session per request" pattern, which means that you will have one session for each http request (thread) and so no reason to worry about concurrency neither.

Spring store object in session

I would like to implement a shopping cart with Spring, so I need to save an object Cart ( which has attributes like products, paymentType and deliveryType ) in session. I've tried to create it with bean and attribute "scope" set to "session", but it just doesn't work, should I use some additional annotations in my controller or Cart class? Any example usage would be really helpful :-) Thanks in advance.
#Component
#Scope("session")
public class Cart { .. }
and then
#Inject
private Cart cart;
should work, if it is declared in the web context (dispatcher-servlet.xml). An alternative option is to use the raw session and put your cart object there:
#RequestMapping(..)
public String someControllerMethod(HttpSession session) {
session.setAttribute(Constants.CART, new Cart());
...
Cart cart = (Cart) session.getAttribute(Constants.CART);
}
If you are injecting the shopping cart directly into your controller, the issue is likely happening because your controller is singleton scoped (by default), which is wider scope than the bean you're injecting. This excellent article gives an overview of four approaches to exactly what you're trying to do: http://richardchesterwood.blogspot.co.uk/2011/03/using-sessions-in-spring-mvc-including.html.
Here's a quick summary of solutions:
Scope the controller to session scope (use #scope("session") on controller level) and just have a shopping cart instance in the controller.
Scope the controller to request and have session-scoped shopping cart injected.
Just use the session directly - kind of messy, IMO.
Use Spring's annotation <aop:scoped-proxy/>.
All of the methods have their pros and cons. I usually go with option 2 or 4. Option 4 is actually pretty simple and is the only approach I have seen documented by Spring.
You just need to add Scope annotation as below with session and proxy mode
#Component
#Scope(value="session", proxyMode=ScopedProxyMode.TARGET_CLASS)
public class ShoppingCart implements Serializable{
}
Where ever you need to use shopping cart object, you can autowire it
#Service
public class ShoppingCartServiceImpl implements ShoppingCartService {
Logger logger = LoggerFactory.getLogger(ShoppingCartServiceImpl.class);
#Autowired
ShoppingCart shoppingCart;
}
Disclosure: I have developed a sample project, which uses spring MVC, angularJS and bootstrap that demonstrate Spring Session scope -
https://github.com/dpaani/springmvc-shoppingcart-sample
try to autowired HttpSession and spring will injects in a proxy to the HttpSession
#Autowired
private HttpSession httpSession;

Spring - "late binding" autowired beans

Let's say I have the following dependencies:
#Configuration
public class MyCfg {
// ...
#Bean
public Session session() {
return sessionFactory().getCurrentSession();
}
}
#Repository
#Transactional
public class MyRepo {
#Autowired
private Session session;
}
sessionFactory() is set up properly. If I inject SessionFactory instead of Session, it works just fine. However, if try and inject Session, it dies with an exception on container bootstrap because there is no session bound to thread.
Since the repository is #Transactional, I know that at run time there will be a session. How can I make it work, so that it injects AOP-initialized Session at run time, but does not try and resolve it when the repo is instantiated?
I would take a look at this bit of Spring documentation regarding bean scopes. Near the bottom they show how to use the #Scope annotation, which you will want to apply to your session() method in MyCfg. It sounds like you would want to use the 'request' value, which will create a new instance of this bean for each HTTP request coming in.
I will also suggest taking a look at the <aop:scoped-proxy/> element for configuration. It is mentioned a couple times in the documentation, and may be useful for what you are trying to do.
This approach will get you into a lot of trouble. Instead of injecting a Session, which you now automatically scopes as a singleton, you should inject the SessionFactory instead. Instances of Session acquired within a #Transactional annotated method will adhere to those transaction rules, eg:
#Transactional(readonly=true)
public List<Person> getPersons() {
Session session = sessionFactory.getCurrentSession();
//find those darn people.
}
#Autowired
private SessionFactory sessionFactory;

Spring UserDetailsService is not Serializable session attribute in google-apps-engine

Here we have a Spring based webapp in google apps engine.
I've created a UserDetailService class to load the UserDetails from the GAE data store (assuming this is the best approach).
#Service("springUserDetailsService")
public class SpringUserDetailsService implements UserDetailsService {
#Resource(name="userDao")
private IUserDao userDao;
//...
But GAE throws the following exception (apparently) when it tries to persist the session to the data store.
java.lang.RuntimeException: java.io.NotSerializableException: com.prepayproxy.servicelayer.SpringUserDetailsService
at com.google.apphosting.runtime.jetty.SessionManager.serialize(SessionManager.java:387)
at com.google.apphosting.runtime.jetty.SessionManager.createEntityForSession(SessionManager.java:364)
I first thought to Serialize the SprintUserDetailsService object, but it has a reference to my UserDao, which in turn has references to data source objects, at about that point I freaked out and decided to see if there's a better approach.
On your second point, I am only assuming that spring security is storing a reference to the UserDetailsService in the session, which is how it gets tied up with the GAE serialization of the session. All beyond my control as far as I see unless I missed something.
There's no reason for SpringSecurity to put a reference to your application's UserDetailsStore into the session. A UserDetailsStore is not conceptually session scoped.
If the session manager is trying to serialize a UserDetailsService, it is probably a result of a reference to the UserDetailsService in some other session scoped object.
Two options:
don't worry about the DataSource - spring, since version 3, serves a proxy which, when deserialized, gets a fresh data source, rather than the original (which is not relevant)
don't put your service in the session. Perhaps it is referenced by something that is in session scope, so make it volatile there.
See also this question

Spring session-scoped beans (controllers) and references to services, in terms of serialization

a standard case - you have a controller (#Controller) with #Scope("session").
classes put in the session usually are expected to implement Serializable so that they can be stored physically in case the server is restarted, for example
If the controller implements Serializable, this means all services (other spring beans) it is referring will also be serialized. They are often proxies, with references to transaction mangers, entity manager factories, etc.
It is not unlikely that some service, or even controller, hold a reference to the ApplicationContext, by implementing ApplicationContextAware, so this can effectively mean that the whole context is serialized. And given that it holds many connections - i.e. things that are not serializable by idea, it will be restored in corrupt state.
So far I've mostly ignored these issues. Recently I thought of declaring all my spring dependencies transient and getting them back in readResolve() by the static utility classes WebApplicationContextUtils and such that hold the request/ServletContext in a ThreadLocal. This is tedious, but it guarantees that, when the object is deserialized, its dependencies will be "up to date" with the current application context.
Is there any accepted practice for this, or any guidelines for serializing parts of the spring context.
Note that in JSF, managed beans (~controllers) are stateful (unlike action-based web frameworks). So perhaps my question stands more for JSF, than for spring-mvc.
In this presentation (around 1:14) the speaker says that this issue is resolved in spring 3.0 by providing a proxy of non-serializable beans, which obtains an instance from the current application context (on deserialization)
It appears that bounty didn't attract a single answer, so I'll document my limited understanding:
#Configuration
public class SpringConfig {
#Bean
#Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
MyService myService() {
return new MyService();
}
#Bean
#Scope("request")
public IndexBean indexBean() {
return new IndexBean();
}
#Bean
#Scope("request")
public DetailBean detailBean() {
return new DetailBean();
}
}
public class IndexBean implements Serializable {
#Inject MyService myService;
public void doSomething() {
myService.sayHello();
}
}
public class MyService {
public void sayHello() {
System.out.println("Hello World!");
}
}
Spring will then not inject the naked MyService into IndexBean, but a serializable proxy to it. (I tested that, and it worked).
However, the spring documentation writes:
You do not need to use the <aop:scoped-proxy/> in conjunction with beans that are scoped as singletons or prototypes. If you try to create a scoped proxy for a singleton bean, the BeanCreationException is raised.
At least when using java based configuration, the bean and its proxy can be instantiated just fine, i.e. no Exception is thrown. However, it looks like using scoped proxies to achieve serializability is not the intended use of such proxies. As such I fear Spring might fix that "bug" and prevent the creation of scoped proxies through Java based configuration, too.
Also, there is a limitation: The class name of the proxy is different after restart of the web application (because the class name of the proxy is based on the hashcode of the advice used to construct it, which in turn depends on the hashCode of an interceptor's class object. Class.hashCode does not override Object.hashCode, which is not stable across restarts). Therefore the serialized sessions can not be used by other VMs or across restarts.
I would expect to scope controllers as 'singleton', i.e. once per application, rather than in the session.
Session-scoping is typically used more for storing per-user information or per-user features.
Normally I just store the 'user' object in the session, and maybe some beans used for authentication or such. That's it.
Take a look at the spring docs for configuring some user data in session scope, using an aop proxy:
http://static.springsource.org/spring/docs/2.5.x/reference/beans.html#beans-factory-scopes-other-injection
Hope that helps
I recently combined JSF with Spring. I use RichFaces and the #KeepAlive feature, which serializes the JSF bean backing the page. There are two ways I have gotten this to work.
1) Use #Component("session") on the JSF backing bean
2) Get the bean from ELContext when ever you need it, something like this:
#SuppressWarnings("unchecked")
public static <T> T getBean(String beanName) {
return (T) FacesContext.getCurrentInstance().getApplication().getELResolver().getValue(FacesContext.getCurrentInstance().getELContext(), null, beanName);
}
After trying all the different alternatives suggested all I had to do was add aop:scoped-proxy to my bean definition and it started working.
<bean id="securityService"
class="xxx.customer.engagement.service.impl.SecurityContextServiceImpl">
<aop:scoped-proxy/>
<property name="identityService" ref="identityService" />
</bean>
securityService is injected into my managedbean which is view scoped. This seems to work fine. According to spring documentation this is supposed to throw a BeanCreationException since securityService is a singleton. However this does not seems to happen and it works fine. Not sure whether this is a bug or what the side effects would be.
Serialization of Dynamic-Proxies works well, even between different JVMs, eg. as used for Session-Replication.
#Configuration public class SpringConfig {
#Bean
#Scope(proxyMode = ScopedProxyMode.INTERFACES)
MyService myService() {
return new MyService();
}
.....
You just have to set the id of the ApplicationContext before the context is refreshed (see: org.springframework.beans.factory.support.DefaultListableBeanFactory.setSerializationId(String))
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
// all other initialisation part ...
// before! refresh
ctx.setId("portal-lasg-appCtx-id");
// now refresh ..
ctx.refresh();
ctx.start();
Works fine on Spring-Version: 4.1.2.RELEASE

Categories

Resources