Instantiating server in Spring Framework 5 and Spring Boot 2 - spring

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.

Related

Standalone wiremock server as spring boot application

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();
}
}

Best practices for using jersey client via guice injection

I'm using Jersey-2.19.x in my application to call rest APIs. Since jersey clients are expensive to create, I wanted to reuse the client for my API calls and therefore inject the client via guice injection.
Here is my guice code for injecting jersey client:
#Provides
#Singleton
Client getClient() {
return ClientBuilder.newClient();
}
And here is my class that uses this injection:
#Inject
public MyClass(Client client) {
this.client = client;
}
public callPost(String uri) {
// code to set web target and invoke
}
Now my question is, how can I close this injected client? What happens if jersey clients are never closed? And what are some best practices for using jersey client via dependency injection?
You need a shutdown hook.
Here is a good article that might be somewhat of an overkill for your situation: https://richardstartin.github.io/posts/lifecycle-management-with-guice-provision-listeners
If you want to keep things simpler, and you don't need to close anything but the Jersey client, you could try something like this:
public static void main(String args[]) {
Injector injector = Guice.createInjector(/* modules... */);
Client jerseyClient = injector.getInstance(Client.class);
Runtime.getRuntime().addShutdownHook(new Thread() {
#Override public void run() {
jerseyClient.close();
}
});
// proceed as normal
}

Define different Feign client implementations based on environment

