spring boot multiple data sources - spring-boot

I was trying to follow this link to configure two databases in my application.
In the latest spring we don't have org.springframework.boot.autoconfigure.jdbc.TomcatDataSourceConfiguration class.
What is the alternative for this to use.
I am using gradle for my spring boot application

I prefer using "org.apache.tomcat.jdbc.pool.DataSource", and then configure my data sources manually.
org.apache.tomcat.jdbc.pool.DataSource dataSource = new org.apache.tomcat.jdbc.pool.DataSource();
I set the fully qualified name, because you should return "javax.sql.DataSource" from whichever factory method you make.
Getting multiple data sources with spring-boot auto configuration is a pan, since the opinionated view is that you should just create a different service for each data source.
That is not always possible, so here's everything I do when I need multiple DataSources in a single application.
Disable the auto configuration like so:
#SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
public class YourApp{}
Create a configuration properties for your datasources:
Properties file:
the-first.datasource.url=<insert value>
the-first.datasource.username=<insert value>
the-first.datasource.pw=<insert value>
the-first.datasource.min-idle=<insert value>
the-first.datasource.max-idle=<insert value>
the-first.datasource.max-active=<insert value>
the-first.datasource.validation-query=SELECT 1
# etc ...
the-second.datasource.url=<insert value>
the-second.datasource.username=<insert value>
the-second.datasource.pw=<insert value>
the-second.datasource.min-idle=<insert value>
the-second.datasource.max-idle=<insert value>
the-second.datasource.max-active=<insert value>
the-second.datasource.validation-query=SELECT 1
Configuration class:
import lombok.*;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#Component("theFirstDataSourceProperties")
#ConfigurationProperties("the-first.datasource")
public class TheFirstDataSourceProperties{
#NonNull
private String password;
#NonNull
private String url;
#NonNull
private String username;
private int minIdle;
private int maxIdle;
private int maxActive;
#NonNull
private String driverClassName;
#NonNull
private String validationQuery;
}
Add a data source configuration class:
Be sure and mark one of them as the "#Primary" to help with injection.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;
/**
* Copyright ${year}
*
* #author J. Keith Hoopes
*/
#Configuration
public class ExampleOfMultipleDataSourceConfiguration{
#Bean(name = "theFirstDataSource")
#Primary
#Autowired
public DataSource theFirstDataSource(
TheFirstDataSourceProperties theFirstDataSourceProperties){
//Fully qualified to not conflict with generic DataSource
org.apache.tomcat.jdbc.pool.DataSource dataSource = new org.apache.tomcat.jdbc.pool.DataSource();
// General
dataSource.setName("theFirstDataSourceName");
dataSource.setDriverClassName(theFirstDataSourceProperties.getDriverClassName());
// etc ....
return dataSource;
}
#Bean(name = "bDataSource")
#Autowired
public DataSource theSecondDataSource(
TheSecondDataSourceProperties theSecondDataSourceProperties){
//Fully qualified to not conflict with generic DataSource
org.apache.tomcat.jdbc.pool.DataSource dataSource = new org.apache.tomcat.jdbc.pool.DataSource();
// General
dataSource.setName("theSecondDataSourceName");
dataSource.setDriverClassName(theSecondDataSourceProperties.getDriverClassName());
// etc ....
return dataSource;
}
}
Inject your custom DataSources where needed using #Qualifier so you get the correct one:)
#Qualifier("theFirstDataSource")
Profit? Yes.
Oh, and here are the basic dependencies I use.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-metadata</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>net.sourceforge.jtds</groupId>
<artifactId>jtds</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>

Related

Unable to get table autocreated in spring module integration test

