#Configuration & #Bean multiple which can be inject - java

this is a springBoot1.5.22 project.I have 3 java config Bean ,use #Configuration and #Bean annotation.
when i try to run project with debug mode。why myBean method of ConfigurationC execute ? ,the myBean method of ConfigurationA and ConfigurationB not execute。what is mechanism ?
packages of the classes
start class
#Configuration
public class ConfigurationA {
#Bean
public MyBean myBean(){
System.out.println("ConfigurationA myBean init");
return new MyBean();
}
}
#Configuration
public class ConfigurationB {
#Bean
public MyBean myBean(){
System.out.println("ConfigurationB myBean init");
return new MyBean();
}
}
#Configuration
public class ConfigurationC {
#Bean
public MyBean myBean(){
System.out.println("ConfigurationC myBean init");
return new MyBean();
}
}

Like #jackycflau said in the comment above, all your beans have the same name.
These three beans, all with the same name and type, are being loaded (but not yet initialized) sequentially into the application context (bean container). When a bean named "myBean" of type MyBean is returned from the application context, you get the one from ConfigurationC because it was the last one written into the container, which overwrote the previous two beans of the same name/type. It's apparently not being initialized until it's actually pulled from the container by client code, which is why it's the only one whose code actually runs.

please provide code snippets to analyse it more.
Bean id should be unique. I don't think you would be allowed to create beans with same beanid.
please try below code
#Configuration
public class ConfigurationA {
#Bean
public MyBean myBean(){
System.out.println("ConfigurationA myBean init");
return new MyBean();
}
}
#Configuration
public class ConfigurationB {
#Bean
public MyBean myBean1(){
System.out.println("ConfigurationB myBean init");
return new MyBean();
}
}
#Configuration
public class ConfigurationC {
#Bean
public MyBean myBean2(){
System.out.println("ConfigurationC myBean init");
return new MyBean();
}
}

You can try specifying names:
#Bean(name="bean1")
and then select the injected bean:
#Autowired
#Qualifier("bean1")

In Spring Boot 1.5.x the bean overriding is enabled by default.
This means, the bean definition tree is built first and then the last overriding bean is used (executed), all others are ignored (as they were overrided). In your case the last definition comes from ConfigurationC.
This mechanism prevents from ambitious bean definitions, where more than one definition is found, and Spring can't know which one to use - an error occurs (BeanDefinitionOverrideException).
Please note, this must be explicit enabled in Spring Boot 2.x.

Related

Why do we use a qualifier when we can have a name for the bean?

