Configuring Spring to ignore dependencies annotated with #Inject - spring

I have an EJB class in which I need to inject two beans - one should be injected by the EJB container and other is a Spring Container.
#Stateless
#Interceptors(SpringBeanAutowiringInterceptor.class)
#LocalBean
public class SomeClass {
#Inject
private EJBClass a;
#Autowired
private SpringComponent b;
}
Here, the Spring interceptor trying to intercept the injection of bean 'a' and it's getting failed. I want the EJB container to inject the bean 'a' and Spring container to inject bean 'b'.
Please show me a way out here.

By customizing the SpringBeanAutowiringInterceptor class, dependencies annotated with #Inject can be excluded from auto wiring.
To understand what happens behind the scene, have a look at source code of
SpringBeanAutowiringInterceptor.java -
/**
* Actually autowire the target bean after construction/passivation.
* #param target the target bean to autowire
*/
protected void doAutowireBean(Object target) {
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
configureBeanPostProcessor(bpp, target);
bpp.setBeanFactory(getBeanFactory(target));
bpp.processInjection(target);
}
At first line, of doAutowireBean, a new instance of AutowiredAnnotationBeanPostProcessor is created. Here set of annotations to be scanned for auto wiring dependencies are configured.
/**
* Create a new AutowiredAnnotationBeanPostProcessor
* for Spring's standard {#link Autowired} annotation.
* <p>Also supports JSR-330's {#link javax.inject.Inject} annotation, if available.
*/
#SuppressWarnings("unchecked")
public AutowiredAnnotationBeanPostProcessor() {
this.autowiredAnnotationTypes.add(Autowired.class);
this.autowiredAnnotationTypes.add(Value.class);
try {
this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
logger.info("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring");
}
catch (ClassNotFoundException ex) {
// JSR-330 API not available - simply skip.
}
}
Since, by default, the #Inject annotation is configured spring scans respective dependencies marked with #Inject and tries to auto wire them.
To exclude #Inject annotated dependencies write below custom class.
public class CustomSpringBeanAutowiringInterceptor extends SpringBeanAutowiringInterceptor {
/**
* Template method for configuring the
* {#link AutowiredAnnotationBeanPostProcessor} used for autowiring.
* #param processor the AutowiredAnnotationBeanPostProcessor to configure
* #param target the target bean to autowire with this processor
*/
protected void configureBeanPostProcessor(AutowiredAnnotationBeanPostProcessor processor, Object target) {
Set<Class> annotationsToScan = new HashSet<Class>();
annotationsToScan.add(Autowired.class);
annotationsToScan.add(Value.class);
processor.setAutowiredAnnotationTypes(annotationsToScan);
}
}
Here configureBeanPostProcessor hook is utilized to customize the bean post processor so as to include only those annotations which we require to be auto wired.
After applying this custom class as interceptor in code the desired behaviour can be achieved
#Stateless
#Interceptors(CustomSpringBeanAutowiringInterceptor.class)
#LocalBean
public class SomeClass {
#Inject
private EJBClass a;
#Autowired
private SpringComponent b;
}
Let know in comments if you face any issues. Also feel free to optimize the code as deemed fit and excuse any compilations / formatting issues.

Use #EJB annotation to inject EJB

Related

Spring Boot configuration for non-beans [duplicate]

