How to manage the scope and memory load heavy beans? - java

Looks like I have a huge issue which is making me quite confused on how to fix it.
I am using 4.0.3.RELEASE of Spring and created an MVC rest application. Most of the configuration is done via Java config as wrote a class WebMVCConfig which extends WebMvcConfigurerAdapter.
I have a spring bean that loads a text mining system which has some heavy lists. In a standalone application, I just load it once and everything I need to process some text I just call the process sentence method out of it. The constructor for that loads all lists once and after that it is just a matter of calling that function. The process function sometimes takes about 10 seconds, but sometimes it takes a few milliseconds to run all depends on the data.
Now, putting it on a Spring MVC application is interesting. If I set the scope to session scope for that bean: #Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS) it works just great, of course takes sometime to load on my rest application.
However, eventually it will run out of the memory as sessions are never killed right away.
If I do it on request it will be the same issue.
If I do it default application scope than I have an issue with concurrent usages of that bean. One user runs well, the other crashes.
I have no idea of what to do. Although session scope seems to be the correct answer to it as the state is preserved on each call. Not only the Bean is heavy but it can take 10 seconds sometimes to perform the analysis.
I have a Java Configuration class where I inject that bean into my Service Implementation class via #Inject annotation. Wonder if the correct would be #Autowire instead.
Basically I have my datamining Bean that is injected into my services bean via #Inject. I had assigned the 2 beans to be Session beans.
Wonder if I should assign the datamining Bean as session and the service bean as application and which method to use to wire that Datamining bean. Whether I use an #Autowire annotation or something else to avoid the problems I am having.
Also, what about ScopedProxyMode? Which one should be used on this case?
The situation, again, is a Heavy Bean which can have a slow processing time (10 seconds).
Thanks,

Related

SpringBoot Single Page Application Concurrency

I have copied a sample Spring Boot SPA. I want to understand, what happens if multiple people use the web page via the URL. Does Java create an instance of the web application per call? Memory resources are not shared, right, i.e. if there is a list object appended to, each user sees their own list?
The default scope for a spring-boot bean is a singleton. Assuming your bean is not managing state you should be fine with the default behavior:
https://docs.spring.io/spring/docs/3.0.0.M3/reference/html/ch04s04.html
4.4.1 The singleton scope
When a bean is a singleton, only one shared instance of the bean will be managed, and all requests for beans with
an id or ids matching that bean definition will result in that one
specific bean instance being returned by the Spring container.
To put it another way, when you define a bean definition and it is
scoped as a singleton, then the Spring IoC container will create
exactly one instance of the object defined by that bean definition.
This single instance will be stored in a cache of such singleton
beans, and all subsequent requests and references for that named bean
will result in the cached object being returned.
Now if you are using a bean that's stateful and want a new bean used per request, you can define the scope of that bean to be prototype:
4.4.2 The prototype scope
The non-singleton, prototype scope of bean deployment results in the creation of a new bean instance every time a
request for that specific bean is made (that is, it is injected into
another bean or it is requested via a programmatic getBean() method
call on the container). As a rule of thumb, you should use the
prototype scope for all beans that are stateful, while the singleton
scope should be used for stateless beans.
Spring resources like #Service and #Repository and #RestController are stateless singletons. Only a single instance is created to serve the application.
Your implementation of the list at scope level will determine whether or not it is shared. If you define the List in the Controller, as in your example, then every user will have access to the same list. You can use multiple browsers to see that the list is shared. Based on the example, this is fine, as getting "all" should really mean getting all.
If you wanted each user to have their own list, you would have to implement some sort of Session or back-end process to associate each individual user with their own list.
This isn't shared-nothing like PHP or Rails. Java is so slow starting up that firing up a new instance of the application for every request isn't an option.
Check out the spring-boot sample application source code, there's a main method on the SpringbootJQueryAjaxClientApplication class, like this:
public static void main(String[] args) {
SpringApplication.run(SpringBootJQueryAjaxClientApplication.class, args);
}
this is the main method like for any Java program, what happens here is it starts the self-hosted servlet container and installs the application into it, then waits for http requests.
It is one process, where every request is served by a thread, so memory is shared. Spring components like com.javasampleapproach.jqueryajax.controller.RestWebController (scoped as singleton by default) are instantiated once in the web application, and every request calls methods on the same instance.

why spring does not manages prototype bean once created

So regarding prototype scoped bean, I know spring just crate it do life cycle process before handover it to requested bean. and then if forgot it.And also logically I can understand that since it is prototype, it will be used by per request only (yes not http request.) But why not spring container just keep reference of prototype bean just to manage complete life cycle?
A "prototype" scope behaves pretty much just like any object POJO created with the "new" operator, except for the Spring prototype will have #Autowired beans connected up. The aren't singletons, or connected to sesssion or request scope, so they are just more similar to a regular POJO.

Weld: Inject dependency inside Thread J2EE

