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
Related
I have a entity class called Customer, I am using this entity object in another class to set the data. When I use this object below like
#Autowired
Customer customer
Spring is complaining that please configure the bean in your classes.
Can we use auto wiring with entity objects?
You can only autowire only those beans whose life-cycle are managed by Spring IoC container.
These beans are defined in xml form with </bean> tag, or with some special annotations like #Bean, #Component, #Service, #Repository etc.
On the other hand,
in simple terms, entities are some java objects that you will need to create, update by yourself according to your business logic and save/update/remove them in/from DB. Their life-cycle cannot be managed by Spring IoC container.
So, you should never feel like you need to autowire an entity if you are doing it right!
In fact, Spring support #Autowire only for Spring Beans. A java class becomes Spring Bean only when it is created by Spring, otherwise it is not.
A workaround might be to annotate your class with #Configurable but you would have to use AspectJ
Please look in the Spring documentations on how to use #Configurable
Also, I wonder why you would autowire an entity class ?
I would warn you not to mix Spring Bean and JPA entities in one class/usecase because:
Spring Beans are instantiated and managed by Spring
Entities are managed by JPA provider
If you mean JPAs #Entity-annotation, Spring is simply telling you, that there isn't a bean in its context.
On startup/runtime classes in the application will be scanned and each class annotated with spring annotations like #Component, #Service etc. will be instantiated as beans and put into a global context (Spring applicationcontext).
This context is then used to lookup and inject those beans into other beans when #Autowired is found during scanning.
Opposed to this, #Entity is used during the creation of the Persistence-Context of JPA (as far as I remember) which isn't aware of Spring and it's context.
Most of the solutions to make both contexts aware of each other a mostly a little bit hacky.
Is there any annotation/trick in Spring that marks a #Configuration #Bean as injectable only on strictly qualified #Autowireds?
I'd like my bean to be qualified in a way that only those that specifically call for its #Qualifer can inject it. It's indeed a mechanism for controlling where is it going to be able to be autowired, with no ambiguity nor arbitrary decisions depending on available beans in the context.
So my bean would never be autowired as a side-effect out-of-my control without me actively marking the injecting as expecting it
You can control bean creation with #Conditional annotation.
Also if you need real control of using bean you can create some annotation like #ConroledByQualifer and use this annotation instead of standard spring component annotation , or extension for one (like service , repository .... ) .
So spring can't process it for autowired as one don't know how to handling it.
You need add custom BeanPostProcessor that will work with #ConroledByQualifer - create it and inject. So your custom bean will be processed only by BeanPostProcessor for #ConroledByQualifer and not custom spring BeanPostProcessors.
This question already has answers here:
Understanding Spring #Autowired usage
(3 answers)
Closed 6 years ago.
Using Spring, i have a class 'BaseController' with BaseService injected using autowiring. How the autowiring working even if the class is not inititalized. Check code below
#Controller
class BaseController{
#Autowired
private BaseService baseService;
//......
}
and bean definition in xml as
<context:annotation-config />
<bean name="baseService" class="com.test.service.BaseService" />
I am not initializing baseService either with Setter/Constructor.
How does it works, when i call a method as show below
baseService.methodOne();
Spring framework relies on Spring IoC (Inversion of Control) Container to create all the components and initialize them by injecting their dependencies. The dependencies are injected though constructors, setters and/or fields by using the reflection API.
Here you annotated the field baseService with the annotation Autowired which will indicate the Spring IoC Container to inject a bean of type BaseService, if at the time the container needs to create your Controller, the dependency has not been created and initialized, it will do it automatically and if this bean has dependencies it will apply the same logic on the dependencies until the dependency tree has been fully created and initialized. This is how it works in a nutshell.
If we have two controller classes A & B, with dependency on
BaseService. Does Spring container create two objects and injects into
A and B separately or Only one instance of BaseService is shared among
all the classes that has dependency.
It depends on the scope that you set on your bean declaration, if the scope is singleton, the container will create only one instance of your bean and then will inject the same instance in your controllers. If you chose prototype for example, it will create a new instance of your bean for each of your controllers. In your case knowing that singleton is the default scope, it will inject the same instance. For more details about the supported scopes in Spring IoC Container, you can read this.
If you have enabled the class scanning, spring detects all the spring bean types at the startup and inject dependencies if it marked with #Autowired, #Resource, etc annotations.
According to your example, BaseController must be a type of spring bean and also the BaseService. If the BaseService is an interface there must be an impl. if there are many impls, then you need a #Qualifier annotation as well.
Spring uses reflection, so you do not need a setter or a constructor to inject the dependency.
By default all the beans are singleton unless you set scope via #Scope
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.
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.