This question already has answers here:
Injecting beans into a class outside the Spring managed context
(8 answers)
Closed 3 years ago.
Introduction
I have some business logic properties in the application.yml file.
They are loaded into the application via a #ConfigurationProperties annotated class.
How could I use these properties in a class which is not a Spring Bean? It cannot be a singleton, because many objects of it must be created during run-time.
Example
application.yml
business.foo: 2
BusinessProperties.java
#ConfigurationProperties("business")
#Getter // lombok
#Setter // lombok
public class BusinessProperties {
private int foo;
}
TypicalBean.java
#Component
public class TypicalBean {
private final BusinessProperties properties;
#Autowired
public TypicalBean(BusinessProperties properties) {
this.properties = properties;
}
#PostConstruct
public void printFoo() {
System.out.println("Foo: " + properties.getFoo()); // "Foo: 2"
}
}
NonBean.java
public class NonBean {
public void printFoo() {
System.out.println("Foo: ???"); // How to access the property?
}
}
Is there some way to create a non-singleton class, which can have access to configuration (or even other Spring beans) but otherwise works the same as a regular java class? Meaning that I can control its creation, it is collected by the garbage collector if not used anymore, etc.
You can still define the NonBean.class as a Component with Scope.Prototype
#Component
#Scope(value = BeanDefinition.SCOPE_PROTOTYPE)
public class NonBean {
#Autowired
public TypicalBean(BusinessProperties properties) {
this.properties = properties;
}
public void printFoo() {
System.out.println("Foo: " + properties.getFoo());
}
}
The trick is how you create an instance of NonBean.class. In the code where you'll be creating an instance of NonBean.class, use Spring's ObjectFactory<T>
private final ObjectFactory<NonBean> nonBeanFactory;
...
NonBean nonBean = nonBeanFactory.getObject();
The instantiated nonBean object will have been autowired.
All spring-beans creates by SpringApplicationContext. Bean - it's simple POJO-object, but created by Spring and saved in his container. If you want to get access to bean from outside of container - see this:
Getting Spring Application Context
Spring beans are really meant to be used within the application context but you might be able to achieve what you want by autowiring the properties to a static field in a Spring bean.
#Component
public class BusinessPropertiesUtils {
public static BusinessProperties INSTANCE;
#Autowired
public setBusinessProperties(BusinessProperties properties) {
this.INSTANCE = properties;
}
}
And then:
public class NonBean {
public void printFoo() {
System.out.println("Foo: " + BusinessPropertiesUtils.INSTANCE.getFoo());
}
}
PS: this is very hacky and definitely not the "Spring way".
You can configure beans with the prototype scope, which will give you a new instance of the bean every time it's requested.
From the Spring documentation:
In contrast to the other scopes, Spring does not manage the complete lifecycle of a prototype bean. The container instantiates, configures, and otherwise assembles a prototype object and hands it to the client, with no further record of that prototype instance.
...
In some respects, the Spring container’s role in regard to a prototype-scoped bean is a replacement for the Java new operator. All lifecycle management past that point must be handled by the client.
Example of how you can convert the TypicalBean class to a prototype scoped bean:
#Component
#Scope("prototype")
public class TypicalBean {
...
}
Another alternative is to manually instantiate the bean class (or any POJO) and injecting the dependencies (configuration, spring beans, etc.) through the constructor or setter methods, if you have them available or can get them from the Spring Context.
new TypicalBean(properties);

JSR-330 #Scope and Spring Don't Match

The java doc for the JSR-330 Scope annotation states "uses the instance for one injection, and then forgets it" implying that the instance is of scope prototype and the Singleton annotation is intended to create the singleton that is the default behavior with spring. So the question is, Why, when I use the Named annotation rather than the Spring Component annotation does Spring not follow the JSR guidelines and scope the bean as prototype? It seems to me like it should.
I would like to keep the spring dependencies consolidated to a single module and use JSR-330 everywhere else so If needed I can easily switch later.
So this is how I made what I want work:
/**
* JSR-330 assumes the default scope is prototype, however Spring IOC defaults to singleton scope.
* This annotation is used to force the JSR-330 standard on the spring application.
*
* This is done by registering this annotation with the spring bean factory post processor.
* <pre>
* <code>
* public class PrototypeBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
*
* public void postProcessBeanFactory(ConfigurableListableBeanFactory factory) throws BeansException {
* for (String beanName : factory.getBeanDefinitionNames()) {
* if (factory.findAnnotationOnBean(beanName, Prototype.class) != null) {
* BeanDefinition beanDef = factory.getBeanDefinition(beanName);
* beanDef.setScope("prototype");
* }
* }
* }
* }
* </code>
* </pre>
*
* #see javax.inject.Scope #Scope
*/
#Scope
#Documented
#Retention(RUNTIME)
public #interface Prototype {}
I put this annotation in my core jar and then let the spring-boot app module do the work of processing the annotation.
It works well for me but I am happy to hear any other suggestions.

spring boot application - get bean from static context

I have a instance of a class that is created outside of Spring that I'd like to have access to Spring beans so that it may fire an event and be observed by Spring beans. I'm not using Spring web, my application is running from the command-line via spring boot.
The only option you have is to expose the Spring context of your application using a static method so that the object that is not managed by Spring can use it to get references to managed beans it needs.
Start with a wrapper for the context. Create a regular managed bean which required reference to the context in its constructor. The reference is assigned to a static class field, which also has a static getter:
#Service
class ContextWrapper {
private static ApplicationContext context;
#Autowired
public ContextWrapper(ApplicationContext ac) {
context = ac;
}
public static ApplicationContext getContext() {
return context;
}
}
Use the static getter to get access to context in the object which is not managed by Spring and get reference to beans using methods available in the context:
SomeBean bean = ContextWrapper.getContext().getBean("someBean", SomeBean.class);
// do something with the bean
Last thing you need is communication channel from Spring beans to non-managed object. For instance, the SomeBean can expose a setter which will accept the non-managed object as a parameter and store the reference in a field for future use. The object mast get references to managed beans using the static context accessor mentioned above and use the setter to make the bean aware of its existence.
#Service
class SomeBean {
// ... your bean stuff
private SomeClass someclass;
public void setSomeClass(Someclass someclass) {
this.someclass = someclass;
}
private void sendEventToSomeClass() {
// communicate with the object not managed by Spring
if (someClass == null) return;
someClass.sendEvent();
}
}
You can inject by constructor that spring beans, something like:
#Service
class Bean {
...
}
class NotBean {
private Bean bean;
public NotBean(Bean bean) {
this.bean = bean;
}
// your stuff (handle events, etc...)
}

