Accesing Spring context from Hazelcast executeOnKeyOwner - java

I have a MultiMap in Hazelcast with a List<SomeObject> for each String key and want to persist each list with something like
IExecutorService executorService = hzInstance.getExecutorService("commonExec");
//...
executorService.executeOnKeyOwner(new PersistTask(key), key);
but the PersistTask object need another object defined in the Spring context. If I understand correctly, the instance of PersistTask is created, then serialized and sent to the key owner and the executed there. How do I reference the local Spring context? I think I could try to access it statically but I feel filthy for doing that. Is there a better way? For the record, I'm using Hazelcast 3.5.3 and Spring 4.2.3. Thanks in advance.

Seems that Hazelcast provide some kind of dependency injector. Your object (in my case, PersistTask) must implement HazelcastInstanceAware and it will be injected the local Hazelcast instance after deserialization. You can add objects in a user context that can be retrieved from the Hazelcast instance. The Hazlcast blog has a nice example.

There is a better and more object-oriented solution: you can add the annotation #SpringAware to your class (in my case PersistTask) and it will be initialized using the Spring context after deserialization. All the Spring annotations and interfaces (#Autowired and InitializingBean for example) will be processed and the dependencies will be injected. For this to work, you must define a ManagedContext in the Hazelcast instance. The SpringManagedContext is what you need. This can be specified in the XML config like this:
<hz:hazelcast id="hzexample">
<hz:config>
<hz:spring-aware /> <!-- this line here !!! -->
<hz:instance-name>hzexample</hz:instance-name>
...
The example in the official blog is this but it is formatted badly.

Related

How to set up custom behavior of spring data on a CDI environment

So, I have an application running on WildFly10, which uses JSF, Spring (DI), JPA, Spring Data;
Right now we're trying to move it to CDI and remove Spring(DI). For now we'll keep Spring Data.
So, I set up CDI and made an EntityManager producer.
#Produces
#Dependent
#PersistenceContext
public EntityManager entityManager;
So, I'm able to inject repositories with CDI and all.
However on my original environment we had a custom repository factory,that was defined in my SpringConfiguration like this:
#EnableJpaRepositories(basePackages = {"com.foo.repository" }, repositoryFactoryBeanClass=CustomJpaRepositoryFactoryBean.class)
So, the question is, how can I define this repositoryFactoryBeanClass=CustomJpaRepositoryFactoryBean.class on a CDI environment?
The current implementation doesn't allow the configuration of the JpaRepositoryFactoryBean as one can see from the code where it gets instantiated.
So I guess you have the following options:
reimplement the instantiation process.
open a feature request.
do 2. and 1. in a reusable way and submit the result as a PR for the issue.
When trying to solve this problem I found that the custom impl was not being picked up. The solution suggested in this question helped me however: https://stackoverflow.com/a/38541669/188624
Basically is uses Java8 default interface method to provide the additional functionality. I had to use the "CDI.current().select" method to get hold of the entity manager though as property injection of course won't work.
I tested with Spring Data JPA 2.0.0

Unable to deserialize Spring Session Scoped bean

I have the following session scoped bean:
#ManagedBean
#Component
#Scope(proxyMode= ScopedProxyMode.TARGET_CLASS, value="session")
public class SessionData implements Serializable {}
and I store tomcat sessions in a database. The problem is that, when the application tries to deserialize a stored session, I receive the following error:
org.apache.catalina.session.PersistentManagerBase.swapIn Error deserializing Session EE913D2ACAD49EB55EDA657A54DFA2CB: {1}
java.lang.ClassNotFoundException: de.myproject.SessionData$$EnhancerBySpringCGLIB$$768b59b9
It seems that it serialized actually the whole Spring context, and obviously there is no such class de.myproject.SessionData$$EnhancerBySpringCGLIB$$768b59b9 after server restarts, so I receive the aforementioned exception.
Is there a way to avoid this, so that the session-scoped bean is serialized properly?
UPDATE: There is an issue regards this which marked as resolved without comments, however I still face it.
Please have a try:
using: import org.springframework.test.util.AopTestUtils;
Serializable readyToSerialize = AopTestUtils.getUltimateTargetObject(yourInstance);
before serialize it.
Note: this code is usefull to understund the problem, if this work, you have to analyze the project architecture and dependecies, to better accomplish for production code. First of all, why you need to serialize a ScopedProxyMode.TARGET_CLASS
Having a bean with a scope session doesn't mean that the bean is serializable and that it can be stored in a session.
As you can guess from the name of the class, a proxy class is generated at runtime with a different name at each startup. This explains why a problem occurs at deserialization.
I guess you try to add this SessionData as an attribute of the web session. You should not. Store your POJO data in the web session without using beans.
If you use the bean to inject database connections or similar objects, forget it. You can just use session scope beans for particular contexts which don't feet your requirements I guess.
i don't know well the your task, but in my opinion a data object like this should not be a spring bean because spring bean should be business logic bean, controller bean and so on and not session dto.
for this reason i consider thag you should try to think why you want store the data of your spring bean, and try to decopled the data that you want in http session, #sessionattribute of springmvc,from the business logic bean that shoud nor be session aware.
i hooe that this can help you to change your implementation stategy in order to find the solution of your problem

