Create only objects used in Java EE - java

Given the EJB below, will the container be intelligent enough to only create the object that is used?
#Stateless
public class MyBean {
#EJB
Clazz1 obj1;
#EJB
Clazz2 obj2;
public void run(int x) {
if (x == 1)
obj1.printCode();
else
obj2.printCode();
}
}

The container will have to resolve all dependencies of the bean (instantiate them first) before instantiating the bean itself.
Now what truly happens when you invoke a method might differ...
You are using purely EJB here, there isn't any speck of CDI in your code!
#EJB is an EJB annotation for dependency injection and #Stateless is an EJB annotation for a "scope".
If you were to use CDI and had Weld as its implementation (all EE servers apart from tomee) then you would get lazy instantiation for any normal scoped beans. That would mean that you in fact inject an "empty" proxy object and it will only be instantiated upon first access.
Now, what I mean by CDI injection - use #Inject instead of #EJB.
You can still have your bean #Stateless, CDI, if it's running in your app, then wraps it with it's own scope.
I also said that you need normal scoped beans - that means beans which use proxies.
Those are pretty much all CDI scopes except #Dependent. Therefore it's #RequestScoped, #SessionScoped, #ApplicationScoped. The dependencies of your bean would have to have those scopes to achieve lazy init.

Related

Circular dependencies between stateless session beans - good practice?

I just ran into a deployment error when deploying two stateless session beans each with dependency to the other and using #Inject.
#Stateless
class BeanA {
#Inject
BeanB b;
public void doSomething() {
b.doSomething();
}
}
#Stateless
class BeanB {
#Inject
BeanA a;
public void doSomeOtherThing() {
a.doSomeOtherThing();
}
}
When deploying this, I get this exception from Glassfish / weld:
org.jboss.weld.exceptions.DeploymentException: WELD-001443 Pseudo
scoped bean has circular dependencies.
Injecting the Beans with #EJB instead of #Inject, everything works fine. Now I have two questions.
First - what happens inside weld that this won't be allowed?
Second (probably more important) - is this bad practice on architectural side and if yes do you know any patterns to avoid it? From my current knowledge was that business driven services on the same layer are allowed to communicate with each other in any way they need.
As written in the spec
The container is not required to support circular chains of
dependencies where every bean participating in the chain has a
pseudo-scope.
Here, you didn't add scope annotation to your session beans so they have the default scope #Dependent. Dependent being a pseudo-scope, it's normal to have this error.
To solve this, add #ApplicationScoped to at least one of your bean. In fact it's a good practice to put your stateless session bean in application context, it prevents CDI to recreate its proxy around the existing EJB each time you inject it.
Regarding circularities, it's not a bad practice, but should be used only when needed since it can bring more complexity to understand your app, debug it and prevent these kind of errors.

