Spring Load Balancer, RestTemplate, and Microservices issue - spring

Following this post, I configured
(1) a Eureka Server,
(2) a toll rate service which is a client of (1),
(3) a toll rate dashboard which read data from (2).
It went well until I made some changes using #LoadBalanced (maybe it is not exactly due to load balancer, but I'll post related code chunks below)
In bootstrap.properties in (2), the common endpoint name is
spring.application.name = demo-tollrate-service
In DashboardController.java in (3), as you can see the HTTP address is changed to above application name
// import some libraries
#Controller
public class DashboardController {
#Autowired
private RestTemplate restTemplate;
#LoadBalanced
#Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder.build();
}
#RequestMapping("/dashboard")
public String GetTollRate(#RequestParam int stationId, Model m) {
TollRate tr = restTemplate.getForObject("http://demo-tollrate-service/tollrate/" + stationId, TollRate.class);
m.addAttribute("rate", tr.getCurrentRate());
return "dashboard";
}
}
The pom.xml is roughly the same in this post
When running this app, I got the below errors.
***************************
APPLICATION FAILED TO START
***************************
Description:
The dependencies of some of the beans in the application context form a cycle:
┌──->──┐
| dashboardController (field private org.springframework.web.client.RestTemplate com.example.demo.DashboardController.restTemplate)
└──<-──┘
Action:
Relying upon circular references is discouraged and they are prohibited by default. Update your application to remove the dependency cycle between beans. As a last resort, it may be possible to break the cycle automatically by setting spring.main.allow-circular-references to true.
Can anyone please help me here? Thank you.

It has a circular dependency, the DashboardController depends on the RestTemplate, but the RestTemplate is defined inside the DashboardController.
The Java version does not make any difference, but maybe the Spring version. The new Spring version is not allowing circular references by default. You can change that adding a property in the application.properties file, here you can find more details:
https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.6-Release-Notes#circular-references-prohibited-by-default
But I recommend a refactor, there is no good reason to define the RestTemplate inside the controller, it is much better to do it in a #Configuration class.

Spring 101: You can’t define beans in a controller class. Move RestRemplate definition to a #Configuration class or to your application main class.

Related

Use Micrometer with OpenFeign in spring-boot application

The OpenApi documentation says that it supports micrometer. How does the integration works? I could not find anything except this little documentation.
I have a FeignClient in a spring boot application
#FeignClient(name = "SomeService", url = "xxx", configuration = FeignConfiguration.class)
public interface SomeService {
#GET
#Path("/something")
Something getSomething();
}
with the configuration
public class FeignConfiguration {
#Bean
public Capability capability() {
return new MicrometerCapability();
}
}
and the micrometer integration as a dependency
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-micrometer</artifactId>
<version>10.12</version>
</dependency>
The code makes a call but I could not find any new metrics via the actuator overview, expecting some general information about my HTTP requests. What part is missing?
Update
I added the support for this to spring-cloud-openfeign. After the next release (2020.0.2), if micrometer is set-up, the only thing you need to do is putting feign-micrometer onto your classpath.
Old answer
I'm not sure if you do but I recommend to use spring-cloud-openfeign which autoconfigures Feign components for you. Unfortunately, it seems it does not autoconfigure Capability (that's one reason why your solution does not work) so you need to do it manually, please see the docs how to do it.
I was able to make this work combining the examples in the OpenFeign and Spring Cloud OpenFeign docs:
#Import(FeignClientsConfiguration.class)
class FooController {
private final FooClient fooClient;
public FooController(Decoder decoder, Encoder encoder, Contract contract, MeterRegistry meterRegistry) {
this.fooClient = Feign.builder()
.encoder(encoder)
.decoder(decoder)
.contract(contract)
.addCapability(new MicrometerCapability(meterRegistry))
.target(FooClient.class, "https://PROD-SVC");
}
}
What I did:
Used spring-cloud-openfeign
Added feign-micrometer (see feign-bom)
Created the client in the way you can see above
Importing FeignClientsConfiguration and passing MeterRegistry to MicrometerCapability are vital
After these, and calling the client, I had new metrics:
feign.Client
feign.Feign
feign.codec.Decoder
feign.codec.Decoder.response_size

