Spring dependency injection controll - java

How do I control/restrict the instantiation of bean?
Lets say, I have 2 beans
A.java
B.java
Scopes of the both the bean as singleton & configured inside Spring application context
If A bean gets instantiated then B shouldn't vice-versa if B gets instantiated the A shouldn't.

You can use #Conditional or #Profile.
For first annotation you can write a class which will check if your bean exists.

Related

How #Autowired works, if #Autowired is set on property(Class) which is only declared but not initialized using setter/constructor [duplicate]

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

Spring dynamic bean definition autowire

So first short introduction:
I have a working application context, now I want to create a new bean factory that extends it with some dynamic bean definitions.
So i create a new instance of DefaultListableBeanFactory passing base application context as parent.
Then I create a new bean definition:
BeanDefinition beanDef = BeanDefinitionBuilder.rootBeanDefinition(beanType)
.setScope(BeanDefinition.SCOPE_PROTOTYPE)
.setLazyInit(false)
.setAbstract(false)
.setDependencyCheck(AbstractBeanDefinition.DEPENDENCY_CHECK_ALL)
.getBeanDefinition();
and at the end I register it with newly created bean factory
beanFactory.registerBeanDefinition(beanName, beanDef);
then some time later i would like to get new instance of that bean so I do:
Object beanInstance = beanFactory.getBean(jobType);
now i would expect that fields annotated with #Autowired are initialized.. but no. Calling beanFactory.autowireBean(beanInstance) does not help.
After looking up some other bean definitions in base application context i can see that my definitoin does not have any attributes and that I can add them by calling beanDef.setAttribute() but that requires me to know them in advance.
Now question. Is there a way to create fully initialized bean definition programmatically so it is autowired correctly?
So so i found out what i was missing:
AutowiredAnnotationBeanPostProcessor
it needs to be added to bean factory to fire up the #Autowired and #Value annotations.
also for #PostConstruct and #PreDestroy you need CommonAnnotationBeanPostProcessor
Bean factory created for application context by spring boot has total of 12 bean post processors so it is possible that some other are needed to get all features.

get a bean instance inside a non managed spring class if I am retrieving it through ApplicationContext getBean method

I know I can not use #Autowired annotation in a non managed spring class. But I notice I do able to get a bean instance inside a non managed spring class if I am retrieving it through ApplicationContext getBean method.
can someone explain me why is that ? what is the different between the options ? in both spring doesn't know the non managed class
1) You can use #Autowired in a non-managed spring class if you use #Configurable -with the usage of internal aspect weaving spring will manage to autowired the referenced beans into your "Configurable" class when it is constructed with the "new" operator. Here is an article how this works: http://www.javacodegeeks.com/2013/09/spring-configurable-magic.html
If a class is not configurable spring cannot notice when a new instance is created to autowire its references.
2) The ApplicationContext is "Central interface to provide configuration for an application." Here you have access to the whole spring managed beans etc. That's why you can get everything due to accessing it via ApplicationContext. http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/ApplicationContext.html
ok, so here's the major points:
the "bean declaration" (either in xml or java) is just a recipe of how to instantiate the object (not a object itself).
when spring application boots, the beanFactory receives this recipes from beanDefinitionReader, instantiates objects according to them (recipes) and then pass them (objects) to a list of beanPostProcessors (several times) that are "injecting" dependences to the instantiated objects and then puts the objects into hashMap.
roughly saying applicationContext is a class exposing access to this beans;
and that's how you can access this beans out of spring application using applicationContext.
another thing is that, actually you can inject beans into non managed beans through #Configurable. in this case the AspectJ would be used for making this work

when is a spring bean instantiated

ApplicationContext ctx = new ClassPathXmlApplicationContext(
"com/springinaction/springidol/spring-idol.xml");
Performer performer = (Performer) ctx.getBean("duke");
performer.perform();
In the above, when are the beans instantiated, when the ApplicationContext is created or when the getBean() is called?
Assuming the bean is a singleton, and isn't configured for lazy initialisation, then it's created when the context is started up. getBean() just fishes it out.
Lazy-init beans will only be initialised when first referenced, but this is not the default. Scoped beans (e.g. prototype-scoped) will also only be created when first referenced.
According to Spring documentation,
The default behavior for ApplicationContext implementations is to eagerly pre-instantiate all singleton beans at startup.
Also, you can set them to load lazily.
For reference, see
Lazy-initialized beans and
Bean scopes
Here's a brief description of when beans are created:
A singleton bean (which is the default scope) that does not have the lazy-init property set to true (default is false) is constructed when the application context is created
A singleton bean that does have the lazy-init property set to true is constructed when it is first requested
A bean set in any other scope is created when it is first requested (for that scope).
By default, all beans are singletons, so whenever Application context gets created, they are all pre-loaded. If, specifically, any singleton bean has an attribute lazy-init="true" set, it will be lazy-loaded, i.e. it will be instantiated when the getBean method is called for the first time.
For other scopes, beans will be instantiated whenever they are requested.
It depends what is the scope of the bean you are calling with getBean() method.
If it is 'Singleton', it is pre-instantiated by the ApplicationContext.
If you are using BeanFactory as an IOC Container, then it uses lazy initialization and the beans will be instantiated only when you call the getBean() method.
This is an advantage of ApplicationContext over BeanFactory that it solves Circular Dependency problem.
By default, Spring ApplicationContext eagerly creates and initializes all ‘singleton scoped‘ beans during application startup itself. ApplicationContext makes the bean available in BeanFactory. getBean() returns the instance of the bean.
By default it's created when the context is started up but the order depends on dependencies.
If we have the following classes :
#Component
public class A{
}
#Component
public class B{
#Autowired
A a;
}
Class A will be created before class B because class B depends on class A.
Basically, when you run ApplicationContext, it automatically creates all the Annotated beans and makes ready them to use for you.
If you don't need some of them, you can annotate them with #Lazy and they will not instantiated when you run the application

is it not allowed to implement a single local interface by two stateless beans?

I am getting following exception when a Local Interface is implemented by two Stateless beans, in which one having normal functionality and other having some enhanced functionality in it.
java.lang.RuntimeException: could not
resolve global JNDI name for #EJB for
container UserBean: reference class:
org.app.SecurityServiceLocal ejbLink:
duplicated in Some.jar
Finally I came to know why I am getting this exception
I have used #EJB annotation to inject a Stateless bean into another Stateless bean Name UserBean with following code
#Stateless(name="UserBean")
#EJB(name="app/SecurityService",
beanInterface=SecurityServiceLocal.class)
public class UserBean implements UserRemote{
}
If you check the injection details I was injecting SecurityServiceLocal, which was implemented by two Stateless bean classes name SercurityServiceBean and SecurityServiceEnhaBean. So, container is in ambiguity state to decide which bean to inject in as both are implementing same interface.
This can be resolved by specifying some more information like beanName property value in #EJB annotation. There you need to provide which stateless bean class needs to be injected by using bean name(declared at that bean level (or) in ejb-jar.xml). check the code to identify the change in the injection mapping
#Stateless(name="UserBean")
#EJB(name="app/SecurityService",
beanInterface=SecurityServiceLocal.class,
beanName="SecurityServiceEnha")
public class UserBean implements UserRemote{
}
It's hard to say for sure without seeing code. A good first step would be to use the optional mappedName="" attribute on your session beans' annotion to give each a unique JNDI name. You'll have to use an equivalent mappedName attribute in your client to make sure you are using the bean that you intent.

Categories