Can I inject dependencies into objects not created by the DI framework

How can I inject dependencies into objects that weren't created by a DI framework?
I am running an application on Google App Engine using Objectify, so POJOs are created by Objectify when data is fetched from the datastore. Personally i like having convenience methods to get related objects, like car.getOwner().getName() The car object is created by Objectify. The code of getOwner() owner would be something like
public Person getOwner(){
return PersonService.getById(this.ownerId);
}
I could improve it with a ServiceLocator
public Person getOwner(){
return ServiceLocator.getService(PersonService.class).getById(this.ownerId);
}
But how would I do this with DI?
I looked at Guice, but i can only think of putting the Injector in a singleton and access it from the getOwner method.
Is my thinking flawed?
If you are using Objectify4 you can subclass ObjectifyFactory and override the construct() method. This will allow you to inject your entity classes.
You can see an example here: https://github.com/stickfigure/motomapia/blob/master/java/com/motomapia/OfyFactory.java
The only solution I can think of is load time weaving, I quote:
The context:load-time-weaver registers AspectJ's Load-time Weaver to
the current classloader. So, not only Spring beans will be targeted,
but any class loaded in the classloader that match the defined
pointcuts.
But I think that will conflict with the GAE restrictions but I haven't tried this in GAE yet.

Wicket #SpringBean doesn't create serializable proxy

#SpringBean
PDLocalizerLogic loc;
When using above I receive java.io.NotSerializableException. This is because loc is not serializable, but this shouldn't be problem because spring beans are a serializable proxies.
I'm using wicket-spring library, and as injector SpringComponentInjector, where wrapInProxies is by default set to true, so I think that proxies should be created, but they aren't.
On the page https://cwiki.apache.org/WICKET/spring.html#Spring-AnnotationbasedApproach is written:
Using annotation-based approach, you
should not worry about
serialization/deserialization of the
injected dependencies as this is
handled automatically, the
dependencies are represented by
serializable proxies
What am I doing wrong?
Do you know how the bean is being injected?
Through component initialization (i.e. a Component and being filled in by the SpringComponentInjector)
Some other object using InjectorHolder.getInjector().inject(this)?
Injected directly by spring (i.e. this is a spring bean where the property is being set by Spring configuration)
Cases 1 and 2 would use wicket-spring integration and would wrap the bean with a wicket proxy which is serializable.
Case 3 would only provide you whatever spring passes to you without wrapping.
First, make sure your bean is really proxied. By default spring does not create proxies.
Second, check your proxying strategy - whether it is proxy-target-class="true" or not. If it is false, (afaik) a reference to your object is stored in the invocation handler of the JDK proxy, and is attempted to be serialized.
So you'll need to make your class Serializable as well, if you need it to be.
Can you double check that the instantiation listener is added in your application class:
addComponentInstantiationListener(new SpringComponentInjector(this));
Also, this only works for fields in Wicket components, not arbitrary classes.
See also wicket #SpringBean can not create bean

How to ensure that methods called from same thread use the same DB session

In our system we have multi-threaded processing engine. During processing each thread calls methods to retrieve data from the database. We determined that performance is greatly improved if methods called from the same thread use the same DB session (sessions are coming from the pool of course).
Is there any standard way in Spring to ensure such thing or we have to come up with our own custom solution?
UPDATE: Forgot to mention that same methods can be called in different context where they should use a standard way of getting the session from the pool
I did not see Spring anywhere in your question. So I assume you want a simple utility to do this.
class SessionUtil {
private ThreadLocal currentSession;
public Session getCurrentSession() {
if(currentSession.get() == null) {
Session s = //create new session
currentSession.set(s);
}
return (Session)currentSession.get();
}
}
The Thread local will ensure that within the same thread it is always the same session. If you are using Spring then the classes/utilities mentioned above (in other responses) should be perfect.
Spring has a class called TransactionSynchronizationManager. It stores the current Session in a ThreadLocal. The TransactionSynchronizationManager is not recommended for use by the developer, but you can try using it.
Session session = ((SessionHolder)
TransactionSynchronizationManager.getResource(sessionFactory)).getSession();
(if you are using EntityManager, simply replace "Session" with "EntityManager").
You can have the sessionFactory injected in your bean - it is per-application.
Take a look at this discussion.
Other options, which I think are preferable to manual thread-handling are:
Thread pooling
Spring batch
Spring-JMS integration
Spring 3.0 has a concept of thread-scoped beans (hovewer, this scope is not registered by default, see docs): 3.5 Bean scopes, 3.5.5.2 Using a custom scope
EDIT:
I say about this:
Thread-scoped beans As of Spring 3.0,
a thread scope is available, but is
not registered by default. For more
information, see the documentation for
SimpleThreadScope. For
instructions on how to register this
or any other custom scope, see
Section 3.5.5.2, “Using a custom
scope”.
Spring coordinates database sessions, connections and threads through it's Transaction Framework (actually, using its TransactionSynchronizationManager - see description here - but you really don't want to mess with that directly, it's fearsome). If you need to coordinate your threads, then this is by far the simplest way of doing it.
How you choose to use the framework, however, is up top you.

Categories

Resources