Spring boot test mutliple projects with same bean name

I have multiple spring projects as part of a single umbrella project. Two of them are AuthServer and BackendApplication. AuthServer, as name suggests is used only for auth purposes and rest is handled by BackendApplication. Now I am trying to write tests inside BackendApplication that also need to use auth related work. For that I have added AuthServer as a test dependency to BackendApplication. Now the problem is that, both projects have beans names Utility because of which I get DuplicateBeanException when I am including both contexts in my test. But I can disable any of them as they are necessary. Is there a way around it?
Could you name your beans, for example:
#Bean(name = "my-utility-1")
public Utility createUtility1() {
return new Utility();
}
// or
#Component(value = "my-utility-2")
public class Utility {
...
}
and refer to them by #Qualified
#Autowired #Qualified("my-utility-1")
private Utility myUtility;
Not related to your question, but i think you can mock AuthServer when testing BackendApplication.

Reload property value when external property file changes ,spring boot

I am using spring boot, and I have two external properties files, so that I can easily change its value.
But I hope spring app will reload the changed value when it is updated, just like reading from files. Since property file is easy enough to meet my need, I hope I don' nessarily need a db or file.
I use two different ways to load property value, code sample will like:
#RestController
public class Prop1Controller{
#Value("${prop1}")
private String prop1;
#RequestMapping(value="/prop1",method = RequestMethod.GET)
public String getProp() {
return prop1;
}
}
#RestController
public class Prop2Controller{
#Autowired
private Environment env;
#RequestMapping(value="/prop2/{sysId}",method = RequestMethod.GET)
public String prop2(#PathVariable String sysId) {
return env.getProperty("prop2."+sysId);
}
}
I will boot my application with
-Dspring.config.location=conf/my.properties
I'm afraid you will need to restart Spring context.
I think the only way to achieve your need is to enable spring-cloud. There is a refresh endpoint /refresh which refreshes the context and beans.
I'm not quite sure if you need a spring-cloud-config-server (its a microservice and very easy to build) where your config is stored(Git or svn). Or if its also useable just by the application.properties file in the application.
Here you can find the doc to the refresh scope and spring cloud.
You should be able to use Spring Cloud for that
Add this as a dependency
compile group: 'org.springframework.cloud', name: 'spring-cloud-starter', version: '1.1.2.RELEASE'
And then use #RefreshScope annotation
A Spring #Bean that is marked as #RefreshScope will get special treatment when there is a configuration change. This addresses the problem of stateful beans that only get their configuration injected when they are initialized. For instance if a DataSource has open connections when the database URL is changed via the Environment, we probably want the holders of those connections to be able to complete what they are doing. Then the next time someone borrows a connection from the pool he gets one with the new URL.
Also relevant if you have Spring Actuator
For a Spring Boot Actuator application there are some additional management endpoints:
POST to
/env to update the Environment and rebind #ConfigurationProperties and log levels
/refresh for re-loading the boot strap context and refreshing the #RefreshScope beans
Spring Cloud Doc
(1) Spring Cloud's RestartEndPoint
You may use the RestartEndPoint: Programatically restart Spring Boot application / Refresh Spring Context
RestartEndPoint is an Actuator EndPoint, bundled with spring-cloud-context.
However, RestartEndPoint will not monitor for file changes, you'll have to handle that yourself.
(2) devtools
I don't know if this is for a production application or not. You may hack devtools a little to do what you want.
Take a look at this other answer I wrote for another question: Force enable spring-boot DevTools when running Jar
Devtools monitors for file changes:
Applications that use spring-boot-devtools will automatically restart
whenever files on the classpath change.
Technically, devtools is built to only work within an IDE. With the hack, it also works when launched from a jar. However, I may not do that for a real production application, you decide if it fits your needs.
I know this is a old thread, but it will help someone in future.
You can use a scheduler to periodically refresh properties.
//MyApplication.java
#EnableScheduling
//application.properties
management.endpoint.refresh.enabled = true
//ContextRefreshConfig.java
#Autowired
private RefreshEndpoint refreshEndpoint;
#Scheduled(fixedDelay = 60000, initialDelay = 10000)
public Collection<String> refreshContext() {
final Collection<String> properties = refreshEndpoint.refresh();
LOGGER.log(Level.INFO, "Refreshed Properties {0}", properties);
return properties;
}
//add spring-cloud-starter to the pom file.
Attribues annotated with #Value is refreshed if the bean is annotated with #RefreshScope.
Configurations annotated with #ConfigurationProperties is refreshed without #RefreshScope.
Hope this will help.
You can follow the ContextRefresher.refresh() code implements.
public synchronized Set<String> refresh() {
Map<String, Object> before = extract(
this.context.getEnvironment().getPropertySources());
addConfigFilesToEnvironment();
Set<String> keys = changes(before,
extract(this.context.getEnvironment().getPropertySources())).keySet();
this.context.publishEvent(new EnvironmentChangeEvent(context, keys));
this.scope.refreshAll();
return keys;
}

