I have a microservice based on spring boot. I have a spring cloud configserver as well in-place. So depending upon the changes in the configserver microservice restart automatically.
So now i need to grab the timestamp when the application got restarted.
Is it possible to do so in the same microservice?
You can listen to spring events such as the ContextStartedEvent. There's a tutorial here that lays it out:
#EventListener
public void handleContextStartedEvent(ContextStartedEvent ctxStartEvt) {
System.out.println("Context Start Event received.");
}
yes, possible by adding the actuator and enabling the startup endpoint.
step1: Add the below dependency
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
<version>2.5.4</version>
</dependency>
step2: Add the below property into the application.properties files.
management.endpoints.web.exposure.include=startup
step3: Setup a little amount of buffer memory to store the startup info and it won't affect the performance at anywhere in your application.
#SpringBootApplication
public class StartupTrackingApplication {
public static void main(String[] args) {
SpringApplication app = new SpringApplication(StartupTrackingApplication.class);
app.setApplicationStartup(new BufferingApplicationStartup(2048));
app.run(args);
}
}
step: Hit the below URL using CURL like below or a POST call from POSTMAN. Then you will be seeing all startup-related info like when the startup started and ended. e.t.c.
curl 'http://localhost:8080/actuator/startup' -X POST | jq
For more explanation, view reference
In the response json, node "timeline"."startTime" is the exact startup timestamp when the applicant has started its startup job.
Related
I have a Kafka consumer built using spring boot and spring-kafka. It is not a Web Application (only spring-boot-starter dependency) and hence there is no port that is exposed by the application. And I donot want to expose a port just for the sake of health checks.
This kafka consumer application is being packaged as a docker image. The CI/CD pipeline has a stage that verifies if the container is up and the service is started. One option I thought was to check for an active java process that uses the service jar file.
ps aux | grep java ...
But the catch here is that a Kafka consumer can keep running for a while if the Kafka broker is not up and eventually stop with errors. So, using the process based approach is not reliable always.
Are there any other alternative options to find out if the application is up and running fine, given that the application is a standalone non-web app?
you need to schedule a job in the spring boot application that checks whatever needs to be checked
and write the health check result to a file in the container
you can have a cronjob on container level to check output of the spring
application in the file and make a final decision about the health status of the container
Popular way for checking application's health is using Spring Boot actuator module it checks different aspects of application, It seems that you should use this module and implement custom end point for checking your application health:
Health Indicators in Spring Boot
I have not any ready source code for calling actuator methods manually but you can try this:
Define a command line argument for running actuator health check.
Disable actuator end points:
management.endpoints.enabled-by-default=false
Call actuator health check:
#Autowired
private HealthEndpoint healthEndpoint;
public Health getAlive() {
return healthEndpoint.health();
}
Parse returned Health object and print a string in command line that indicates health status of application.
Grab the printed health status string by grep command.
As outlined in the Spring Boot reference documentation, you can use the built-in liveness and readiness events.
You could add a custom listener for readiness state events to your application. As soon as your application is ready (after startup), you could create a file (and write stuff to it).
#Component
public class MyReadinessStateExporter {
#EventListener
public void onStateChange(AvailabilityChangeEvent<ReadinessState> event) {
switch (event.getState()) {
case ACCEPTING_TRAFFIC:
// create file /tmp/healthy
break;
case REFUSING_TRAFFIC:
// remove file /tmp/healthy
break;
}
}
}
As explained in the same section, you can publish an AvailabilityChangeEvent from any component - the exporter will delete the file and let other systems know that it's not healthy.
I have my endpoints like so:
#Path("/users")
public class Users {
private final SomeDependency dependency
public Users(SomeDependency dependency) {
this.dependency = dependency;
}
#GET
#Path("/{id}")
public Response Get(#PathParam("id") int id) {
User user = this.dependency.get(id);
return Response.ok(user).build();
}
}
Now how do I actually run a server with this endpoint?
I am confused about web servers/applications/servlets, using jersey jetty glassfish or whatever. Also web.xml files? what? ResourceConfigs only accept classes, not their instances. Everything seems to be such a mess.
How can I just do something similar to this?
public static void main(String[] args) throws Exception {
SomeDependency dependency = new SomeDependency();
Users usersEndpoint = new Users(dependency);
Server server = new Server();
server.registerEndpoint(usersEndpoint);
server.start();
}
Server
As far as the server goes, you have two types you have to consider: installed or embedded.
Installed
An installed server is one that is installed on your machine. For example, if you download Tomcat 10 and then follow the installation instruction, the server will get installed on your machine at whatever location you choose. In this situation, when you have an app (a war file) you are ready to deploy, you will copy it to your Tomcat server (to a specific location) and on server startup, Tomcat will see the application and then run it. The applications running in this type of environment will require a web.xml as they are deployed in a war file.
Embedded
An embedded server is one that is packaged into your jar application and is started in a main method just like any other Java SE application. Most installed servers also come with an embedded version. All you need to do is add the server dependencies into your application and then write the server configuration and startup (and shutdown) code. Applications running in this environment will not require a web.xml as they are deployed as a jar file.
Which one to use?
With the advancement and popularity of cloud services and microservices, many applications are moving towards embedded servers. The reason is that they are easy to deploy, are scalable, relatively lightweight, and applications become more self contained. There are many other pros that come with using embedded servers, but there are also some cons. Do your research before you make your final decision about which one you should use.
Example
If you want to quickly get started without having to worry about setting up the project, knowing what dependencies you need to add, adding the startup code, an easy way to get up and running is to use a Maven Archetype. If you go to the Jersey Docs, they get you started with an embedded Grizzly server running a Jersey application. What you need to do is run the following command from the command line (assuming you have Maven installed in your machine)
mvn archetype:generate -DarchetypeArtifactId=jersey-quickstart-grizzly2 \
-DarchetypeGroupId=org.glassfish.jersey.archetypes -DinteractiveMode=false \
-DgroupId=com.example -DartifactId=simple-service -Dpackage=com.example \
-DarchetypeVersion=2.33
If you read the docs I linked to, it will give an explanation of all that comes with the initial application. The main class will look like the following (with comments and imports omitted)
public class Main {
public static final String BASE_URI = "http://localhost:8080/myapp/";
public static HttpServer startServer() {
final ResourceConfig rc = new ResourceConfig().packages("org.example");
return GrizzlyHttpServerFactory.createHttpServer(URI.create(BASE_URI), rc);
}
public static void main(String[] args) throws IOException {
final HttpServer server = startServer();
System.out.println(String.format("Jersey app started with WADL available at "
+ "%sapplication.wadl\nHit enter to stop it...", BASE_URI));
System.in.read();
server.stop();
}
}
In this code, they use the packages() method of the ResourceConfig class that specifies a package for Jersey to scan for #Path and #Provider classes to register. In your case, if you don't need that, you can remove the method call. If you want to register your Users instance, all you do is call register(users) on the ResourceConfig.
See Also
What exactly is the ResourceConfig class in Jersey 2 - this link will help you get started with the ResourceConfig class and show you how you can register you resource classes or instances.
Other Frameworks
There are other frameworks out there that you may also want to consider
Dropwizard - Dropwizard is an opinionated framework built on top of Jersey. It uses an embedded Jetty as its server and comes with many other features to make developing your applications easier. They have pretty good, easy to follow documentation. There is a good "getting started" guide if you want to give them a try.
Spring Boot - Spring Boot is a bootstrapping framework that makes getting up and running with applications much easier. There are auto configurations made for you but give you options to change them. You can use Spring MVC or Jersey as the REST framework when you work with Spring Boot. There is also an Initializer, which is similar to the Maven Archetypes, but is interactive and allows you to add what you want to your applications.
So I just accepted the fact that java is an utter mess and pulled these dependencies in:
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxrs</artifactId>
<version>3.4.2</version>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http-jetty</artifactId>
<version>3.4.2</version>
</dependency>
So i can launch everything like so:
public static void main(String[] args) throws Exception {
SomeDependency dependency = new SomeDependency();
Users usersEndpoint = new Users(dependency);
JAXRSServerFactoryBean serverFactory = new JAXRSServerFactoryBean();
serverFactory.setResourceClasses(usersEndpoint.getClass());
serverFactory.setResourceProvider(usersEndpoint.getClass(), new SingletonResourceProvider(usersEndpoint));
serverFactory.setAddress("http://localhost:8080/");
serverFactory.create().start();
}
I have more endpoints, of course, so I put everything in a for loop.
As to why I'm answering from a guest account, the account I used to ask this question was created using a disposable email address, and I can no longer access it.
Hope this helps anyone in the future!
I went via almost all docs and all but not able to get grip on this mysterious stuff.
so my question - Can I use my standalone spring boot app to monitor health and other metrics of my app via http jmx url? Do I need to configure something else for this?
I have added below dependency in boot app.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.jolokia</groupId>
<artifactId>jolokia-core</artifactId>
</dependency>
I have also configured below properties in my config file.
management.endpoints.web.exposure.include=*
management.endpoints.jmx.unique-names=true
management.server.port=8080
management.server.ssl.enabled=false
When I try to hit URL : http://localhost:8080/actuator/jolokia/health I am not able to see any results.
Also tried adding custom end point like below but not working.
#Endpoint(id="mypoint")
#Component
public class myPointEndPoint {
#ReadOperation
public String mypoint(){
return "Hello" ;
}
with additional property
management.endpoint.mypoint.enabled=true
The problem is the url you are trying to invoke.
First, retrieve the possible mbeans with: http://localhost:8080/actuator/jolokia/list
When you take a look at the Health mbean, you must provide the unique name and the operation (op).
In my case, it looked like: http://localhost:8080/actuator/jolokia/exec/org.springframework.boot:type=Endpoint,name=Health,identity=4200098/health
Also check the Jolokia documentation: https://jolokia.org/reference/html/index.html
I have been trying to figure out an issue with spring boot and as i am new to spring I thought of getting some help here.
I have a spring boot based java application which runs as a daemon and makes some GET request to a remote server. (Acts only as a client).
But my spring boot application internally starts an embedded tomcat container.
My understanding is that if the java app acts as a server, it would need tomcat. But my application being only a consumer of remote machine's GET APIs, why would it need an embedded tomcat ?
In my pom file I have specified spring-boot-starter-web,
on assumption that it is needed for even making GET calls.
But after doing some research on disabling embedded tomcat, I found a solution.
To make following changes,
#SpringBootApplication(exclude = {EmbeddedServletContainerAutoConfiguration.class,
WebMvcAutoConfiguration.class})
&
in application.yml
spring:
main:
web-environment: false
With the application.yml changes, my jar is not even getting started, aborts directly, without even logging anything in logback logs.
Now, if i remove the application.yml change, my jar starts (only with first change in #SpringBootApplication anno.) but goes into some exception.
[main] o.s.boot.SpringApplication : Application startup failed
org.springframework.context.ApplicationContextException: Unable to start embedded container; nested exception is org.springframework.context.ApplicationContextException: Unable to start EmbeddedWebApplicationContext due to missing EmbeddedServletContainerFactory bean.
My Doubts here are,
1) Is tomcat, be it standalone or embedded, really needed for a application which just makes GET API calls to remote machine ?
2) How do i overcome this exception and safely remove the embedded tomcat and still perform the GET API calls ?
You seem to be on completely the wrong track here, starting from a web application template and then trying to turn off the web application aspect.
Far better to start from a regular commandline client template and go from there, as detailed in the relevant Spring Guide.
Basically the application reduces to
#SpringBootApplication
public class Application {
private static final Logger log = LoggerFactory.getLogger(Application.class);
public static void main(String args[]) {
SpringApplication.run(Application.class);
}
#Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder.build();
}
#Bean
public CommandLineRunner run(RestTemplate restTemplate) throws Exception {
return args -> {
Quote quote = restTemplate.getForObject(
"http://gturnquist-quoters.cfapps.io/api/random", Quote.class);
log.info(quote.toString());
};
}
}
And the pom to
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
</dependencies>
I had this problem. All I wanted was to have a Client making REST requests. Unfortunately I had a dependency which was embedding Jetty, and Jetty was always started.
In order to disable Jetty all I needed to do was to add in applications.properties the following entry:
spring.main.web-application-type=none
That fixed it.
Here is the most simple solution for me, make spring boot application just a restful api consumer.
Replace the dependence
implementation("org.springframework.boot:spring-boot-starter-web")
with
implementation("org.springframework.boot:spring-boot-starter-json")
RestTemplate and jackson are available in the project without embedded tomcat.
Answering your questions:
1) embedded by defaut - not needed for clients HTTP requests;
2) You can use CommandLineRunner for spring boot applications without any web:
#SpringBootApplication
public class SpringBootConsoleApplication implements CommandLineRunner {
public static void main(String[] args) {
SpringApplication.run(SpringBootConsoleApplication.class, args);
}
#Override
public void run(String... args) {
// TODO: start you thread here to execute client HTTP REST requests (or any other job you need)
}
}
This will disable web completelly - no issues with manual miss-configuration.
Here is some docs:
http://www.baeldung.com/spring-boot-console-app
You also need replase spring-boot-starter-web dependency with spring-boot-starter:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
From your question, i assume you want your application to keep running in background and it makes some get calls in it's life cycle. If that's the case, then
answering your first question, yes, you need an embedded tomcat or
jetty or need to deploy your application to an external application
server.
Second, to get rid of the exception your facing, don't exclude
EmbeddedServletContainerAutoConfiguration and
WebMvcAutoConfiguration class as it's needed for default embedded
tomcat auto configuration.
Is there any authentication method (user and password) and UI for it avalible for Netflix's server registry library Eureka? I'm looking for something like Spring Boot Admin's login page.
There is ui page which you can see just enter your host:port in browser. But it just shows info about registered clients, nothing you can do more. And for authentication you can use basic spring security. If you enable basic security with a user name and password, that ui asks you for it when you try to get to page. Additionally you should supply those username and password for registering clients too.
Just like any other Spring Boot Application:
#SpringBootApplication
#EnableEurekaServer
public class ServeurCloudEurekaApplication {
public static void main(String[] args) {
SpringApplication.run(ServeurCloudEurekaApplication.class, args);
}
}
In your pom file.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
Start your App and enter your host:port in browser