简体   繁体   中英

Pass objects between stateless session beans

I have several stateless and singleton beans.

@Stateful
@Local(IMyService.class)
@LocalBean
public class MyService implements IMyService {

    private @EJB Singleton1 singleton1;
    private @EJB Singleton2 singleton2;

    public void doSomeStuff() {
        // construct shared object
        singleton1.doOtherStuff();
        singleton2.doOtherStuff();
    }
}

@Singleton
@LocalBean
public class Singleton1 extends MySingleton {
    @Override
    public void doOtherStuff() {
        // use shared object
    }
}

@Singleton
@LocalBean
public class Singleton2 extends MySingleton {
    @Override
    public void doOtherStuff() {
        // use shared object
    }
}

public abstract class MySingleton {
    public abstract void doOtherStuff();
}

Now I want to have an object shared between all those beans without having to pass it as a parameter.

I could have used stateful session beans, but injeting stateful beans in stateless beans will not work.

I'm not passing it as a parameter because I don't want to keep passing that parameter into methods while it's only needed in few situations.

Is there a mean to inject an object in the client session so that I can read it wherever I am ?

You can use ContextHolder pattern along with ThreadLocal and Interceptor.

ThreadLocal — This class allows for variables to be stored at the thread scope. I have no intention of getting into the pros and cons of using ThreadLocal. I will simply say it is very powerful and must be used very carefully.

EJB Interceptor — Used to intercept calls to business methods and lifecycle events of bean instances.

Now let we want to have an user object shared between all those beans without having to pass it as a parameter.

So our AuditContextHolder would be:

public class AuditContextHolder {
    private static final ThreadLocal<String> AUDIT_CONTEXT = new ThreadLocal<>();

    private AuditContextHolder() {
    }

    public static void put(String  auditUser) {
        AUDIT_CONTEXT.set(auditUser);
    }

    public static String get() {
        return AUDIT_CONTEXT.get();
    }

    public static void cleanup() {
        AUDIT_CONTEXT.remove();
    }
} 

And the Audit Interceptor would be this:

public class AuditInterceptor {

    @Resource
    private SessionContext sessionContext;

    @AroundInvoke
    public Object inject(InvocationContext ctx) throws Exception {
        String userName = sessionContext.getCallerPrincipal().toString();
        try {
            AuditContextHolder.put(userName);
            return ctx.proceed();
        } finally {
            // very important
            AuditContextHolder.cleanup();
        }
    }
}

Now you can use @Interceptors(AuditInterceptor.class) in your stateless session bean which is first in call chain. And everywhere inside the call chain you can get the audit user by calling AuditContextHolder.get()

References:

  1. http://www.adam-bien.com/roller/abien/entry/how_to_pass_context_with
  2. https://www.captechconsulting.com/blogs/a-persistence-pattern-using-threadlocal-and-ejb-interceptors

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM