Unresolvable circular reference with #RefreshScope on #Configuration or #SpringBootApplication - spring

I'm trying to get the refreshed value of my property apiKey, after modifying it and requesting the /refresh endpoint.
For some reason my bean is unable to get the refreshed value even when annotated with #RefreshScope. I added #RefreshScope on my class as I did for my DatasourceConfig but in this case I'm getting this error :
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.application': Initialization of bean failed;
nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.application.initTimestamp.transformer.handler': Invocation of init method failed;
nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'scopedTarget.application': Requested bean is currently in creation: Is there an unresolvable circular reference?
Description:
The dependencies of some of the beans in the application context form a cycle:
┌─────┐
| scopedTarget.application
└─────┘
Here is my Application.java :
#SpringBootApplication
#EnableConfigServer
#EnableSwagger2
#RefreshScope
public class Application{
#Value("${api.key}")
private String apiKey;
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Autowired
private IMonitoringsService monitoringsService;
#Bean
public MessageChannel initTimestampChannel() {
return new DirectChannel();
}
#RefreshScope
#Bean
#InboundChannelAdapter(value = "initTimestampChannel", poller = #Poller(fixedRate = "${start.task.rate}"))
public MessageSource<?> buildRequestMessageSource() {
MethodInvokingMessageSource source = new MethodInvokingMessageSource();
source.setObject(tasksService);
source.setMethodName("requestAllTasks");
System.out.println(apiKey);
return source;
}
}
Yet it's working for my DatasourceConfig :
#RefreshScope
#Configuration
public class DatasourceConfig {
#Value("${spring.datasource.tomcat.max-active}")
private int maxActive;
#RefreshScope
#ConfigurationProperties(prefix = "spring.datasource")
#Bean
public DataSource dataSource() {
DataSource dataSource = DataSourceBuilder.create().build();
org.apache.tomcat.jdbc.pool.DataSource ds = (org.apache.tomcat.jdbc.pool.DataSource) dataSource;
ds.setMaxActive(maxActive);
return ds;
}
}
I'm using :
<spring-cloud.version>Edgware.SR2</spring-cloud.version>
<spring-boot-version>1.5.9.RELEASE</spring-boot-version>

As spencergibb suggested, you shouldn't put #SpringBootApplication and #RefreshScope on the same class. Remove #RefreshScope from Application and move the configuration that needs #RefreshScope to a separate class.

Related

Confusion about "No qualifying bean of type...RedisConnectionFactory"

Since the different configs, I have written two LettuceConnectionFactory:
ItemFactoryConfig
ActivityFactoryConfig
the code as follows:
#Configuration
#PropertySource(value = "classpath:config/redis.properties", encoding = "UTF-8")
public class ItemFactoryConfig {
#Value("${item.host}")
private String host;
#Value("${item.port}")
private int port;
#Bean
public LettuceConnectionFactory itemFactory(){
RedisStandaloneConfiguration redisConfiguration = new RedisStandaloneConfiguration();
redisConfiguration.setHostName(host);
redisConfiguration.setPort(port);
return new LettuceConnectionFactory(redisConfiguration);
}
}
#Configuration
#PropertySource(value = "classpath:config/redis.properties", encoding = "UTF-8")
public class ActivityFactoryConfig {
#Value("${activity.host}")
private String host;
#Value("${activity.port}")
private int port;
#Bean
public LettuceConnectionFactory activityFactory(){
RedisStandaloneConfiguration redisConfiguration = new RedisStandaloneConfiguration();
redisConfiguration.setHostName(host);
redisConfiguration.setPort(port);
return new LettuceConnectionFactory(redisConfiguration);
}
}
And I added #Qualifier when these LettuceConnectionFactories were autowired.
#Configuration
public class ItemTemplateConfig {
#Autowired
#Qualifier("itemFactory")
private LettuceConnectionFactory itemFactory;
#Bean
public RedisTemplate<String, String> itemTemplate(){...}
}
#Configuration
public class ActivityTemplateConfig {
#Autowired
#Qualifier("activityFactory")
private LettuceConnectionFactory activityFactory;
#Bean
public RedisTemplate<String, String> activityTemplate(){...}
}
However, spring boot still report the NoUniqueBeanDefinitionException.
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'org.springframework.data.redis.connection.RedisConnectionFactory' available: expected single matching bean but found 2: activityFactory,itemFactory
Spring boot Description:
Parameter 0 of method redisTemplate in org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration required a single bean, but 2 were found:
- activityFactory: defined by method 'activityFactory' in class path resource [com/lyf/redisdemo/config/Activity/ActivityFactoryConfig.class]
- itemFactory: defined by method 'itemFactory' in class path resource [com/lyf/redisdemo/config/Item/ItemFactoryConfig.class]
Action:
Consider marking one of the beans as #Primary, updating the consumer to accept multiple beans, or using #Qualifier to identify the bean that should be consumed
spring boot: 2.1.0.RELEASE

Autowireing of Qualified Datasource not working

I have a SpringBoot 2.0.4 app, and I am using JdbcTemplates. I had it all working, when I got a requirement to do a data transfer between 2 DBs.
So I set up 2 Data Sources like this:
#Configuration
public class OracleConfiguration {
#Bean(name = "oracleDataSource")
#ConfigurationProperties(prefix = "oracle.datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
}
and my DAO is like this:
#Repository
#Component
public class personDao extends JdbcDaoSupport {
static final Logger logger = LoggerFactory.getLogger(CymNetworkDao.class);
#Autowired
public void setDs(#Qualifier("oracleDataSource") DataSource dataSource) {
setDataSource(dataSource);
}
public List<PersonBean> findAll() {
List<PersonBean> result = getJdbcTemplate().query("SELECT * FROM PERSON", new PersonRowMapper());
return result;
}
}
I am getting this error:
Unsatisfied dependency expressed through field 'jdbcTemplate';
nested exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException:
No qualifying bean of type 'org.springframework.jdbc.core.JdbcTemplate' available:
expected at least 1 bean which qualifies as autowire candidate. Dependency annotations:
{#org.springframework.beans.factory.annotation.Autowired(required=true), #org.springframework.beans.factory.annotation.Qualifier(value=oracleJdbcTemplate)}
My reading of tutorials was telling me to just autowire the datasource, and the jdbcTemplate would create itself. Am I qualifying wrong or something else?
you should create jdbcTemplate by injecting DataSource like following example
#Repository
public class personDao {
private JdbcTemplate oracleJdbcTemplate;
#Autowired
public void setDataSource(#Qualifier("oracleDataSource") DataSource dataSource) {
this.oracleJdbcTemplate = new JdbcTemplate(dataSource);
}
And in error message it clearly shows it was missing JdbcTemplate bean
#org.springframework.beans.factory.annotation.Qualifier(value=oracleJdbcTemplate)}

Spring boot test wrong configuration classes

I am trying to test my repository layer using Spring Boot 2.0.1 but when I run my test class, Spring tries to instantiate a Config class not from the test package.
Here is the test code:
TestConfig.class
#Configuration
#Import(value = {TestDatabaseConfig.class})
#Profile("local")
public class TestConfig {
}
TestDatabaseConfig.class
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(
entityManagerFactoryRef = "logEntityManagerFactory",
transactionManagerRef = "logTransactionManager",
basePackages = { "it.xxx.yyy.repository.log" })
#EntityScan(basePackages = {"it.xxx.yyy.model.log", "it.xxx.yyy.common"})
#Profile("local")
public class TestDatabaseConfig {
#Bean("logDataSourceProperties")
public DataSourceProperties logDataSourceProperties() {
return new DataSourceProperties();
}
#Bean(name = "logDataSource")
public DataSource dataSource(#Qualifier("logDataSourceProperties") DataSourceProperties properties) {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.addScript("classpath:schema.sql")
.build();
}
#Bean(name = "logEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean logEntityManagerFactory(EntityManagerFactoryBuilder builder,
#Qualifier("logDataSource") DataSource logDataSource) {
return builder.dataSource(logDataSource)
.packages("it.xxx.model.log")
.persistenceUnit("log")
.build();
}
#Bean(name = "logTransactionManager")
public PlatformTransactionManager logTransactionManager(#Qualifier("logEntityManagerFactory")EntityManagerFactory logEntityManagerFactory) {
return new JpaTransactionManager(logEntityManagerFactory);
}
}
When I run this class
#RunWith(SpringRunner.class)
#SpringBootTest
#ActiveProfiles("local")
public class LogRepositoryTest {
#Autowired
private ResultLogRepository resultLogRepository;
#Test
public void init(){
}
}
it says :
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'kafkaProducer': Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'kafka.topic.operation' in value "${kafka.topic.operation}"
[...]
Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'kafka.topic.operation' in value "${kafka.topic.operation}"
But I cannot understand why it brings up my KafkaProducer.class from my main package (that has #Configuration annotation on it).
In your LogRepositoryTest test class you should indicate the alternate test configuration class that should be taken into account, in your case I think should be the TestConfig.
From Spring Boot documentation:
If you are familiar with the Spring Test Framework, you may be used to using #ContextConfiguration(classes=…​) in order to specify which Spring #Configuration to load. Alternatively, you might have often used nested #Configuration classes within your test.
So annotate LogRepositoryTest with #ContextConfiguration(classes = {TestConfig.class})
#RunWith(SpringRunner.class)
#SpringBootTest
#ActiveProfiles("local")
#ContextConfiguration(classes = {TestConfig.class})
public class LogRepositoryTest {
#Autowired
private ResultLogRepository resultLogRepository;
#Test
public void init(){
}
}
UPDATE
Also annotate your configuration class with:
#EnableAutoConfiguration
Something like:
#Configuration
#EnableAutoConfiguration
#EnableTransactionManagement
#EnableJpaRepositories(
entityManagerFactoryRef = "logEntityManagerFactory",
transactionManagerRef = "logTransactionManager",
basePackages = { "it.xxx.yyy.repository.log" })
#EntityScan(basePackages = {"it.xxx.yyy.model.log", "it.xxx.yyy.common"})
#Profile("local")
public class TestDatabaseConfig {
//...
}
UPDATE 2
For error:
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'org.springframework.boot.autoconfigure.jdbc.DataSourceProperties' available: expected single matching bean but found 2: logDataSourceProperties,spring.datasource-org.springframework.boot.autoconfigure.jdbc.DataSourceProperties
Completely remove the method:
#Bean("logDataSourceProperties")
public DataSourceProperties logDataSourceProperties() {
return new DataSourceProperties();
}
and change your:
#Bean(name = "logDataSource")
public DataSource dataSource(#Qualifier("logDataSourceProperties") DataSourceProperties properties) {
// ...
}
to:
#Bean(name = "logDataSource")
public DataSource dataSource(DataSourceProperties properties) {
// ...
}

MongoDB and Spring JPA integration is throwing error

I am trying to integrate Spring JPA with MongoDB. My intention is to just retrieve data from mongo DB. I am getting the below error while injecting my repository.
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'mongoService': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.org.coop.society.data.mongo.repositories.MaterialMasterRepository com.org.coop.security.service.MongoService.materialMasterRepository; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'materialMasterRepository': Invocation of init method failed; nested exception is java.lang.AbstractMethodError
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:334)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1210)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:537)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
My configuration snippet is given below.
TestMongoDBConfig.java
#Configuration
#EnableMongoRepositories(basePackages = {"com.abc.data.mongo.repositories"})
#ComponentScan(basePackages = "com.abc")
#PropertySource("classpath:applicationTest.properties")
public class TestMongoDBConfig extends AbstractMongoConfiguration {
#Autowired
private Environment env;
#Override
protected String getDatabaseName() {
return "retail";
}
#Override
#Bean
public MongoClient mongo() throws Exception {
MongoClient client = new MongoClient("localhost", 27017);
return client;
}
#Override
protected String getMappingBasePackage() {
return "com.abc.data.mongo.entities";
}
#Bean
public MongoTemplate mongoTemplate() throws Exception {
return new MongoTemplate(mongo(), getDatabaseName());
}
}
MaterialMaster.java in com.abc.data.mongo.entities package
#Document(collection = "materialMaster")
public class MaterialMaster {
#Id
private Long materialId;
#Field
private String name;
MaterialMasterRepository.java in com.abc.data.mongo.repositories package
public interface MaterialMasterRepository extends MongoRepository<MaterialMaster, Long> {
}
MongoService.java in com.abc.service package
#Service
public class MongoService {
#Autowired
private MaterialMasterRepository materialMasterRepository;
public void getMaterials() {
List<MaterialMaster> materials = materialMasterRepository.findAll();
System.out.println(materials);
}
}
Junit class looks like below
#RunWith(SpringJUnit4ClassRunner.class)
#ComponentScan(basePackages = "com.abc")
#ContextHierarchy({
#ContextConfiguration(classes={TestMongoDBConfig.class})
})
public class ModuleWSTest {
#Autowired
private MongoService mongoService;
#Test
public void testModule() {
mongoService.getMaterials();
}
}
I have tried all possible changes (as per my knowledge) but no luck. Any help is really appreciated.
The error message is little confusing. I was using latest spring-data-mongodb (1.8.4.RELEASE). Once I downgraded the dependency to 1.6.0.RELEASE then the above configuration started working.

