MeterBinders in Spring Boot - spring-boot

I'm trying to understand why some of the micrometer MeterBinders are hooked up and others not. I can see that the MeterRegistryPostProcessor gets all of that type from context. But why is for instance JettyStatisticsMetrics not in context, but JvmGcMetrics is?

MeterBinders need to be exposed as Spring Beans in order for them to be picked up.
For Spring-Boot 1.x they need to be exposed/configured in the micrometer-spring-legacy project. For Spring-Boot 2 this is done in the spring-boot project itself.
In case you are missing some auto-configured MeterBinders, don't hesitate to file an issue in the respective bug trackers: here or here. (Please use the search. It might be these issues already have been reported.)

Related

Why spring.jpa.properties. prefix is not always required in Spring Boot properties

I learning Spring boot and found that in some examples use the same properties with the prefix spring.jpa.properties while other do it without prefix.
For instance:
The article explains second level cahche https://www.baeldung.com/hibernate-second-level-cache and autor shows example of needed properties ( example on autor's gitHub):
hibernate.cache.use_second_level_cache=true
hibernate.cache.region.factory_class=org.hibernate.cache.ehcache.EhCacheRegionFactory
But it did not work for me, and I spent few hours loking for the reason, but then i noticed, someone use prefix spring.jpa.properties. to get it working (Exact moment from video lesson):
spring.jpa.properties.hibernate.cache.use_second_level_cache=true
spring.jpa.properties.hibernate.cache.region.factory_class=org.hibernate.cache.ehcache.EhCacheRegionFactory
Which perfectly worked for me.
So my questions are:
why are they working in different way?
how to understand which properties in which cases requires this prefix?
is it probably something related to my project settings OR Spring Boot version?
any other suggestions are appreciated :)
Thank you in advance!
There are a couple of things in play here. First the tutorial you use is using plain Spring not Spring Boot. Which means a manually configured EntityManagerFactory on which you directly can set the provider specific properties. Like hibernate.cache.use_second_level_cache.
As you decided to use Spring Boot you don't have a manually configured EntityManagerFactory (although you could!). Which means you are using an autoconfigured EntityManagerFactory. Properties for this reside in the spring.jpa namespace for properties.
As it isn't feasible to specify properties for each and every extension for Hibernate (or other JPA providers) only some commonly used ones are exposed like spring.jpa.generate-ddl and a few provider specific ones in the spring.jpa.hibernate namespace. However to set all the other properties in an autoconfigured way there needed to be something else. Hence the spring.jpa.properties prefix. Anything specified in there will be passed on as is (without the said prefix ofcourse) to the EntityManagerFactory for configuration.

Spring Data GemFire Region entry expiration (Time-To-Live) error

