Standalone wiremock server as spring boot application - spring-boot

I am trying to make a mock service as a spring boot application.
Can I use standalone mock server inside a spring boot application?
When I tried to run a mock server on any port inside the spring boot application it throws the "Address already bound exception"
Is there a way to over come that so that I can have a mockservice running as a spring boot docker container and just configure the urls I want to mock.

Basically, you would want to avoid any starter that brings up a container/server. Initially, I have only these two dependencies: com.github.tomakehurst:wiremock-jre8:2.31.0 and org.springframework.boot:spring-boot-starter-json. Optionally, confirm you don't want to run any server(s): spring.main.web-application-type: none.
Finally, declare a config file to setup WireMock:
#Configuration
#AllArgsConstructor
#EnableConfigurationProperties(WireMockConfig.ApplicationProps.class)
public class WireMockConfig {
private final ApplicationProps props;
#Bean
public WireMockServer mockServer() {
return new WireMockServer(WireMockConfiguration.options().port(8081));
}
}
...and a listener to start the server:
#Component
#AllArgsConstructor
public class ApplicationListener {
private final WireMockServer server;
#EventListener
public void onApplicationEvent(final ApplicationReadyEvent event) {
server.start();
}
}

Related

Spring Boot WebSockets #EventListener doesn't detect SessionConnectEvent but detect SessionDisconnectEvent at the same class

I try to create simple chat via WebSockets. I have configuration class which register appropriate endpoints and I try to create service which will save user id which is generated in handshake service. The problem is that I cannot inject any services to the handshake service so I decided to create class as below:
#Slf4j
#RequiredArgsConstructor
public class WebSocketEventListener {
#EventListener
public void handleWebSocketConnectListener(SessionConnectEvent event) {
log.debug("Handled connection event");
}
#EventListener
public void handleWebSocketConnectedListener(SessionConnectedEvent event) {
log.debug("Handled connected event");
}
#EventListener
public void handleWebSocketDisconnectListener(SessionDisconnectEvent event) {
log.debug("Handled disconnection event");
}
}
Register it as a Bean in configuration class:
#Bean
public WebsocketEventListener websocketEventListener() {
return new WebsocketEventListener();
}
And there try to save user id into database.
Unfortunately when I connect to the webSocket via android app, Spring doesn't detect any event connected with Connection session but when I close the connection between android app and spring server I'm getting log from handleWebSocketDisconnectListener method.
I also tried to add annotation #Component to the class WebSocketEventListener instead of registering it as a Bean but I got the same situation.
I tried to implement ApplicationListener and register it in META-INF folder but also without any results.
P.S. I use Spring Boot version: 2.6.4 and Java 17
I don't know what I'm doing wrong. Any suggestions?

How do I setup baggage fields in Spring Cloud Sleuth for a Command Line Runner?

I'm successfully using Spring Cloud Sleuth in a Spring Boot microservice and am having fields logged and sent over http headers appropriately.
I now need to integrate this same process for logging and header propagation in a Spring Boot command line runner application but it looks like no trace and span are automatically setup since it isn't in the middle of an Http request (as it is a command line app). I cannot see these fields in my logs (with the same %X format in log configuration).
I've looked at the docs and can't find any examples for this specific use case. Is this possible in a command line runner app?
In order to add baggage you need to have a span. Spring Cloud Sleuth and Spring Boot create a span for you when the controller is invoked. If you want to do the same using CLI application, you need to create span yourself.
You have two options.
Using API calls:
Span span = this.tracer.nextSpan().name("mySpan");
// do some work
span.end(); // best to put it in finally to make sure span is always ended
Or you can use annotations:
#NewSpan
public void doWork() {
}
If you use the annotation, please keep in mind the AOP proxies limitations. In particular self invocations (calls using this) would not work.
#SpringBootApplication
public class ConsoleApplication
implements CommandLineRunner {
#Override
public void run(String... args) {
doWork(); //this is the same as this.doWork();
}
#NewSpan
public void doWork() {
}
}
This is not going to work as doWork is not invoked through the AOP proxy. Make sure that you annotate a component managed by Spring and then use an injected instance.
#SpringBootApplication
public class ConsoleApplication
implements CommandLineRunner {
#Autowired
private MyService myService;
#Override
public void run(String... args) {
myService.doWork();
}
}
#Component
class MyService {
#NewSpan
public void doWork() {
}
}
In this case myService is not instance of MyService, but rather an instrumented proxy.

How can I discover my Service(Spring Boot application) in legecy(Spring web-mvc) code