Why do we use qualifiers with #Bean when we can have different names for different beans of the same type (class)?
#Bean
#Qualifier("fooConfig")
public Baz method1() {
}
Isn't the following code more clean?
#Bean("fooConfig")
public Baz method1() {
}
If I create two beans of the same type with different names (using #Bean annotation), then can we inject them specifically using the #Qualifier annotation(can be added on field/constructor parameter/setter) in another bean?
#Bean("fooConfig")
public Baz method1(){
}
#Bean("barConfig")
public Baz method2(){
}
// constructor parameter of a different bean
final #Qualifier("fooConfig") Baz myConfig
If the above is true, then where do we use #Qualifier (with #Bean or #Component) instead of giving the bean a name as shown below?
#Bean
#Qualifier("fooConfig")
public Baz method1(){
}
#Bean
#Qualifier("barConfig")
public Baz method2(){
}
// constructor parameter of a different bean
final #Qualifier("fooConfig") Baz myConfig
Beans have names. They don't have qualifiers. #Qualifier is annotation, with which you tell Spring the name of Bean to be injected.
No.
Default Qualifier is the only implementation of the interface(example is below, 4th question) or the only method with a particular return type. You don't need to specify the #Qualifier in that case. Spring is smart enough to find itself.
For example:
#Configuration
public class MyConfiguration {
#Bean
public MyCustomComponent myComponent() {
return new MyCustomComponent();
}
}
If you will try to inject myComponent somewhere, Spring is smart enough to find the bean above. Becaude there is only one Bean with return type MyCustomComponent. But if there was a couple of methods, that would return MyCustomComponent, then you would have to tell Spring which one to inject with #Qualifier annotation.
SIDENOTE: #Bean annotation by default Spring uses the method name as a bean name. You can also assign other name like #Bean("otherComponent").
You have one Interface, and a couple of Classes implementing it. You inject bean of your interface. How can Spring know which Class should be used?
This is you interface:
public interface TestRepository{}
This is your implementation 1:
#Repository
public class Test1Repository implements TestRepository{}
Your implementation 2:
#Repository
public class Test2Repository implements TestRepository{}
Now you are injecting it like:
private final TestRepository testRepository;
public TestServiceImpl(TestRepository testRepository) {
this.testRepository= testRepository;
}
QUESTION! How is Spring supposed to know which class to inject? Test1 or Test2? That's why you tell it with #Qualifier which class.
private final TestRepository testRepository;
public TestServiceImpl(#Qualifier("test1Repository") TestRepository testRepository) {
this.testRepository= testRepository;
}
I Prefer different method to not using #Qualifier
Create common Interface
public interface CommonFooBar{
public String commonFoo();
public String commonBar();
}
Extends to each service
public interface FooService extends CommonFooBar {
}
public interface BarService extends CommonFooBar {
}
Then using it to your class
#Autowired
FooService fooService;
or
#Autowired
BarService barService;
so, we can defined the single responsibility to each interface and This kind of segregation is more readable to every junior.
I quite like a different way of working. Surely if you provide a unique name for your bean, then that is all you need?
Given the example below, its easy to see that Spring will name the beans based on the method name used to create the beans. In other words, if you give your beans sensible names, then the code should become self-explanatory. This also works when injecting beans into other classes.
The end result of this is:
Spring will name your beans based on the method used to create them.
If you import a bean, Spring will try to match on the bean name.
If you try to import a bean that does not match the name, Spring will attempt to match the class.
If your injected field name does not match the bean name and there are more than one instance of your bean, Spring will throw an exception on startup as it won't know which one to inject.
Lets not over-complicate Spring.
#Bean
mqConnectionFactory() {
ConnectionFactory connectionFactory = new MQXAConnectionFactory();
return connectionFactory;
}
#Bean
public ConnectionFactory pooledConnectionFactory(ConnectionFactory mqconnectionFactory) {
JmsPoolConnectionFactory connectionFactory = new JmsPoolConnectionFactory();
connectionFactory.setConnectionFactory(mqConnectionFactory);
return connectionFactory;
}
#Bean
public ConnectionFactory cachingConnectionFactory(ConnectionFactory mqConnectionFactory) {
CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
connectionFactory.setTargetConnectionFactory(mqConnectionFactory);
return connectionFactory;
}
#Bean
public JmsTemplate jmsTemplate(ConnectionFactory cachingConnectionFactory) {
JmsTemplate jmsTemplate = new JmsTemplate();
jmsTemplate.setConnectionFactory(cachingConnectionFactory);
return jmsTemplate;
}
#Bean
public DefaultMessageListenerContainer messageListenerContainer(ConnectionFactory pooledConnectionFactory) {
DefaultMessageListenerContainer container = new DefaultMessageListenerContainer();
container.setConnectionFactory(pooledConnectionFactory);
...
return container;
}

Spring check if a lazy bean is instantiated

Suppose I have a lazy Spring managed bean MyBean within a custom scope like this:
#Configuration
public class MyConfiguration {
#Scope("custom")
#Lazy
#Bean
MyBean myBean () {
return new MyBean();
}
}
and another Spring managed bean:
#Component
class MyBeanCounter{
void checkIfMyBeanIsInstantiated () {
// Check if there is an instance of MyBean within Spring context
}
}
Within checkIfMyBeanIsInstantiated I want to check if there is an instance of MyBean within Spring context without triggering the bean creation.
The obvious idea is to inject MyBean like this:
#Component
class MyBeanCounter {
#Autowired
MyBean myBean;
void checkIfMyBeanIsInstantiated () {
if (myBean != null) {// this doesn't trigger the bean creation
// there is an instance
}
}
}
The problem with the above solution is that I have to refresh the MyBeanCounter every time the MyBean instance changes according to it's custom scope.
The above solution doesn't work because #Autowired MyBean myBean; does instantiate the bean. Replacing it with #Lazy #Autowired MyBean myBean; still doesn't work since I end up with an injected proxy.
Is there any solution?
Since you seem to not actually need or want the instance in the check, just do
#Configuration
public class MyConfiguration {
#Scope("custom")
#Lazy
#Bean
MyBean myBean (MyBeanCounter counter) {
counter.setBeanInstantiated();
return new MyBean();
}
}
#Component
class MyBeanCounter {
#Setter
private boolean beanInstantiated;
void checkIfMyBeanIsInstantiated () {
if (beanInstantiated) {
// there is an instance
}
}
}
#Component
class MyBeanCounter {
#Autowired
private ApplicationContext appContext;
void checkIfMyBeanIsInstantiated () {
String[] beans= appContext.getBeanDefinitionNames();
// now loop the beans and if it is Null it has not been Instantiated
// beans will contain all the beans name
}
}
For the "refresh" issue, make sure your scope uses a proxy which will help you retrieve the correct bean instance. You can add proxyMode = ScopedProxyMode.TARGET_CLASS to your #Scope annotation. This way you won't need to reload the MyBeanCounter so that it uses the new instance.
As for checking if the bean has bean initialized, you can directly check if it's different to null. A non initialized bean is equals to null.
So your checkIfMyBeanIsInstantiated could be as follows:
void checkIfMyBeanIsInstantiated () {
if(myBean == null) {
// Not initialized
return;
}
// Initialized
}
Also make sure you add required = false to your #Autowired annotation:
#Autowired(required = false)
MyBean myBean;
If required is not set to false (it's default value is true), myBean will be instantiated right away because Spring see it as a required component for MyBeanCounter. By setting it to false and with using #Lazy, Spring will only initialize it when it's called.
But make sure you always test it for null to avoid a NullPointerException.

spring not creating bean

I have two beans that implements the same interface. Both are created in Java configuration, like this:
#Bean
#Qualifier("kafkaEventSender")
public IKafkaEventSender<KafkaData> kafkaEventSender(#Qualifier("EventBus") KafkaTemplate<String, Object> kafkaTemplate){
return new KafkaEventSender<>(kafkaTemplate, false);
}
#Bean
#Qualifier("kafkaEventSenderAudited")
public IKafkaEventSender<KafkaData> kafkaEventSenderAudited(#Qualifier("EventBus") KafkaTemplate<String, Object> kafkaTemplate){
return new KafkaEventSenderAudited<>(kafkaTemplate, false);
}
The problem is that spring doesn't create first bean only the second. Any idea why?
Try using bean names instead:
#Bean(name = "kafkaEventSender")
public IKafkaEventSender<KafkaData> kafkaEventSender(#Qualifier("EventBus") KafkaTemplate<String, Object> kafkaTemplate){
return new KafkaEventSender<>(kafkaTemplate, false);
}
#Bean(name = "kafkaEventSenderAudited")
public IKafkaEventSender<KafkaData> kafkaEventSenderAudited(#Qualifier("EventBus") KafkaTemplate<String, Object> kafkaTemplate){
return new KafkaEventSenderAudited<>(kafkaTemplate, false);
}
Ok, the problem was with method name, after changing it, bean is properly created. In some other library configuration class was a method with same name. Guessing that was the problem.
#Qualifier annotation is used to select one bean over multiple available beans of same type in spring container.
when you annotate a method with #Bean annotation, default, it creates a bean whose name is the name of same method. So, for example:
#Bean
public BeanA itsBeanA() {
return new BeanA();
}
#Bean(name = "specialBeanA")
public BeanA itsAgainBeanA() {
return new BeanA("specialConstructorParam");
}
#Bean
public BeanB beanB(#Autowired #Qualifier("specialBeanA") BeanA beanA) {
return new BeanB(beanA);
}
first method will create an instance of BeanA with name 'itsBeanA'. Second, will create an instance with name 'specialBeanA' since we provided the name attribute here.
There maybe a scenario where you need to have multiple beans of same TYPE (like BeanA here). It will create ambiguity for container which bean to use of all same types, we specify the #Qualifier with the name of bean which we want.
I hope that helps.

Eliminating Spring.xml from Spring Framework

In Spring Framework is it possible to eliminate the entire Spring.xml and use a configuration class with #Configuration and #Bean annotation for creating bean, and for all other purpose use a spring.xml?
Yes, you can have pure java configuration in Spring. You have to create a class and annotate it with #Configuration. We annotate methods with #Bean and instantiate the Spring bean and return it from that method.
#Configuration
public class SomeClass {
#Bean
public SomeBean someBean() {
return new SomeBean();
}
}
If you want to enable component scanning, then you can give #ComponentScan(basePackages="specify_your_package") under the #Configuration. Also the method name as someBean serves as bean id. Also if you have to inject a dependency, you can use constructor injection and do as following:
#Configuration
public class SomeClass {
#Bean
public SomeDependency someDependency() {
return new SomeDependency();
}
#Bean
public SomeBean someBean() {
return new SomeBean(someDependency());
}
}
Yes,most of (maybe all of)official guides uses absolutely no xml configuration file,just annotations.

Registering #Component annotated class programmatically

I'm new to spring framework, my problem is to register spring component through the spring application context I tried it with many different ways but no luck yet.
#Configuration
#ComponentScan("com.example.app")
#EnableAutoConfiguration
public class ContextDataConfiguration
{
...
}
registered it with
#PostConstruct
public void initilize()
{
AutowireCapableBeanFactory beanFactory = context.getAutowireCapableBeanFactory();
beanFactory.initializeBean( new ContextDataConfiguration(), "contextDataConfiguration" );
}
but the other beans specified in the ContextDataConfiguration class are not getting initialized with this approach.
And if I specify the ContextDataConfiguration class in the component scan it is working but it is giving me an error like
not a managed type class
Is there any alternative way to do this?
You can use the #Bean annotation in a factory method to initialize your bean. So, lets say you have a MyBean component and wants to initialize it... You can do this inside your #Configuration class:
#Bean
public MyBean myBean() {
MyBean myBean = ... // initialize your bean here
return myBean;
}
How a about
#Bean
public ContextDataConfiguration contextDataConfiguration(){
return new ContextDataConfiguration();
}
This registers an instance of ContextDataConfiguration as a bean.

Categories

Resources