JSF Named Bean, Eager application scoped (aka #ManagedBean(eager=true) )

Is there any way to initialize Named Bean annotaded by javax.inject.Named/javax.enterprise.context.ApplicationScoped like #ManagedBean(eager=true) from javax.faces package?
#Named
#ApplicationScoped
public Mail() { ... }
I want to load this class when application starts, not when webapplication refers to this bean.
ps. JSF 2.1
Bean Injected by Glassfish 3.1
You can create a CDI extension that has the #Observes AfterBeanDiscovery parameter on one of his methods. There you can instantiate the bean and thus initialize it when the container starts up.
CODI has made those things easier for you, see https://cwiki.apache.org/confluence/display/EXTCDI/Core+Usage#CoreUsage-Startup

Calling a CDI session scoped producer method from an EJB stateless session bean

I want to inject the current user using #Inject #Current User across all layers (i.e. web layer, EJB layer). In order to do this, I have the following CDI Producer method:
#Named
#SessionScoped
public class UserController {
#Resource SessionContext sessionContext;
#EJB UserDao userDao;
#Produces #Current
public User getCurrentUser() {
String username = sessionContext.getCallerPrincipal().getName();
User user = userDao.findByUsername(username);
}
}
#Qualifier
#Target({TYPE, METHOD, PARAMETER, FIELD})
#Retention(RUNTIME)
public #interface Current{}
Now, I want to inject the current user into an EJB stateless session bean as follows:
#Stateless
public class SomeBackendService {
#Inject #Current
private User user;
}
My question: Is the current user object always re-injected after the session changes, because the dependencies of a stateless session bean are normally injected once at creation time and the bean may be pooled and used across different sessions?
Although I haven't tried this exact situation, in CDI beans are normally not re-injected. Instead, a proxy is injected that is aware of its context.
Via this mechanism, it's possible to inject say a session scoped bean in an application scoped bean. Every user of the application scoped bean goes to the same bean and the same proxy, but the proxy will then dynamically resolve calls on it to a different bean for each user.
So even though the scope of #Stateless is basically 'application', it would be possible that the proxy that represents User in your `SomeBackendService' still delegates to the correct session scoped version.
p.s.
If with layers you actually mean modules as in web and EJB modules that are part of an EAR, it's going to be a little bit more complicated, as CDI doesn't always works as expected between modules (especially in JBoss AS). This is partly due to the ambiguity of what an 'application' and thus the application scope is within an EAR.
Yes, to each business method called the container will be re-injected all dependencies of your SLSB. Here is text that guarantees this in EJB 3.1 specification:
"If a session bean makes use of dependency injection, the container injects these references after the bean instance is created, and before any business methods are invoked on the bean instance." - Section 4.3.2
I had this doubt too and I posted a question explaining this situation
here
By design, your stateless session bean should not have a state "User", it's stateless by all means.
If you want your EJB to have states, then use #Stateful instead.

How to inject resources into EJB3 beans with Spring 2.5?

If I create an EJB3 bean (say a stateless session bean) in an application using Spring 2.5 for DI, how should I inject dependencies from Spring into the bean without coupling the bean to Spring?
I don't know if you consider applying an interceptor as coupling but that's to my knowledge the standard approach. From the Chapter 18. Enterprise Java Beans (EJB) integration of the documentation:
18.3.2. EJB 3 injection interceptor
For EJB 3 Session Beans and
Message-Driven Beans, Spring provides
a convenient interceptor that resolves
Spring 2.5's #Autowired annotation
in the EJB component class:
org.springframework.ejb.interceptor.SpringBeanAutowiringInterceptor.
This interceptor can be applied
through an
#Interceptors
annotation in the EJB component class,
or through an interceptor-binding XML
element in the EJB deployment
descriptor.
#Stateless
#Interceptors(SpringBeanAutowiringInterceptor.class)
public class MyFacadeEJB implements MyFacadeLocal {
// automatically injected with a matching Spring bean
#Autowired
private MyComponent myComp;
// for business method, delegate to POJO service impl.
public String myFacadeMethod(...) {
return myComp.myMethod(...);
}
...
}
SpringBeanAutowiringInterceptor by
default obtains target beans from a
ContextSingletonBeanFactoryLocator,
with the context defined in a bean
definition file named
beanRefContext.xml. By default, a
single context definition is expected,
which is obtained by type rather than
by name. However, if you need to
choose between multiple context
definitions, a specific locator key is
required. The locator key (i.e. the
name of the context definition in
beanRefContext.xml) can be
explicitly specified either through
overriding the
getBeanFactoryLocatorKey method in a
custom
SpringBeanAutowiringInterceptor
subclass.
The only other option I'm aware of (extending the EJB 2.x support classes) is much worse from a coupling point of view (and thus doesn't answer your question).
See also
Default Injecting Spring bean to EJB3 SLSB without #Autowired Annotation

EJB 3.1 #EJB Injection into POJO

With the new EJB 3.1 spec is it possible to inject an EJB into a pojo? I know in EJB 3.0 the #EJB annotation could be used to inject an EJB but this did not work on simple pojos.
If it is not do I have to look the bean up in JNDI as I know you cannot simple use the new keyword.
With the new EJB 3.1 spec is it possible to inject an EJB into a pojo? I know in EJB 3.0 the #EJB annotation could be used to inject an EJB but this did not work on simple pojos.
Injection of EJB into an POJO is possible IF you use JSR-299 (Java Contexts and Dependency Injection) i.e. if your POJO is a CDI managed bean. In that case, you could do:
#Inject MyEJB service
But this is not an EJB 3.1 feature, this comes from CDI. And if you're not using CDI, you'll have to do a lookup.
Yes, use JNDI lookup.
Since your POJO is created by you (I assume), the container is not responsible for injecting the dependencies.
The new EJB spec (3.1) adds the ability to specify global JNDI names for EJBs. This means that you can use them in any bean, anywhere.
You must do an explicit JNDI lookup, however, as an EJB 3.1 container will not know about your POJO.
The only exception, which I'm guessing does not apply to you, is if your POJO is really an application client, in which case provided the field that is to contain the EJB is static, you may apply the #EJB annotation to it. If that's your situation, you should check out the application client rules in the overall Java EE 5 specification.
Finally, Java EE 6, with its inclusion of JSR-299, may allow what you describe to happen in some way; I do not know the spec yet so cannot comment on it.
I hope this all helps.
I wonder too if I could inject EJBs into unmanaged objects. See the Weld (JSR 299 reference implementation) documentation for more details.
But you can perform dependency injection by hand inside a repository or factory like this:
#Stateless
public PojoRespository {
#Inject
ResourceForPojos resource;
#PersistenceContext
private EntityManager em;
public Pojo findById(Object id) {
Pojo p = (Pojo) em.find(Pojo.class, id);
p.setResource(resource); // injects resource
return p;
}
}
If you have many methods where injection should be performed, you could use an interceptor.

Categories