I have my legacy spring application (not spring boot).
Now I have moved some code which I thought can be work separately as a service, I was able to move code cleanly and able to run as a separate service (spring boot application).
Now I want to discover my service and want to call from legacy code, I add a NetFlix-Eureka dependency but that is downloading the spring-boot dependency, that I don't want.
How can I discover my service in the legacy application and call its APIS
I assume from your question that -
You have Eureka server running
Your new spring boot microservice is connecting to eureka server
You are asking how to connect your legacy
application with Eureka server, As after that you can discover and
call the APIs of new microservice
If that's correct. For connecting your legacy application you can do below configurations.
Create a class say CustomEurekaClient.
public class CustomEurekaClient {
private static ApplicationInfoManager appaInfoManager;
private static EurekaClient eurekaClient;
#Autowired
private WebAppInstanceConfig webAppInstanceConfig;
#Autowired
private EurekaClientConfig eurekaClientConfig;
private ApplicationInfoManager initializeApplicationInfoManager(EurekaInstanceConfig instanceConfig) {
InstanceInfo instanceInfo = new EurekaConfigBasedInstanceInfoProvider(instanceConfig).get();
return new ApplicationInfoManager(instanceConfig, instanceInfo);
}
private EurekaClient initializeEurekaClient(ApplicationInfoManager applicationInfoManager, EurekaClientConfig clientConfig) {
eurekaClient = new DiscoveryClient(applicationInfoManager, eurekaClient); //use this eureka client while de
// registering service
return eurekaClient;
}
#PostConstruct
public void runRegistration() {
ApplicationInfoManager applicationInfoManager =
initializeApplicationInfoManager(webAppInstanceConfig);
initializeEurekaClient(applicationInfoManager, eurekaClientConfig);
applicationInfoManager.setInstanceStatus(InstanceInfo.InstanceStatus.UP);
}}
EurekaClientConfig class-
class EurekaClientConfig extends DefaultEurekaClientConfig {
//minimum change needed override
#Override
public List<String> getEurekaServerServiceUrls(String myZone) {
return Arrays.asList(YOUR_COMMA_SEPRATED_EUREKA_SERVER_URL);
}}
WebAppInstanceConfig class-
class WebAppInstanceConfig extends MyDataCenterInstanceConfig {
// TODO override all the methods of EurekaInstanceConfig, which you need like serviceUrl...interface and provide respective values
}
In postConstruct of CustomEurekaClient we are registering the service to Eureka server. Once both services are registered to Eureka you can access APIs.

How to trigger a Spring cloud task from an external application?

I have created a spring cloud task that will perform some specific task based on the requirement. I wanted to call this task from another spring boot application. Please let me know is there any way of calling the below task from an external application.
#SpringBootApplication
#EnableTask
public class FileGenerationTaskApplication {
#Autowired
private DataSource dataSource;
public class FileGeneratorTaskConfigurer extends DefaultTaskConfigurer {
public FileGeneratorTaskConfigurer(DataSource dataSource){
super(dataSource);
}
}
#Bean()
public FileGeneratorTaskConfigurer getTaskConfigurer() {
return new FileGeneratorTaskConfigurer(dataSource);
}
public static void main(String[] args) {
SpringApplication.run(FileGenerationTaskApplication.class, args);
}
#Component
public static class FileGeneratorTaskRunner implements ApplicationRunner {
#Autowired
private FulfillmentFileGenerationService service;
public void run(ApplicationArguments args) throws Exception {
System.out.println("FileGeneratorTaskRunner from Spring Cloud Task!");
service.fulFillmentFileGenerationTask();
}
}
}
Can we create a REST api to call the spring cloud task?
It would be nice to have the Task registered on Spring Cloud Dataflow.
After you have your Task registered, you can make REST calls to trigger the Task. Check this example out.
You can also use Spring Cloud Dataflow Rest Client
DataFlowOperations dataFlowOperations = new DataFlowTemplate(URI.create(springDataFlowUri));
TaskOperations operations = dataFlowOperations.taskOperations();
Then you can start launching the Tasks previously got using the API Rest.
In case you do not want to use Spring Cloud DataFlow, remember when you create a Task, this is a Spring Boot Application by itself, so you can expose end points to trigger the Task.

Instantiating server in Spring Framework 5 and Spring Boot 2

I am using Spring Boot 2 just to try some reactive programming with Spring 5. I created some standard MVC controller.
#RestController
#RequestMapping("/judge/rest")
public class BasicController {
private static final Logger LOGGER = LoggerFactory.getLogger(BasicController.class);
#GetMapping("/hello")
public Mono<String> handle() {
LOGGER.debug("Invoking hello controller");
return Mono.just("Hello WebFlux");
}
}
And standard router function.
#Configuration
public class WebConfig {
#Bean
public RouterFunction<?> helloRoute() {
return route(GET("/judge/router/hello"),
request -> ServerResponse.ok().body(fromPublisher(Mono.just("Hello Router WebFlux"), String.class)));
}
}
My main spring boot application looks like this
#SpringBootApplication
public class JudgeRuleEngineApplication {
public static void main(String[] args) {
SpringApplication.run(JudgeRuleEngineApplication.class, args);
}
}
But in documentation for spring 5 I ran into
HttpHandler httpHandler = RouterFunctions.toHttpHandler(route);
ReactorHttpHandlerAdapter adapter =
new ReactorHttpHandlerAdapter(httpHandler);
HttpServer server = HttpServer.create("localhost", 8080);
server.startAndAwait(adapter);
It seems that server is intantiated manually.
My question is when should I instantiate the server like this? Because so far it seems with #SpringBootApplication and main it handles requests just fine.
As the document says
Now there is just one piece of the puzzle missing: running a router
function in an HTTP server. You can convert a router function into a
HttpHandler by using RouterFunctions.toHttpHandler(RouterFunction).
The HttpHandler allows you to run on a wide variety of reactive
runtimes: Reactor Netty, RxNetty, Servlet 3.1+, and Undertow.
Which means the above code which you have shown, uses Reactor Netty as the reactive runtime. If you wish to use any other runtimes which has reactive native adapter, you can do so. In such cases you would instantiate the server like this.
By default Spring boot default to Reactor Netty.

Resources