I have a parameters module in my project which other modules are dependent on. I'd like to write instegration tests for this module in separate manner. This module is a spring based one and has some db related logic, though db migration scripts are not available in this module since it is something that is out of its area of resposibility. By the way in-memory H2 instance is used for testing purposes.
What I'm trying to achieve is to make spring/hibernate create DB tables based on single #Entity class present in this module, it is called ParameterEntity.
It is defined like this:
#Entity
#Table(name = "SYSTEM_PARAMETERS")
public class ParameterEntity {
#Id
#Column(name = "id")
private String id;
#Column(name = "value")
private String value;
// accessors go here...
}
In my application-test.yml file I provide the following props:
spring:
jpa:
hibernate:
ddl-auto: create
database: h2
show-sql: true
And define integration test class like this:
#ExtendWith(SpringExtension.class)
#EnableConfigurationProperties
#EntityScan("path.to.package.where.parameter.entity.resides")
#ConstextConfiguration(initializers = ConfigFileApplicationContextInitializer.class)
#ActiveProfiles("test")
#TestInstance(Lifecycle.PER_CLASS)
public class ParametersIntegrationTest {
#Autowired
private ParameterWarden warden;
#BeforeEach
public void setUp() {
warden.initialize();
}
#Configuration
#ComponentScan("base.module.package")
static class TestConfiguration {
// here comes some test beans which will be used in testing purposes only
}
}
In #BeforeEach method ParameterWarden class calls repository class which in turn make some calls to database to retrieve parameter entities from database and these calls fail because SYSTEM_PARAMETERS is missing.
Could anyone, please, let me know what am I missing here and how can I make spring or hibernate create table based on the entity present in my project. Even the place where I can debug this would be nice to know.
It seems like I need another magical thing that will trigger this functionality but I was unable to figure out what exactly I need.
Any help is really appreciated, thank you very much for your time!
p.s. I can not use #SpringBootTest annotation since this module uses only some spring features and is not a spring boot application itself. It is used as a dependecy in another spring boot applications.
Can you still use #DataJpaTest?
package com.test;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit.jupiter.SpringExtension;
#ExtendWith(SpringExtension.class)
#DataJpaTest
#ContextConfiguration(classes = TestEntityRepository.class)
#TestPropertySource(properties = {
"spring.jpa.hibernate.ddl-auto=create",
"spring.datasource.platform=h2",
"spring.jpa.show-sql=true"
})
#EnableAutoConfiguration
public class IntegrationTest {
#Autowired
TestEntityRepository testEntityRepository;
#Test
void testCreateRead() {
var saved = testEntityRepository.save(new TestEntity("test"));
Assertions.assertNotNull(saved);
var read = testEntityRepository.findById(saved.getId());
Assertions.assertNotNull(read);
}
}
Where repository and entity in the com.test package are:
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
#Repository
public interface TestEntityRepository extends CrudRepository<TestEntity, Long> { }
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
#Entity
#Data
#NoArgsConstructor
public class TestEntity {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column
private Long id;
#Column
private String attr;
public TestEntity(String attr) {
this.attr = attr;
}
}
Dependecies used (through dependency management and Spring Boot BOM of version 2.3.4.RELEASE):
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
Alternatively, if you want to fully decouple tests from Spring you can use org.hibernate.tool.hbm2ddl.SchemaExport in some utility logic since that's what's really executing under the hood. I use this approach since my project requires some extra steps to setup the database, however, it might be too complicated for some use cases.

Spring Boot and Couchbase Connection Error