I have a Spring boot application which uses Feign to call an external web service via Eureka. I'd like to be able to run the application using a mocked out implementation of the Feign interface, so I can run the application locally without necessarily having Eureka or the external web service running. I had imagined defining a run configuration that allowed me to do this, but am struggling to get this working. The issue is that the Spring "magic" is defining a bean for the Feign interface no matter what I try.
Feign interface
#FeignClient(name = "http://foo-service")
public interface FooResource {
#RequestMapping(value = "/doSomething", method = GET)
String getResponse();
}
Service
public class MyService {
private FooResource fooResource;
...
public void getFoo() {
String response = this.fooResource.getResponse();
...
}
}
I tried adding a configuration class that conditionally registered a bean if the Spring profile was "local", but that was never called when I ran the application with that Spring profile:
#Configuration
public class AppConfig {
#Bean
#ConditionalOnProperty(prefix = "spring.profile", name = "active", havingValue="local")
public FooResource fooResource() {
return new FooResource() {
#Override
public String getResponse() {
return "testing";
}
};
}
}
At the point my service runs, the FooResource member variable in MyService is of type
HardCodedTarget(type=FoorResource, url=http://foo-service)
according to IntelliJ. This is the type that is automatically generated by the Spring Cloud Netflix framework, and so tries to actually communicate with the remote service.
Is there a way I can conditionally override the implementation of the Feign interface depending on a configuration setting?
the solution is like below:
public interface FeignBase {
#RequestMapping(value = "/get", method = RequestMethod.POST, headers = "Accept=application/json")
Result get(#RequestBody Token common);
}
then define your env based interface:
#Profile("prod")
#FeignClient(name = "service.name")
public interface Feign1 extends FeignBase
{}
#Profile("!prod")
#FeignClient(name = "service.name", url = "your url")
public interface Feign2 extends FeignBase
{}
finally, in your service impl:
#Resource
private FeignBase feignBase;
Having posted the same question on the Spring Cloud Netflix github repository, a useful answer was to use the Spring #Profile annotation.
I created an alternative entry point class that was not annotated with #EnabledFeignClients, and created a new configuration class that defined implementations for my Feign interfaces. This now allows me to run my application locally without the need to have Eureka running, or any dependent services.
I'm using a simpler solution to avoid having multiples interfaces for a variable parameter like url.
#FeignClient(name = "service.name", url = "${app.feign.clients.url}")
public interface YourClient{}
application-{profile}.properties
app.feign.clients.url=http://localhost:9999

Spring controllers not being found

I am trying to create a RESTful service using spring web reactive. I have a controller that has the usual structure
package com.hcl.bc4sc.server.controller;
...
#RestController
#RequestMapping("/api/v1/registrar/enroll")
public class ControllerV1RegistrarEnroll {
...
#RequestMapping(method = RequestMethod.POST, consumes = "application/json")
public Mono<ResponseEntity> registrarEnrollPost(#RequestBody final UserInfo userInfo) {
...
I am using #ComponentScan to get the controller registered like this
#Configuration
#ComponentScan(basePackages = "com.hcl.bc4sc.server.controller")
public class ServerInitialization {
...
The various beans in my ServerInitialization class are being defined, so I know that ServerInitialization is being processed by Spring.
I am wondering if the problem might be with the way I am starting Spring and the HttpServer like this:
public static void boot() throws TimeoutException {
final GenericApplicationContext context
= new AnnotationConfigApplicationContext(DelegatingWebReactiveConfiguration.class,
ServerInitialization.class);
final HttpHandler handler = DispatcherHandler.toHttpHandler(context);
final ServerConfig config = context.getBean(ServerConfig.class);
applicationContext = Optional.of(context);
// Reactor Netty
final Function<HttpChannel, Mono<Void>> adapter
= new ReactorHttpHandlerAdapter(handler);
final HttpServer server = HttpServer.create(config.getHost(), config.getPort());
httpServer = Optional.of(server);
server.ws("", adapter).startAndAwait();
}
When I try to test this I use the url http://localhost/api/v1/registrar/enroll. It returns a 404.
If I should be starting my service differently, could somebody please point me at a good complete working example?
As per the code you mentioned in question, your controller is in
com.hcl.bc4sc.server.config
But the scan you are doing is for package:
com.hcl.bc4sc.server.controller
You should first fix this ambiguity. And let know of if it still fails. Startup Logs would help.

How to Create Spring WebSocket Application With HTML5 WebSocket API?

Recent Version of Spring WebSocket works with SockJS and StompJS libraries. But i don't like to use theme in my application. So how to create Spring WebSocket application with HTML5 WebSocket API and integrate our application with Spring Security?
I could not find any good example on how to configure spring websocket without sockjs but i found some helpful documentation in spring documentation site and i like to share that. Well, How to Create Spring WebSocket Application With HTML5 WebSocket API?
First: Create a Class that extends TextWebSocketHandler or BinaryWebSocketHandler and Annotate it with #Component annotation and Override its appropriate method.This Class works like handler methods in controllers.
#Component
public class SimpleWebSocketHandler extends TextWebSocketHandler {
#Override
protected void handleTextMessage(WebSocketSession session,
TextMessage message) throws Exception {
// Sends back response to client.
session.sendMessage(new TextMessage("Connection is all right."));
}
}
Second: Create a Configuration Class that implements WebSocketConfigurer and Annotate it with #Configuration and #EnableWebSocket annoations and Override its appropriate method.This Class uses Handler Class that we created already.
#Configuration
#EnableWebSocket
public class WebSocketConfigurations implements WebSocketConfigurer {
#Autowired
private SimpleWebSocketHandler simpleWebSocketHandler;
#Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
// Regsiters a handler for related endpoint.
registry.addHandler(simpleWebSocketHandler, "/chat");
}
}
Third: Add all your WebSokcet Endpoints to your Spring Security Configuration.
httpSecurity.authorizeRequests()
.antMatchers("/chat").permitAll();
Fourth: We create a new javascript WebSocket objet with appropriate URL.
// Create WebSocket Object.
var ws = new WebSocket("ws://localhost:8080/chat");
// Runs when connecion is estabilished.
ws.onopen = function () {
// Sends request to server with string value.
ws.send("webSocket");
};
// Runs when response is ready.
// Use event to get response value.
ws.onmessage = function (event) {
};
Note: WebSocket URLs Format: ws://domain:port/endpoint

Resources