I have a Spring Data GemFire Region that's configured using annotations below:
#TimeToLiveExpiration(timeout = "100", action = "INVALIDATE")
#PartitionRegion(name = "blockedIPCache")
class BlockedIpEntityType { ... }
My application is a Spring Boot application and I used the following annotations to configure SDG:
#PeerCacheApplication
#EnableGemfireCaching
#EnableCachingDefinedRegions(clientRegionShortcut = ClientRegionShortcut.LOCAL, serverRegionShortcut = RegionShortcut.LOCAL)
#EnableStatistics
#EnableExpiration
#EnableEntityDefinedRegions(basePackageClasses = {...})
#EnableGemfireRepositories(basePackages = {...})
class GemFireConfiguration { ... }
All I want is to insert an object using a Spring Data GemFire Repository and after awhile the entry will be invalidated.
But, I face this Exception when I start my application...
Caused by: java.lang.IllegalStateException: Cannot set idle timeout when statistics are disabled.
at org.apache.geode.internal.cache.AbstractRegion.setCustomEntryIdleTimeout(AbstractRegion.java:1157) ~[geode-core-9.1.1.jar:?]
at org.springframework.data.gemfire.config.annotation.ExpirationConfiguration$ExpirationPolicyMetaData.configure(ExpirationConfiguration.java:511) ~[spring-data-gemfire-2.0.6.RELEASE.jar:2.0.6.RELEASE]
at org.springframework.data.gemfire.config.annotation.ExpirationConfiguration$1.postProcessAfterInitialization(ExpirationConfiguration.java:160) ~[spring-data-gemfire-2.0.6.RELEASE.jar:2.0.6.RELEASE]
...
This happens exactly when Spring tries to autowire my Repository related to the Region configured above.
So what I'm doing wrong? And, is there a way to enable Region statistics using Java configuration or Annotations?
Note: Using Spring Data GemFire 2.0.6, Spring 5.0.5, Spring Boot 2.0.1 used in the project.
It turns out, you did not do anything wrong. Unfortunately, you stumbled across a bug(!), for which I have already filed SGF-747 and fixed. I am sorry for the inconvenience this issue may have caused you.
We are planning a Spring Data Lovelace M3 (Milestone 3) release tomorrow (Thursday, 5/17, CET). The release schedule is visible from Spring Release Calendar. All dates are tentative.
As such, you could try the new Spring Data for Pivotal GemFire (SDG) Lovelace bits (i.e. 2.1.0.M3) with the fix. SDG 2.1.0. should work just fine with Spring Boot 2.0.1/2.RELEASE and Spring 5.0.5/6.RELEASE.
However, if you are expecting to get GA bits for SDG containing this fix, then you will have to wait for the next Spring Data Kay Service Release (Kay SR8), or the Spring Data for Pivotal GemFire 2.0.8 Service Release. I am backing porting this fix.
Unfortunately, there is not another Spring Data Kay Service Release (i.e. Kay SR8) planned until probably around July 2nd or 3rd, right after Spring Framework 5.0.7 is released on Monday, July 2nd and just before Spring Boot 2.0.3 is released on Wednesday, July 4th, which is usually when we plan Spring Data Service Releases. Also, know that Spring Boot 2.0.x is based on Spring Data Kay, but should work just fine with SD Lovelace too, as I mentioned previously.
In the meantime, I will try to think of workaround where the convenience of the Annotations (e.g. #EnableEntityDefinedRegions) can still be used. I will post the workaround in SGF-747.
I see that you specified the clientRegionShortcut attribute in the #EnableCachingDefinedRegions annotation but have declared your application to be a #PeerCacheApplication. While there is no harm in doing so, the clientRegionShortcut attribute is useless in this case. Likewise, the serverRegionShortcut attribute would have no meaning if you are application were a #ClientCacheApplication instead; something to keep in mind.
Lastly, I wanted to let you know that the SDG #EnableStatistics annotation does not have the effect you probably think it does.
Specifically, SDG's #EnableStatistics annotation is concerned with enabling Pivotal GemFire's statistics "sampling" as explained here, which is configured by doing this, as also explained in the SDG #EnableStatistics annotation Javadoc, as well as referenced in the SDG Reference Guide.
The "statistics enabling" that ultimately needs to happen is by setting the Region's staticsEnabled attribute property when configuring and creating the Region (e.g. "blockedIPCache").
That is exactly what the #EnableExpiration annotation will indirectly guarantee now, with the fix in SGF-747, without the need to #EnableStatistics.
Anyway, I hope this all makes sense and helps.
Regards,
John

How to debug when Flyway doesn't work on Spring Boot?

I am using Maven and Spring Boot. I run the application using mvn spring-boot:run.
https://flywaydb.org/documentation/plugins/springboot says Flyway should be called on Spring Boot start.
So my pom.xml contains the dependency to Flyway.
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
<version>4.1.2</version>
</dependency>
The first time I ran the Maven command above it downloaded Flyway stuff, so I think the dependency is working.
I have the following files:
./src/main/resources/db/migration/V123__foo.sql
./src/main/resources/application.properties
The above article implied it should "just work", but I don't understand where it would find the JDBC URL to the database. So I added the following to the application.properties file:
flyway.url=jdbc:postgresql://localhost:5432/services?user=postgres&password=postgres
flyway.enabled=true
When Spring Boot starts up (and loads and makes available my web application) there are no logs from Flyway. I think Flyway is ignored.
What can I do? Or, more generally, how would I go about debugging this problem myself?
Nobody has posted an answer so I'll post what I found out.
M. Deinum was indeed correct in their comments to the question, the problem was a lack of a data source.
My original question was what the approach should be to debugging this kind of issue. Obviously one option is to post to stackoverflow :) But I wanted to know how to do it myself.
Spring Boot has a number of classes which look at your code and classpath, and act appropriately. For example, there are classes providing implementations to the rules like "if Flyway is on the path, and there is a data source, then execute Flyway". That rule wasn't getting triggered in my case, because I had no data source.
It's not the case that the code you write calls Spring Boot, it's the other way around, Spring Boot (external to your code) inspects your code and decides what to do based on rules. This architecture is known as action at a distance. The main problem with action at a distance is it's very difficult to debug.
The only real way to find the solution, and it was the way I went about confirming M. Deinum's diagnostic, is to read the Spring Boot source code and understand the annotations which are used to create Spring Boot code.
From the source code to Spring Boot's Flyway integration we see
#ConditionalOnClass(Flyway.class)
#ConditionalOnBean(DataSource.class)
This means "this code will get executed if Flyway is on the classpath, and if there is a DataSource bean available; otherwise it silently won't get executed".
So the answer to the question "how to debug this problem" is that there is no mechanism other than to read the source code of Spring Boot and find out how it works.
If you want to avoid this sort of problem, you have to avoid frameworks which work via "action at a distance", and that includes Spring Boot.