Is #Autowired taking care of the nested autowiring?

I have the following components, in two different files:
#Component
public class Chauffeur {
Car car;
public Chauffeur(Car car){
this.car = car;
}
public void go(){
System.out.println("Chauffeur");
car.drive();
}
}
#Component
public class Car{
public void drive() {
System.out.println("Drive car");
}
}
the following configuration file:
#Configuration
#ComponentScan
public class DriveableConfiguration {
}
and the following test:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes=DriveableConfiguration.class)
public class DriveableTest {
#Autowired
Chauffeur chauffeur;
#Test
public void chauffeurTest(){
chauffeur.go();
}
}
All the classes above are in the same package and the test is passing.
In the test I annotated chauffer with #Autowired, which should mean that the Spring container looks after the creation of the instance of Chauffeur without the developer needing to explicitly instantiate it.
Now, the constructor for Chauffer needs an instance of Car, so there is no default constructor for that class. Nonetheless the container creates it, injecting the required instance in the constructor.
Is the #Autowired saying to the container to instantiate the element with whatever (Components, Beans) it can provide, included parameters in the constructor? If so, in what case is it needed to use #Autowired to annotate a constructor?
Only if you use Spring 4.3+. In such a case #Autowired on constructor is optional if you have one non default constructor.
You can check the example here.
So as of 4.3, you no longer need to specify an explicit injection annotation in such a single-constructor scenario. This is particularly elegant for classes which otherwise do not carry any container annotations at all, for example when programmatically registered
For versions lower than 4.3 you will an exception will be thrown:
the container will throw an exception looking for a default
constructor, unless you explicitly indicate autowire mode
‘constructor’ in your bean definition setup (e.g. in an XML )

How do you use a bean from an another class in a class?

Using xml, I was able to define a common xml file, where i can put common bean which are used for other differect condig file.
I move my config to psring java config, how to achieve this with java config?
let's say I have my common class as :
#Configuration
public class Common {
#Bean
public A a(){
return new A();
}
}
and I want to use it as
#Configuration
public class AConfig {
#Bean
public ABB abb(){
ABB abb = new ABB();
//TODO abb.set ????
return abb;
}
}
The TODO part is missing, I want to use the a() from the common class.
Is that possible?
The simplest approach is just to 'Autowire' in a private member like this:
#Configuration
public class AConfig {
#Autowire
private A myA;
#Bean
public ABB abb(){
ABB abb = new ABB();
abb.setA(myA); // or MUCH better, make the A member of ABB private final and overload a construtor
return abb;
}
}
The reason this works is that AConfig is a Bean too. It has to be constructed by the Spring Bean Factory. After construction, the Post Construction activities take place - one of those being processing post construction annotations such as Autowired. So 'myA' will be set before it is used in the #Bean annotated method.
From the #Import annotation Javadoc:
* <p>Provides functionality equivalent to the {#code <import/>} element in Spring XML.
* Only supported for classes annotated with {#code #Configuration} or declaring at least
* one {#link Bean #Bean} method, as well as {#link ImportSelector} and
* {#link ImportBeanDefinitionRegistrar} implementations.
*
* <p>{#code #Bean} definitions declared in imported {#code #Configuration} classes
* should be accessed by using {#link org.springframework.beans.factory.annotation.Autowired #Autowired}
* injection. Either the bean itself can be autowired, or the configuration class instance
* declaring the bean can be autowired. The latter approach allows for explicit,
* IDE-friendly navigation between {#code #Configuration} class methods.
*
* <p>May be declared at the class level or as a meta-annotation.
*
* <p>If XML or other non-{#code #Configuration} bean definition resources need to be
* imported, use {#link ImportResource #ImportResource}
I presume that if you import the #Configuration class itself, the "latter approach", you'd then just explicitly call the #Bean method on the imported class, e.g.
#Configuration
#Import(BarConfiguration.class)
public class FooConfiguration {
#Autowired
private BarConfiguration barConfiguration;
#Bean
public Foo foo() {
Foo foo = new Foo();
foo.setBar(barConfiguration.bar());
return foo;
}
}

Resources