I am starting to learn spring boot and couchbase together, and implementing a simple custom query. However when I hit localhost:8889/agents/findByAgentId/14045, I got "this site can't be reached" error. What I missed here? I will appreciate any response. Thank you
here is the Entity Class
import com.sun.istack.internal.NotNull;
import lombok.*;
import org.springframework.data.annotation.Id;
import org.springframework.data.couchbase.core.mapping.Document;
import org.springframework.data.couchbase.core.mapping.Field;
#Document
#Setter
#Getter
#AllArgsConstructor
#NoArgsConstructor
#EqualsAndHashCode
public class Agent {
#Id
#NotNull
#Field
private String AgentLeaderId;
#Field
private String agentPreference;
#Field
private String agency;
#Field
private String mobilePhone;
}
Here is the Configuration Class
import org.springframework.context.annotation.Configuration;
import org.springframework.data.couchbase.config.AbstractCouchbaseConfiguration;
#Configuration
public class AgentConfig extends AbstractCouchbaseConfiguration {
#Override
public String getConnectionString() {
return ("127.0.0.1");
}
#Override
public String getUserName() {
return "******";
}
#Override
public String getPassword() {
return "*******";
}
#Override
public String getBucketName() {
return "******";
}
}
Here is the Repository
import com.bit.pruleads.entity.Agent;
import org.springframework.data.couchbase.core.query.N1qlPrimaryIndexed;
import org.springframework.data.couchbase.core.query.ViewIndexed;
import org.springframework.data.couchbase.repository.CouchbaseRepository;
import org.springframework.data.couchbase.repository.Query;
import org.springframework.stereotype.Repository;
import java.io.Serializable;
import java.util.List;
#Repository
#N1qlPrimaryIndexed
#ViewIndexed(designDoc = "primaryLeadsData")
public interface AgentRepository extends CouchbaseRepository<Agent, String > {
#Query("#{#n1ql.selectEntity} WHERE agentLeaderId = $1 AND #{#n1ql.filter}")
List<Agent> findByAgentId(String agentId);
#Query("#{#n1ql.selectEntity} WHERE mobilePhone = $1 AND #{#n1ql.filter}")
List<Agent> findAgentsByPhoneNumber(String phoneNumber);
}
Controller Class
import com.bit.pruleads.entity.Agent;
import com.bit.pruleads.repository.AgentRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
#RestController
public class AgentController {
#Autowired
private AgentRepository agentRepository;
public AgentController(AgentRepository agentRepository) {
this.agentRepository = agentRepository;
}
#PostMapping("/findByAgentId/{id}")
public List<Agent> findByAgentId(#PathVariable String id) {
return agentRepository.findByAgentId(id);
}
#PostMapping("/findAgentsByPhoneNumber/{phoneNumber}")
public List<Agent> findAgentByPhoneNumber(#PathVariable String phoneNumber) {
return agentRepository.findAgentsByPhoneNumber(phoneNumber);
}
}
Here is the pom file
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-couchbase</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
Here is the Application properties
#Server port
server.port =8889
Here is some of the Logs
No active profile set, falling back to default profiles: default
Bootstrapping Spring Data Couchbase repositories in DEFAULT mode.
Finished Spring Data repository scanning in 456ms.
Found 0 Couchbase
repository interfaces.
Bootstrapping Spring Data Couchbase repositories in DEFAULT mode.
Finished Spring Data repository scanning in 35ms.
Found 1 Couchbase repository interfaces.
Opened bucket "leads-data"
Started PruleadsApplication in 7.502 seconds (JVM running for 8.685)
Closed bucket "leads-data"
Node disconnected
Completed shutdown and closed all open buckets
Process finished with exit code 0
I think you need to have spring-boot-starter-web included in your pom. With no web server, spring-boot starts and finds it has nothing to do so it will just stop.
First of all, use this version instead:
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-couchbase</artifactId>
<version>4.1.1</version>
</dependency>
You will need to change a few imports, so check the documentation here: https://docs.spring.io/spring-data/couchbase/docs/current/reference/html/#reference
Remove the annotations #N1qlPrimaryIndexed and #ViewIndexed, they have been replacing by new annotations: https://docs.spring.io/spring-data/couchbase/docs/current/reference/html/#couchbase.repository.indexing
You don't need to create the indexes right now, just make sure that you have a primary index on your database and you should be able to get something up and running:
CREATE PRIMARY INDEX ON MY_BUCKET
Here is an example:
https://github.com/deniswsrosa/spring-data-couchbase-quickstart
Just Run the class "QuickStartCouchbase" and after the application startup, the method "run" inside "CmdRunner" should be called.

Appending custom conditions on spring data jpa repository method queries

