DAO classes have the same #Qualifier - java

I have the source code of a website.
This website uses spring, and I'am confused about the Injection.
There are some DAO classes, on these DAO with a Qualifier :
#Repository("myDao")
#Qualifier("myTransactionManager")
public class MyCategoryDao {
}
But there is also another bean with the same name of the Qualifier.
And this bean is a JpaTransactionManager.
#Configuration
#EnableTransactionManagement(mode = AdviceMode.PROXY)
#ComponentScan(basePackages = "com.my.repository")
public class DatabaseConfig {
#Primary
#Bean(name = "myTransactionManager")
public JpaTransactionManager jpaTransactionManager(
#Named("myEntityManagerFactory") EntityManagerFactory entityManagerFactory) {
}
}
I don't know why the bean and the DAOs have the same name/Qualifier.
Wouldn't it conflict the others?

Spring will check for type first, and if there is any ambiguity, then only it will check for the name specified in #Qualifier. In your case, types of both the beans are different, so that should work fine.

Related

What difference does #EnableConfigurationProperties make if a bean is already annotated with #ConfigurationProperties?

The Spring Boot documentation says that to use the #ConfigurationProperties annotation
You also need to list the properties classes to register in the
#EnableConfigurationProperties annotation, as shown in the following
example:
and gives this code:
#Configuration
#EnableConfigurationProperties(AcmeProperties.class)
public class MyConfiguration {
}
But in the very next paragraph says:
Even if the preceding configuration creates a regular bean for
AcmeProperties, we recommend that #ConfigurationProperties only deal
with the environment and, in particular, does not inject other beans
from the context. Having said that, the #EnableConfigurationProperties
annotation is also automatically applied to your project so that any
existing bean annotated with #ConfigurationProperties is configured
from the Environment.
Suggesting that listing a #ConfigurationProperties bean under an #EnableConfigurationProperties annotation is not necessary.
So which is it? Experimentally, I've seen that if I annotate a bean with #ConfigurationProperties it gets properties injected to it as expected without needing to list it in #EnableConfigurationProperties, but if this is the case then why list anything that has a #ConfigurationProperties annotation under #EnableConfigurationProperties, as is shown in the documentation? Does it make any kind of difference?
As M. Deinum referred #EnableConfigurationProperties Is for enabling support of #ConfigurationProperties. If you take a look to the annotation Java Doc you can see:
Enable support for ConfigurationProperties annotated beans. ConfigurationProperties beans can be registered in the standard way (for example using Bean #Bean methods) or, for convenience, can be specified directly on this annotation. [...]
For example, let's say you have a class whose responsibility is to read and store information from your application.yml / application.properties that is required to make a connection to different databases. You annotate it with #ConfigurationProperties.
Then, you typically have a #Configuration annotated class that provides a DataSource #Bean to your application. You can use the #EnableConfigurationProperties to link it to the #ConfigurationProperties class and init your data sources accordingly.
Here is a small example:
application.yml
data-sources:
db1:
url: "jdbc:postgresql://localhost:5432}/db1"
username: test
password: test
db2:
url: "jdbc:postgresql://localhost:5432}/db2"
username: test
password: test
DataSourcesConfiguration
#ConfigurationProperties
public class DataSourcesConfiguration {
private Map<String, BasicDataSource> dataSources;
public void setDataSources(Map<String, BasicDataSource> dataSources) {
this.dataSources = dataSources;
}
Map<String, BasicDataSource > getDataSources() {
return dataSources;
}
}
DataSourceConnectionConfiguration
#Configuration
#EnableConfigurationProperties(DataSourcesConfiguration.class)
public class DatabaseConnectionConfiguration implements Provider<Connection> {
private DataSourcesConfiguration dataSourcesConfiguration;
public DatabaseConnectionConfiguration(DataSourcesConfiguration dataSourcesConfiguration) {
this.dataSourcesConfiguration = dataSourcesConfiguration;
}
#Bean
public DataSource dataSource() {
// Use dataSourcesConfiguration to create application data source. E.g., a AbstractRoutingDataSource..
}
}
It took me a while to reach to this post but would like to add here so that others may get benefited.
#ConfigurationProperties - Used to bind a class with an externalized property file. Very powerful and must be used to separate out bean classes with configuration entity class.
#Configuration - Creates a Spring bean of configuration stereotype.
#EnableConfigurationProperties - Creates a binding between a configuration entity class and Spring configuration stereotype so that after injection within a service properties can be retrieved easily.
If we look at the code below:
#Configuration #EnableConfigurationProperties #ConfigurationProperties(prefix="ar1")
public class ar1Settings { }
#Configuration tells Spring to treat this as a configuration class and register it as a Bean
#EnableConfigurationProperties tells Spring to treat this class as a consumer of application.yml/properties values
#ConfigurationProperties tells Spring what section this class represents.
My understanding is that if you don't need to specify the section of the property file, then #ConfigurationProperties can be omitted.
#EnableConfigurationProperties imports EnableConfigurationPropertiesRegistrar which enables support for #ConfigurationProperties annotated beans.
#ConfigurationProperties is an annotation for externalized configuration, it is to be applied to a bean configuration class or method annotated with #Bean eg
#ConfigurationProperties(prefix = "some-prefix")
public SomePrefix prefixBean() {
return new SomePrefix();
}
To load the properties and bind them to properties within the method or the class that match the prefix.
ps: some-prefix binds to SomePrefix because of spring's support for Relaxed binding.
Before springboot 2.2, You could do either of the following:
#Configuration
#ConfigurationProperties(prefix = "some-prefix")
public class ConfigProperties {
//...some code
}
or
#Configuration
#EnableConfigurationProperties(SomeClassToBeBounded.class)
public class ConfigProperties {
along with
#ConfigurationProperties(prefix = "some-prefix")
public class SomeClassToBeBounded{
//...some code
}
From springboot 2.2
You can do it in a much easier way:
#ConfigurationProperties(prefix = "some-prefix")
#ConfigurationPropertiesScan
public class ConfigProperties {
//...some code
}
With this, the classpath scanner enabled by #SpringBootApplication finds the ConfigProperties class, even though we didn't annotate this class with #Component.

What are all the #Configuration naming rules for beans?

I have some integration tests that are supposed to mock out one of many beans in my system. To do this, I have a #Configuration that looks like this:
#Configuration
public class MockContext {
#Primary
#Bean
public RealBean realBean() {
return new MockBean();
}
}
I noticed that this method gets used if RealBean is a java class without #Component. But if RealBean is a #Component, I have to change this context method to look like this:
#Configuration
public class MockContext {
#Primary
#Bean
public RealBean getRealBean() {
return new MockBean();
}
}
Can anyone explain why I need to change this method name and where I can find all these rules? It takes a very long time to troubleshoot these "why isn't my MockContext working correctly?" issues.
FWIW, here's how I'm using this context in a test:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = {RealContext.class, MockContext.class})
#WebAppConfiguration
public abstract class AbstractIntegrationTest {
And my integration test will extend this class. I am using Spring Boot 1.2.4.RELEASE
You can have various beans registered with same type. But they need to have different names.
If you use #Bean annotation without name attribute, name of the bean is extracted from method name (in your case realBean/getRealBean).
When you use #Component annotation without attribute (which specifies bean name), name of the bean is extracted from method name where first letter is lowercased.
So with your first case, you get a name clash. You can't have two beans named realBean.
Your second example is without clash because bean annotated by #Component has name realBean and second bean registered via #Bean has name getRealBean.
#Primary annotation helps Spring choose which bean to pick if there are two of the same type and you inject by type. When you inject by name (usage of #Qualifier annotation), you can inject also secondary instance.

Autowire a bean within Spring's Java configuration

Is it possible to use Spring's #Autowired annotation within a Spring configuration written in Java?
For example:
#Configuration
public class SpringConfiguration{
#Autowired
DataSource datasource;
#Bean
public DataSource dataSource(){
return new dataSource();
}
// ...
}
Obviously a DataSource interface cannot be directly instantiated but I directly instantiated it here for simplification. Currently, when I try the above, the datasource object remains null and is not autowired by Spring.
I got #Autowired to work successfully with a Hibernate SessionFactory object by returning a FactoryBean<SessionFactory>.
So my question specifically: is there a way to do that with respect to a DataSource? Or more generally, what is the method to autowire a bean within a Spring Java Configuration?
I should note I am using Spring version 3.2.
If you need a reference to the DataSource bean within the same #Configuration file, just invoke the bean method.
#Bean
public OtherBean someOtherBean() {
return new OtherBean(dataSource());
}
or have it autowired into the #Bean method
#Bean
public OtherBean someOtherBean(DataSource dataSource) {
return new OtherBean(dataSource);
}
The lifecycle of a #Configuration class sometimes prevents autowiring like you are suggesting.
For completeness sake: Yes it is technically possible to use #Autowired annotation in spring #Configuration classes, and it works the same way as for other spring beans. But the accepted answer shows how the original problem should be solved.
maybe you can use constructor to inject some bean from other configuration file to your configuration,while #Autowired may not work correct in the configuration file
#Configuration
public class AppConfig {
private DataSource dataSource;
public AppConfig(DataSource dataSource) {
this.dataSource = dataSource;
}
#Bean
public OtherBean otherBean(){
return new OtherBean(dataSource);
}
}
beans configured with #Configuration class can't be autowired ,
So you cannot use #Autowiring and #configuration together

Multiple jpa:repositories in xml config, how to configure with #EnableJPARepositories using Spring java config?

I have researched and found an explaination and sample code as to how to use spring data jpa with multiple datasources which refers to configuring multiple jpa:repositories in the xml configuration as follows:
<jpa:repositories base-package="org.springframework.data.jpa.repository.sample"
entity-manager-factory-ref="entityManagerFactory">
<repository:exclude-filter type="assignable" expression="org.springframework.data.jpa.repository.sample.AuditableUserRepository" />
</jpa:repositories>
<jpa:repositories base-package="org.springframework.data.jpa.repository.sample"
entity-manager-factory-ref="entityManagerFactory-2"
transaction-manager-ref="transactionManager-2">
<repository:include-filter type="assignable" expression="org.springframework.data.jpa.repository.sample.AuditableUserRepository" />
</jpa:repositories>
How would you declare both of the above jpa:repositories configurations using java configuration and the #EnableJpaRepositories annotation?
The annotation seems to support only one set of attributes (i.e. for one jpa:repository only) and it is not possible to declare the annotation multiple times.
I created a 'minimal' multiple datasource project to help me work out how to do this. There are 7 Java classes and other config in there, so I will only post key extracts in this answer. You can get the full project from GitHub: https://github.com/gratiartis/multids-demo
The demo sets up two JPA entities:
#Entity public class Foo { /* Constructors, fields and accessors/mutators */ }
#Entity public class Bar { /* Constructors, fields and accessors/mutators */ }
Associated with these we will create two repositories. Thanks to the awesomeness of Spring Data, we can get ourselves some pretty full-featured repositories purely by defining interfaces which extend JpaRepository:
public interface FooRepository extends JpaRepository<Foo, Long> {}
public interface BarRepository extends JpaRepository<Bar, Long> {}
Now we need to ensure that each of these maps to a table in its own database.
To achieve this, we will need two separate entity managers, each of which has a different datasource. However, in a Spring Java config #Configuration class, we can only have one #EnableJpaRepositories annotation and each such annotation can only reference one EntityManagerFactory. To achieve this, we create two separate #Configuration classes: FooConfig and BarConfig.
Each of these #Configuration classes will define a DataSource based on an embedded HSQL database:
#Bean(name = "fooDataSource")
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder()
.setName("foodb").setType(EmbeddedDatabaseType.HSQL).build();
}
#Bean(name = "barDataSource")
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder()
.setName("bardb").setType(EmbeddedDatabaseType.HSQL).build();
}
#Bean(name = "barEntityManagerFactory")
public EntityManagerFactory entityManagerFactory() {
LocalContainerEntityManagerFactoryBean lef =
new LocalContainerEntityManagerFactoryBean();
lef.setDataSource(dataSource());
lef.setJpaVendorAdapter(jpaVendorAdapter);
lef.setPackagesToScan("com.sctrcd.multidsdemo.domain.bar");
lef.setPersistenceUnitName("barPersistenceUnit");
lef.afterPropertiesSet();
return lef.getObject();
}
#Bean(name = "fooEntityManagerFactory")
public EntityManagerFactory entityManagerFactory() {
LocalContainerEntityManagerFactoryBean lef =
new LocalContainerEntityManagerFactoryBean();
lef.setDataSource(dataSource());
lef.setJpaVendorAdapter(jpaVendorAdapter);
lef.setPackagesToScan("com.sctrcd.multidsdemo.domain.foo");
lef.setPersistenceUnitName("fooPersistenceUnit");
lef.afterPropertiesSet();
return lef.getObject();
}
Each configuration should define an EntityManagerFactory, as above, which references its own dataSource() #Bean method. It also defines a path to the #Entity beans which it manages. You need to make sure that #Entity beans for different data sources are in different packages.
At this point it's worth noting that if each of these configurations uses the default namings for key persistence beans (i.e. entityManagerFactory), then Spring will see that there are two beans with the EntityManager interface, both of which have the same name. So one will be chosen. This leads to errors such as:
Not an managed type: class com.sctrcd.multidsdemo.domain.bar.Bar
This can be seen in the branch of the demo project here: https://github.com/gratiartis/multids-demo/tree/1-unnamed-entitymanager-beans
This is because in that example, Spring has wired up the beans relating to the "foodb" database, and Bar is not an entity in that database. Unfortunately the BarRepository has been wired up with the Foo entity manager.
We resolve this issue by naming all our beans in each of config class. i.e.
#Bean(name = "fooDataSource") public DataSource dataSource() { .. }
#Bean(name = "fooEntityManager") public EntityManager entityManager() { .. }
At this point if you were to run the tests in the project, you might see warnings such as:
No bean named 'entityManagerFactory' is defined.
This is because ... drumroll ... we do not have an EntityManagerFactory with the default name "entityManagerFactory". We have one called "fooEntityManagerFactory" and another called "barEntityManagerFactory". Spring is looking for something with a default name, so we need to instruct it to wire things up differently.
As it turns out, this is incredibly simple to do. We just need to put the correct references in the #EnableJpaRepositories annotation for each #Configuration class.
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(
entityManagerFactoryRef = "fooEntityManagerFactory",
transactionManagerRef = "fooTransactionManager",
basePackages = {"com.sctrcd.multidsdemo.integration.repositories.foo"})
public class FooConfig {
// ...
}
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(
entityManagerFactoryRef = "barEntityManagerFactory",
transactionManagerRef = "barTransactionManager",
basePackages = { "com.sctrcd.multidsdemo.integration.repositories.bar" })
public class BarConfig {
// ...
}
As you can see, each of these #EnableJpaRepositories annotations defines a specific named EntityManagerFactory and PlatformTransactionManager. They also specify which repositories should be wired up with those beans. In the example, I have put the repositories in database-specific packages. It is also possible to define each individual repository by name, by adding includeFilters to the annotation, but by segregating the repositories by database, I believe that things should end up more readable.
At this point you should have a working application using Spring Data repositories to manage entities in two separate databases. Feel free to grab the project from the link above and run the tests to see this happening. Hopefully this answer is useful to more folks, as I have spent a decent amount of time working out to do this as cleanly as possible with as little code as I could manage. Any ideas for improvement of the answer or demo project are welcome.
You may try put it on two #Configuration classes (one #EnableJpaRepositories per #Configuration).

Can I create a prototype scoped bean with Spring Javaconfig?

The old docs for Spring Javaconfig say that I can use
#Bean(scope=DefaultScopes.PROTOTYPE)
to get a prototype bean, but Spring 3.0.5's #Bean doesn't seem to have this property.
Is there any way to control the scope of a bean in Javaconfig?
Use #Scope instead.
Also, DefaultScopes is not available in Spring core, but you can use BeanDefinition.SCOPE_PROTOTYPE and BeanDefinition.SCOPE_SINGLETON for convenience.
You can add #Scope("prototype") for example:
#Bean
#Scope("prototype")
public DemoDao getDao() {
DemoDao dao = new DemoDao();
dao.setAddress("annoted:address");
dao.setName("annoted:name");
return dao;
}
Use the following for Java config,
#Bean
#Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public SpringBean springBean(){
SpringBean bean = new SpringBean();
return bean;
}
Or simply,
#Scope(value = "prototype")
Refer #Scope annotation

Categories

Resources