Unable to autowire dozer Mapper in component class in spring boot

I am new to Spring Boot. I was trying to develop small application in spring boot mvc with neo4j database. Following is my Server
#Configuration
#ComponentScan({ "myproject" })
#EnableAutoConfiguration
#EnableNeo4jRepositories(basePackages = "myproject")
public class Server extends Neo4jConfiguration implements CommandLineRunner
{
public Server()
{
setBasePackage("myproject");
}
#Bean
SpringRestGraphDatabase graphDatabaseService()
{
return new SpringRestGraphDatabase("http://localhost:7474/db/data");
}
#Bean
Mapper mapper()
{
return new DozerBeanMapper();
}
public void run(String... args) throws Exception
{
}
public static void main(String[] args) throws Exception
{
SpringApplication.run(Server.class, args);
}
}
Following is my main class
#Configuration
#ComponentScan({ "myproject.business" })
#EnableNeo4jRepositories(basePackages = "myproject")
public class MainWithStructure extends Neo4jConfiguration implements CommandLineRunner
{
#Autowired
private MyService myService;
public MainWithStructure()
{
setBasePackage("myproject");
}
#Bean
SpringRestGraphDatabase graphDatabaseService()
{
return new SpringRestGraphDatabase("http://localhost:7474/db/data");
}
.......
......
public static void main(String[] args) throws Exception
{
FileUtils.deleteRecursively(new File("accessingdataneo4j.db"));
SpringApplication app = new SpringApplication(MainWithStructure.class);
app.setWebEnvironment(false);
app.run(args);
}
}
Following is my Component class
#Component
public class MyService
{
#Autowired
private Mapper mapper; //Fails to autowire org.dozer.Mapper
.....
}
Following is my Controller class
#RestController
#RequestMapping("/rest")
public class MyController
{
#Autowired
private Mapper mapper; //autowire sucess org.dozer.Mapper
}
I got following Exception when I run main class MainWithStructure
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'mainWithStructure': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private myproject.business.MyService myproject.main.MainWithStructure.MyService; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'myService': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private org.dozer.Mapper myproject.business.MyService.mapper; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.dozer.Mapper] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
Following is my project structure
demo_project
src/main/java
---myproject.main
------MainWithStructure.java
------Server.java
---myproject.business
------MyService.java
---myproject.rest
------MyController.java
If I autowire org.dozer.Mapper in Controller, it sucessfuly autowired it. BUT if I autowire org.dozer.Mapper in Component class it fails to autowire.
Why it is failing to autowire org.dozer.Mapper only on Component class?
Please make me correct if I wrong. Thank you :)
Your Server is not in one of the packages that you #ComponentScan, so the Mapper is indeed not a bean. Try removing the explicit package from the #ComponentScan (since everything is in a subpackage of the main class that will pick up all the components).
You can add #SpringBootApplication in your main class which has #ComponentScan
which will scan all your sub components in project.

Resources