Short Version
I am looking for a way to have all the findBy methods of a repository class appended with a particular condition
Full Version
Let's assume I have a Product entity and Customer entity. Both of them extends the OwnerAwareEntity and they inherit ownerRef field which identifies the owner of the entity( It could be a merchant or a partner ). I want to have the findBy methods of the Product and Customer modified in runtime such that they are appended with an additional condition of the ownerRef. The ownerRef value could be identified from the user session.
Example
The parent entity class that provides the common ownerRef field
public class OwnerAwareEntity implements Serializable {
private String ownerRef;
}
Customer entity extending OwnerAwareEntity
public class Customer extends OwnerAwareEntity {
private String firstname;
private String mobile ;
}
Product entity extending OwnerAwareEntity
public class Product extends OwnerAwareEntity {
private String code;
private String name;
}
Repository class for Product & Customer extending an OwnerAwareRepository
public interface OwnerAwareRepository extends JpaRepository {
}
public interface ProductRepository extends OwnerAwareRepository {
Product findByCode(String code );
}
public interface CustomerRepository extends OwnerAwareRepository {
Customer findByFirstname(String firstname );
}
This, when executed, should result in a query like below
select P from Product P where P.code=?1 and P.ownerRef='aValue'
&
select C from Customer C where C.firstname=?1 and C.ownerRef='aValue'
What should be my approach to have this appending of condition achieved?. I only want this appending to be happening when the parent repository is OwnerAwareRepository.
TL;DR: I used #Filter of Hibernate and then created an Aspect to intercept the methods
Defined a base class entity with the following structure
OwnerAwareEntity.java
import org.hibernate.annotations.Filter;
import org.hibernate.annotations.FilterDef;
import org.hibernate.annotations.ParamDef;
import javax.persistence.Column;
import javax.persistence.MappedSuperclass;
import java.io.Serializable;
#MappedSuperclass
#FilterDef(name = "ownerFilter", parameters = {#ParamDef(name = "ownerRef", type = "long")})
#Filter(name = "ownerFilter", condition = "OWNER_REF = :ownerRef")
public class OwnerAwareEntity implements Serializable{
#Column(name = "OWNER_REF",nullable = true)
private Long ownerRef;
}
We set the filter on this entity. The hibernate #Filter allows us to set a condition to be appended to the select where clause.
Next, defined a base repository for the entity of type OwnerAwareEntity
OwnerAwareRepository.java
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.NoRepositoryBean;
#NoRepositoryBean
public interface OwnerAwareRepository<T, ID extends java.io.Serializable> extends JpaRepository<T, ID> {
}
Created an Aspect that will intercept all the methods from the repositories that extend OwnerAwareRepository
OwnerFilterAdvisor.java
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.hibernate.Filter;
import org.hibernate.Session;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
#Aspect
#Component
#Slf4j
public class OwnerFilterAdvisor {
#PersistenceContext
private EntityManager entityManager;
#Pointcut("execution(public * com.xyz.app.repository.OwnerAwareRepository+.*(..))")
protected void ownerAwareRepositoryMethod(){
}
#Around(value = "ownerAwareRepositoryMethod()")
public Object enableOwnerFilter(ProceedingJoinPoint joinPoint) throws Throwable{
// Variable holding the session
Session session = null;
try {
// Get the Session from the entityManager in current persistence context
session = entityManager.unwrap(Session.class);
// Enable the filter
Filter filter = session.enableFilter("ownerFilter");
// Set the parameter from the session
filter.setParameter("ownerRef", getSessionOwnerRef());
} catch (Exception ex) {
// Log the error
log.error("Error enabling ownerFilter : Reason -" +ex.getMessage());
}
// Proceed with the joint point
Object obj = joinPoint.proceed();
// If session was available
if ( session != null ) {
// Disable the filter
session.disableFilter("ownerFilter");
}
// Return
return obj;
}
private Long getSessionOwnerRef() {
// Logic to return the ownerRef from current session
}
}
The advisor is set to intercept all the methods from classes that extends the OwnerAwareRepository. On the interception, the current hibernate Session is obtained from entityManager ( of current persistence context ) and the filter is enabled with the param value of "ownerRef".
Also have a configuration file created to have the advisor scanned
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
#Configuration
#ComponentScan(basePackages = {"com.xyz.app.advisors"})
public class AOPConfig {
}
Once these files are in place, you need to have the following things done for the entities that need to be owner aware
The entity needs to extend OwnerAwareEntity
The entity repository class need to extend OwnerAwareRepository
Dependencies
This setup requires the spring aop to be in the dependencies. You may add the following to the pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
Advantages
Works with all select queries ( findBy methods, findAll etc )
#Query methods also gets intercepted
Simple implementation
Caveats
The where clause of delete or update is not affected by
this filter.
If the repository contains a save/update/delete method and if the
method is not tagged as #Transactional, then interceptor will give
error ( You can catch and have the method proceed normally in these
cases)
You can use Predicate of QueryDSL (or Specification) in Spring Data JPA methods.
Example:
interface UserRepository extends CrudRepository<User, Long>, QueryDslPredicateExecutor<User> {
}
Predicate predicate = QUser.user.firstname.equalsIgnoreCase("dave")
.and(user.lastname.startsWithIgnoreCase("mathews"));
userRepository.findAll(predicate);
To work with QueryDSL add to you pom.xml:
<dependencies>
//..
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-jpa</artifactId>
<version>4.1.4</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
<version>4.1.4</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>com.mysema.maven</groupId>
<artifactId>apt-maven-plugin</artifactId>
<version>1.1.3</version>
<executions>
<execution>
<goals>
<goal>process</goal>
</goals>
<configuration>
<outputDirectory>target/generated-sources</outputDirectory>
<processor>com.querydsl.apt.jpa.JPAAnnotationProcessor</processor>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
Then compile your project and you will get Q-classes of your entities.
More info is here.