I'm currently going into a huge problem and any help would be highly appreciated.
First of all, the following is occuring in a J2EE environment and I know I shouldn't be managing a Thread myself, but unfortunately I can't change that nor use EJB. The environment is based on the Tomcat Web Container and Weld CDI manager.
My structure contains lots of RESTful services, Service layer and DAO layer implementations, and all of them are getting one another injected by using
#Inject and it works fine. The issue comes when I need to get my Service layer injected into my Run method and I get
WELD-001303 No active contexts for scope type javax.enterprise.context.RequestScoped.
I already have a method to return the desired bean with its contextual, as the following code describes:
BeanManager manager = (BeanManager) jndiContext.lookup("java:/comp/BeanManager");
Bean<T> bean = (Bean<T>) manager.getBeans(beanClass).iterator().next();
CreationalContext<?> ctx = manager.createCreationalContext(bean);
return (T) manager.getReference(bean, beanClass, ctx);
But even I use this method I get the error. So, is there any way in which I could inject my beans inside a Thread created and managed by me?
Thank you.
Sorry, but nope - this just won't work.
CDI, as it is, does not support context propagation across threads. It is bound to one thread only. Having it otherwise would present a severe overhead due to synchronization.
As a proof of my thread-bound claim above, look at Weld source code, where there is ThreadLocal<BeanStore> used as a storage for beans in given context. The class I refer to in the link is a predecessor to context implementing classes. Also note that this is not Weld-only "problem", any CDI impl out there work on the same basis.
You could activate given Context/Scope in a different thread but that means everything will be created anew and any state you had saved in your (for instance) #ApplicationScoped bean, will not propagate. Also, with some definitely not nice hacking, you might be able to access the bean store and make a copy to the other thread. That would give you a read-only access but I am not sure how to do that and if that's even worth the efforts.
Last but not least, CDI allows you to implements you own context or even supplement your version of built-in contexts. That way you would be able to provide a full-blown version of context working across threads, but there are so many challenged to it, that I am not sure it's doable/reasonable.

Spring 4 Dynamic Bean Creation

Maybe I'm not using the right terminology and that's why i can't find an answer, but I want to know how can I take information from a database to create beans that I can inject into the application?
Here's an example, rather than having this coded in a configuration file, I would like to possibly loop some values stored in a database and build these beans based on that:
#Bean
public CronTriggerFactoryBean cronTriggerFactoryBean() {
CronTriggerFactoryBean factory = new CronTriggerFactoryBean();
factory.setJobDetail(jobDetailFactoryBean().getObject());
factory.setStartDelay(3000);
factory.setCronExpression("0 0/2 * 1/1 * ? *");
return factory;
}
How can I build beans like this and have them become a part of the application?
There are probably multiple ways how to achieve that, but all of them are pretty complex with a lots of pitfalls. I would say that in your example you should not create triggers as separate beans but rather have a single service to manage your schedules (and leave it out of Spring).
The thing with Spring is, that it is not designed to act as a dynamic container (like OSGi for example). This means that for example #Autowired dependencies are initialized during context startup and stays the same till the application context is destroyed.
However it is possible to construct bean definitions on the fly during initialization. Best place would be BeanFactoryPostProcessor. But this would be called during context initialization. This means you will have no other beans available (like EntityManager, DataSource, ...).
Another possibility is to somehow take advantage of context hierarchy. You can create and destroy application contexts on-the-fly. However implementing that would require deeper knowledge of Spring's internals.
Question for others: not sure if it is possible to reference initialized beans from parent context during child context initialization.
After you load the necessary bean properties from Database , use BeanDefinitionBuilder. You can refer this link

Refreshing/replacing beans in the ApplicationContext. Possible or am I missing the point?

First off, I think I'm trying to use Spring incorrectly, but confirmation would be appreciated.
I am trying to reset a single bean in mid-application. My initial configuration works just fine.
My scenario
1 Insurance Claim bean (session
scope)
1 Claim details bean which is a
multiactionController
(getClaim&setClaim enabled, prototype
scope)
1 Claimant details bean which is a
multiactionController
(getClaim&setClaim enabled, prototype
scope)
1 Submit claim bean which is a
multiactionController
(getClaim&setClaim enabled, prototype
scope).
My application is more complex than this, but for the sake of providing a clear example I wont describe the whole thing.
The first two controllers are used to set various properties of the claim, validate etc.
The third writes a claim to the database. THEN I want it to reset the bean. However I can't just say claim=new Claim() in SubmitClaimController.OnSubmit() as the ApplicationContext keeps its reference to the old Claim.
I could just create a method Claim.clear(), but that feels like the wrong approach. However, I can't see anything like ApplicationContext.destroyBean(beanname) or ApplicationContext.createBean().
I do not want to refresh the entire ApplicationContext as I will have other beans I want to keep alive throughout the session.
Thanks in advance.
I don't think the Claim object should be Spring-managed. It's really not injected; sounds like it should be bound from the request sent into the controller and passed to the service for processing. If you put a Claim into session scope, you need to invalidate the session when the transaction is done or if the session times out.
By the way, I see you mention three controllers, but no service. You should have a service layer, and controllers should not deal with DAOs or persistence.
You can change the scope of a bean. Default is singleton which is sometimes not appropriate in web contexts. You can change it to be session scoped by adding for example
the attribute scope="session"
and the child <aop:scoped-proxy proxy-target-class="false"/>
to the bean definition.
I am working with 3.0M4, btw, but I would expect it to be in earlier versions, as well, as it's a very important functionality. Have a look at:
http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/ch03s05.html
Cheers!

Categories