I have multiple datasource beans defined in my configuration file.I have 2 beans named customerDataSource. I want one of them to be instantiated only if other bean is not loaded.I was trying to use #ConditionalOnMissingBean. However it looks like this will work only when another bean of same "type" is not present. Is there a way to control this by using "name"?
The annotation has the parameter name, where you can specify the bean name that should be checked:
#ConditionalOnMissingBean(name = "beanNameToCheck")
Related
Tried to create two separate ElasticsearchRestTemplate using qualifier bean and gave different elasticsearchTemplateRef to ElasticsearchRepository , but its not working.
Getting error:
The bean 'elasticsearchTemplate', defined in class path resource [com/paytm/digital/search/ingestion/elastic/ElasticConfigK8.class], could not be registered. A bean with that name has already been defined in class path resource [com/paytm/digital/search/ingestion/elastic/ElasticConfig.class] and overriding is disabled.\n\nAction:\n\nConsider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-
Cannot register bean definition
I'm doing as follows:
register a NamespaceHandler (with all spring.x files, the handler is properly located and invoked)
in the Parser registered by the namespace handler, I load an xml file containing bean definitions (rather than defining them programmatically):
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(parserContext.getRegistry());
reader.loadBeanDefinitions(new ClassPathResource("definitions.xml"));
definitions.xml contains a <context:property-placeholder location="classpath:.. />
the applicationContext.xml which invokes my handler needs to pass a property (e.g. <foo:bar prop="${baz}" />
in the namespace handler I define an inline PropertySource and register it with the Environment, so that I can dynamically register a property that I need, which is based on the prop passed as attribute. I tried registering a String bean instead, but resolution fails.
The property placeholder resolution happens after bean definitions, so happens after my code in the namespace handler's parser is invoked.
However, this all fails. Multiple times, for multiple reasons. Here are they:
if <context:property-placeholder /> is defined without ignore-unresolvable="true" and order, the first placeholder configurer fails to find properties required by the 2nd one. This is logical, of course, and seems to be mandatory whenever multiple placeholder configurers are used
because the dynamic property is based on the passed prop, it looks like file://${prop}/foo", which means it is a nested property. You can't configure the behaviour of nested property resolution per configurer, which means even thoughignore-unresolvable` is true, nested properties are not ignored, and the whole thing fails.
The solution I found is to get the AbstractEnvironment in the namespace handler's parser, and set the call env.setIgnoreUnresolvableNestedPlaceholders(true)
This looks like a hack though. So my questions are:
how to dynamically register properties that will later be resolved?
how to configure ignoring nested property resolution per configurer?
is there a better way to achieve what I need - namely, include a "bundle" of definitions via a custom namespace, and pass properties (loaded from file) to them?
P.S. Spring improvement request posted: https://jira.springsource.org/browse/SPR-10654
I'm reading in a number of xml files which have bean definitions in them. I want to see the bean id of each bean as spring starts the process of reading the XML and/or creating the bean.
I have bean definition files, and I'm not certain they are being read in. I'd like to be certain.
If you have log4j turned on, all the app contexts and their bean names will be printed to the console/log.
<beans default-autowire="byType" />
means that all fields of beans will automatically have dependencies injected if there is no more than 1 bean with the desired type.
I wonder if there is a way to define some sort of priority order (based on naming convention for example) for the auto-wiring in the case where there are more than one bean of the desired type.
Thanks in advance.
Edit: I just want to add that i'm not allowed to use annotations such as #Component and #Qualifier in the project i'm currently working on.
No there is not, but you can override this behavior as needed for each bean e.g.specify something like this where required:
<beans default-autowire="byType" >
<bean id="..." autowire="byName">
....
</bean>
</beans>
From spring 2.5 upwards when using the <context:component-scan/> to autowire beans via #Autowired you can also add #Qualifier where needed to specify a bean by name if there are multiple beans of the same type.
As stated in the spring documentation there are a few different ways to specify autowiring:
no - do not autowire, this is the default
byType - property type must match bean type, if more than one bean of that type is exists then an exception is thrown
byName - bean name must match property name
constructor - basically the same as byType but for constructors, spring picks the constructor with the most matches
autodetect - same as byType unless there is no default constructor where it falls back to constructor autowiring
What exactly causes this?
org.springframework.beans.factory.NoSuchBeanDefinitionException: \
No unique bean of type [fi.utu.keycard.business.KeyCardManager] \
is defined: expected single matching bean but found 2: \
[dataBaseTarget, database]
// etc. (rest of Stack Trace is irrelevant)
What I need is autowiring 3 things: validator, ldap connection and database connection.
I call it:
#Controller
Controller(KeyCardManager database,
LdapPersonDao personManager,
GiveFormValidator validator)
The error seems to cause by another bean, if I change the order of these parameters. I have no signing-in, so I dont have UserDetails or so.
The fix is probably something like this:
public Controller(
#Qualifier("beanQualifier") KeyCardManager database,
LdapPersonDao personManager,
GiveFormValidator validator
)
Since there are apparently two beans of type KeyCardManager in your application context, you need to tell the context which one to wire.
Unfortunately the #Qualifier mechanism doesn't work with bean names, you must either annotate the actual bean with a corresponding #Qualifier or add a <qualifier> element to the XML bean definition.
The #Resource annotation works with bean names, but it doesn't support Constructor parameters (that's not Spring's fault, it's a JSR-250 standard annotation with #Target({TYPE, FIELD, METHOD}))
Reference:
Autowiring Collaborators
Fine-tuning annotation-based
autowiring with qualifiers
Troubleshooting
If you don't know why there are two beans of the same type in the context, first of all navigate to the bean interface (I assume KeyCardManager is an interface, if not, do the same thing for the class anyway) and if you use Eclipse select Navigate > Open Type Hierarchy. If you find more than one concrete class that inherits from KeyCardManager (including KeyCardManager itself), then there's probably your problem.
If that is not the case, you probably have two beans of the same type in your application context. One way that can happen is when you define a bean through both XML and classpath scanning. I.e. if you have this line in your XML:
<context:component-scan base-package="org.example"/>
Make sure you don't manually wire any beans from the org.example package (or you will have double beans, which can lead to the problem you have).
org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [fi.utu.keycard.business.KeyCardManager] is defined: expected single matching bean but found 2: [dataBaseTarget, database]
It seems you are autowiring by class type. but there are multiple bean available in the context with same class. which are dataBase & dataBaseTarget
byType
Allows a property to be autowired if
there is exactly one bean of the
property type in the container. If
there is more than one, a fatal
exception is thrown, and this
indicates that you may not use byType
autowiring for that bean. If there are
no matching beans, nothing happens;
the property is not set. If this is
not desirable, setting the
dependency-check="objects" attribute
value specifies that an error should
be thrown in this case.
Document