We have a spring boot based application and using spring webflux, we are exposing 3 ports
server.port
management.server.port (actuator) and are planning to expose another port called as admin port.
We want to expose a specific REST controller on this admin port which will be private. This api will provide all the admin level configuration and will not be available publicly to the user.
Note: We don't want to expose api on actuator port. Need to open a new port.
Using the following code to open a new port by starting a new server instance.
#Configuration
public class NettyServerForAdminPort {
#Value("${admin.port}")
private Integer adminPort;
#Autowired
HttpHandler httpHandler;
WebServer http;
#PostConstruct
public void start() {
ReactiveWebServerFactory factory = new NettyReactiveWebServerFactory(8081);
this.http = factory.getWebServer(this.httpHandler);
this.http.start();
}
#PreDestroy
public void stop() {
this.http.stop();
}
}
Any insights on how this can be achieved?
Related
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();
}
}
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.
Can anybody tell me how 2 ports (for HTTP and HTTPS) can be configured when using Spring Boot 2 and WebFlux? Any hint is appreciated!
This isn't directly supported by Spring Boot 2 yet.
But, you may be able to get it to work in a couple of ways.
By default, Spring Boot WebFlux uses Netty. If you are already configured for ssl, then Spring Boot will start up and open port 8443 (or whatever you have configured).
Then, to add 8080, you can do:
#Autowired
HttpHandler httpHandler;
WebServer http;
#PostConstruct
public void start() {
ReactiveWebServerFactory factory = new NettyReactiveWebServerFactory(8080);
this.http = factory.getWebServer(this.httpHandler);
this.http.start();
}
#PreDestroy
public void stop() {
this.http.stop();
}
Which is a bit clunky since your https configuration is in one spot (application.yml) and your http configuration is in Java config, but I have tested this myself with a toy application. Not sure how robust of a solution it is, though.
Another option that may work is to try the equivalent of other suggestions, but use the reactive version of the class, which is TomcatReactiveWebServerFactory. I'm not aware of any way to provide more than one connector for it, but you could possibly override its getWebServer method:
#Bean
TomcatReactiveWebServerFactory twoPorts() {
return new TomcatReactiveWebServerFactory(8443) {
#Override
public WebServer getWebServer(HttpHandler httpHandler) {
// .. copy lines from parent class
// .. and add your own Connector, similar to how tutorials describe for servlet-based support
}
}
}
Also, a bit messy, and I have not tried that approach myself.
Of course, keep track of the ticket so you know when Spring Boot 2 provides official support.
Follow the instructions listed in the link provided by jojo_berlin (here's the link). Instead of using his EmbeddedTomcatConfiguration class though, use this below
#Configuration
public class TomcatConfig {
#Value("${server.http.port}")
private int httpPort;
#Bean
public ConfigurableServletWebServerFactory webServerFactory() {
TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
Connector connector = new Connector(TomcatServletWebServerFactory.DEFAULT_PROTOCOL);
connector.setPort(httpPort);
factory.addAdditionalTomcatConnectors(connector);
return factory;
}
}
Actually you can define a second connector as described here . So you can define a https connector as your default and an additional HTTP Connector
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
How can we use grcp communication with spring boot application. And how we can use common service discovery method for use with grpc to get end point of spring boot application.
For service discovery, implement your own NameResolver.
I used below code to get instance discovery client. It help to call all servers using revers poxing.
#Autowired
private DiscoveryClient discoveryClient;
and below method help to call all the services using service name
#RequestMapping(method = RequestMethod.GET, value = "/senduser")
public ResponseEntity<?> sendMessageToAllServices() {
user u=null;
List<ServiceInstance> server=discoveryClient.getInstances("grpc-server");
for (ServiceInstance serviceInstance : server) {
String hostName=serviceInstance.getHost();
int gRpcPort=Integer.parseInt(serviceInstance.getMetadata().get("grpc.port"));
ManagedChannel channel=ManagedChannelBuilder.forAddress(hostName,gRpcPort).usePlaintext(true).build();
UserServiceBlockingStub stub=UserServiceGrpc.newBlockingStub(channel);
UserDetail user=UserDetail.newBuilder()
.setName("Thamira")
.setEmail("Thamira1005#gmail.com")
.setAge(24).setGender(Gender.Male)
.setPassword("password").build();
u=stub.createUser(user);
}
return ResponseEntity.ok("User "+u);
}
we can change register as a consul or eureka. This method support both of that.