Override Spring-Boot's GsonAutoConfiguration with custom Gson

Is there a way to override the GsonAutoConfiguration in spring-boot?
I would like to add some typeAdapter to the gson instance.
Preferably using java configurations
I've added the following to the application.properties.
spring.http.converters.preferred-json-mapper=gson
and the following class
#Configuration
#ConditionalOnClass(Gson.class)
public class GsonConfig {
#Bean
public Gson gson() {
return new GsonBuilder()
.registerTypeAdapter(DateTime.class, new DateTimeTypeAdapter())
.setPrettyPrinting().create();
}
}
I am also using Jersey in the mix as well.
So I've also have the following code, which also didn't work.
InternalApplication.java
import com.google.gson.GsonBuilder;
import java.util.HashSet;
import java.util.Set;
import javax.ws.rs.core.Application;
import org.immutables.gson.stream.GsonMessageBodyProvider;
import org.immutables.gson.stream.GsonProviderOptionsBuilder;
import org.joda.time.DateTime;
public class InternalApplication extends Application {
#Override
public Set<Class<?>> getClasses() {
final Set<Class<?>> classes = new HashSet<>();
classes.add(TestResource.class);
return classes;
}
#Override
public Set<Object> getSingletons() {
final Set<Object> singletons = new HashSet<>();
singletons.add(new GsonMessageBodyProvider(
new GsonProviderOptionsBuilder()
.gson(new GsonBuilder()
.registerTypeAdapter(DateTime.class, new DateTimeTypeAdapter())
.setPrettyPrinting()
.create())
.lenient(true)
.build()
)
);
return singletons;
}
}
Since when does Gson have anything to with Jersey in Spring Boot? It doesn't. What you really want to do is first disable Jackson (which is the default provider). Then you can register your GsonMessageBodyProvider.
Basically all you need to do is exclude the Jackson provider from your Maven/Gradle dependencies, as the Jersey starter pulls it in
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jersey</artifactId>
<exclusions>
<exclusion>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</exclusion>
<exclusion>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
</exclusion>
</exclusions>
</dependency>
And I'm not quite sure why you are using an Application class, as Spring Boot doesn't support that for its auto-configuration. You should be using a ResourceConfig class
#Component
#ApplicationPath("/api")
public class JerseyConfig extends ResourceConfig {
public JerseyConfig() {
register(TestResource.class);
register(new GsonMessageBodyProvider(...));
}
}

Spring #RefreshScope is not working with #Component

I've the component class and pom.xml dependencies like below. The properties are never set and staying as null.
#Component
#RefreshScope
public class SecurityProperties1 {
#Value("${ad.url}")
public String adUrl;
#Value("${ad.manager.dn}")
public String managerDN;
#Value("${ad.manager.password}")
public String managerPassword;
#Value("${ad.search.base}")
public String searchBase;
#Value("${ad.user.filter}")
public String userFilter;
}
pom.xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
<version>1.2.1.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-commons -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-commons</artifactId>
<version>1.1.4.RELEASE</version>
</dependency>
Also,
My Property source is like below
#Component
public class CustomPropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer {
#Override
protected String resolvePlaceholder(String placeholder, Properties props) {
return DynamicProperty.getProperty(placeholder);
}
#Override
protected String resolvePlaceholder(String placeholder, Properties props, int systemPropertiesMode) {
return DynamicProperty.getProperty(placeholder);
}
}
I had same problem. My solution: I added proxymode = default annotation
#Component
#RefreshScope(proxyMode = DEFAULT)
public class MyClass {
#Value("${test.value}")
private String testValue;
}
For newer version if somebody is facing this issue :
Make sure you have spring-cloud-starter-bootstrap dependency in classpath and also add spring.application.name property in your bootstrap.properties file
And annotated each class that is getting property from config server with #RefreshScope

Resources