Add property to entity in spring data REST

I am trying out the ResourceProcessor interface in Spring Data REST. I don't think my Processor ever gets called. No error message either.
Here is my processor (in Groovy):
#Autowired
PersonService personService
#Override
public Resource<Person> process(Resource<Person> resource) {
resource.content.isAdult = personService.isAdult(resource.content)
// sanity check: does this link get added?? (NOPE!!)
resource.add(new Link("http://localhost:8080/people", "added-link"))
log.info "## resource.content.isAdult ==> ${resource.content}"
return resource
}
Any help would be most appreciated!! You can see the entire project here in GitHub: https://github.com/txiasummer/spring-data-rest-examples
Finally got it to work! It turns out to be something completely trivial and I can't believe I missed it. I have a PersonProcessor classes which implements Spring's native ResourceProcessor interface. But PersonProcessor is still just a basic class that must be injected by Spring!! I think I was getting it confused with #Projection, which will be recognized automatically and does not need to be injected explicitly.
I addd #ComponentScan to my Application.groovy and now everything is working swimmingly. Alternatively, you an also manually define the PersonProcessor class and its service PersonService class as #Bean in Application.groovy. Again, you can see the whole project here: https://github.com/txiasummer/spring-data-rest-examples

Need matching class for LoggersMvcEndpoint. in spring-boot 2.1.9 release

I am upgrading my project from spring-boot 1.5.12.release to 2.1.9.release. I am unable to find LoggersMvcEndpoint (https://docs.spring.io/spring-boot/docs/1.5.12.RELEASE/api/org/springframework/boot/actuate/endpoint/mvc/LoggersMvcEndpoint.html) in latest version.
In one of my controller I had this. Can some one help me to fix this.
public class LoggerController extends CloudRestTemplate {
#Autowired
LoggersMvcEndpoint loggerAPI;
#Override
public Object getFromInternalApi(final String param) {
return StringUtils.isEmpty(param) ? loggerAPI.invoke() : loggerAPI.get(param);
}
#Override
public Object postToInternalApi(final String param, final Object request) {
return loggerAPI.set(param, (Map<String, String>) request);
}
}
As per Spring docs here
Endpoint infrastructure
Spring Boot 2 brings a brand new endpoint
infrastructure that allows you to define one or several operations in
a technology independent fashion with support for Spring MVC, Spring
WebFlux and Jersey! Spring Boot 2 will have native support for Jersey
and writing an adapter for another JAX-RS implementation should be
easy as long as there is a way to programmatically register resources.
The new #Endpoint annotation declares this type to be an endpoint with
a mandatory, unique id. As we will see later, a bunch of properties
will be automatically inferred from that. No additional code is
required to expose this endpoint at /applications/loggers or as a
org.springframework.boot:type=Endpoint,name=Loggers JMX MBean.
Refer to documentation, it will help you further
and for your info LoggersMvcEndpoint was there until 2.0.0.M3 https://docs.spring.io/spring-boot/docs/2.0.0.M3/api/org/springframework/boot/actuate/endpoint/mvc/LoggersMvcEndpoint.html however there is no reference of deprecation in subsequent version's release notes of 2.0.0.M4
https://docs.spring.io/spring-boot/docs/2.0.0.M4/api/deprecated-list.html#class

Resources