Programmatically configure Spring Boot app

what's the easiest way to get the spring boot goodness but not try to autoconfigure all the things? For instance, to only run flyway with our already configured properties (some loaded via Consul + Spring Cloud), I was hoping I could do something like:
#Configuration
#Import({DataSourceAutoConfiguration.class, FlywayAutoConfiguration.class})
public class FlywaySetup {}
and have the main method just call SpringApplication.run(FlywaySetup.class)
The problem with this is it picks up all the Component Scan / crazy long list of other dependencies. Any way to specifically configure the dependencies (but still get the nicities of the framework)
If you run this app, it shouldn't use component scan at all. There's nothing that triggers component scan in spring boot besides #ComponentScan (that's available on #SpringBootApplication).
It would help if you could provide more accurate details rather than "crazy long list of other dependencies.". Running that FlywaySetup should only load those two configuration classes (important: these are not handled as auto-configuration anymore). If you have component scan, there's something else you're not showing.
You can exclude auto-configurations you don't need.
You may want to take a look at this SO answer to explore mechanism how to do that.

Camelize a spring boot application

We have a spring boot application that is growing in complexity because of integration needs - like send an email after you do this, or broadcast a jms message after you that etc. In looking for some higher level abstractions, I came across apache camel (haven't used camel ever before). The question that I have is what do I do with the spring boot application? The application has the standard spring controllers, services and uses spring-data for connecting to databases. I didn't find much help online on how to merge camel into a spring-boot restful application. Is that even something that is doable or is camel a completely different beast that the spring boot won't fit?
I did read that Camel tightly integrates with Spring, but still I didn't know if 1) Spring Controllers are still something that can be used along with Camel 2) If I can call the other spring beans from camel routes and whether I can call invoke a camel route from a spring bean (sorry if these sound like camel newbie questions to the experts)
As an example of what we have to do:
After finishing writing anything to the database about an order, we have to send an email out to the order processing department
If someone deletes a particular user address, we have to send to a jms topic so other applications can take action.
Every http request is coming in through the Spring MVC stack today.
Is there a way to "hand-off" the processing to camel after a particular task is complete? (like writing the order to the database successfully via the Spring MVC stack and hand off to camel to send a jms message and do other things)? Or should we completely replace Spring with Camel?
Not sure what the right path is. Can someone please guide us?
This question is slightly old, but though it was worth mentioning here that Apache Camel now includes a Spring Boot component.
Details can be found here
http://camel.apache.org/spring-boot.html
and they document an example here
http://camel.apache.org/spring-boot-example.html
Follow this for the current best practice in camelising a spring boot application!
One option is to
1> define camel routes either in Spring DSL or Java DSL or other means and define it in Spring Application context.
2> And have a class that implements ApplicationContextAware and cache the Spring ApplicationContext in a Static Variable.
3> For #Controller we can get this static variable and get hold of ApplicationContext .
4> With the camel context ID we can do a getBean from ApplicationContext.
5> This is the instance of DefaultCamelContext,with this we can do a createProducer and call camel routes from #Controller.
Like some others mentioned, spring-boot-camel (but use spring-boot-camel-starter as your dependency) works very well and it is really easy to set up. When you annotate your RouteBuilder extensions and your Processor implementations with #Component, they wire up directly into the context and you are good to go. Then, you can #Autowire a CamelContext or a ProducerTemplate into your classes and use them as necessary.
You asked about how Controllers can work with Camel, and if you #Autowire any of the things you need (probably a context or a producer template), then the answer is a definite "yes" that you can use them together quite easily. And when you use spring-web, your context will start and remain running without any additional configuration, etc.
Like Matthew Wells suggested, the links will get you pointed in the right direction. If you, or others on your team, are at all familiar with Camel, then it will be very easy for you to do what you need to do. But, ah, I notice that this question is from 2014, and you're probably well past the point of your question. At least if anyone else stops by this thread, they will have plenty of information to get going. If you come by and re-visit your question, please let us know how it went for you, and what you ended up doing. Cheers!

Resources