How to enable IP lookup - enableLookups in Spring MVC - spring-boot

On Tomcat there is an attribute "enableLookups" to enable IP lookup. I have a program which we have migrated from Tomcat to Spring MVC and I am not getting any idea where can I set this atrribute.
#RequestMapping(method = RequestMethod.GET, path = "/something")
public String something(Model model, HttpServletRequest request) {
String someVar = request.getRemoteHost();
.....
.......
request.getRemoteHost() - returns IP Address instead of host name.

If your Spring Boot application is configured to use an embedded application server, use the WebServerFactoryCustomizer facility to configure the server according to your needs. Some hints specific to Tomcat as embedded server are given in the official Spring Boot guide:
#Component
public class TomcatServerCustomizer
implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> {
#Override public void customize(TomcatServletWebServerFactory tomcatServletWebServerFactory) {
TomcatConnectorCustomizer customizer = connector -> connector.setEnableLookups(true);
tomcatServletWebServerFactory.addConnectorCustomizers(customizer);
}
}
Note, TomcatServletWebServerFactory is available since Spring Boot 2.0.0.

Related

How to config max-delivery-attempts for Spring Boot with Embedded ActiveMQ Artemis?

I would like to config the max-delivery-attempts of dead letter as described in the manual.
I tried Spring Boot with embedded ActiveMQ Artemis JMS server, but cannot figure out how to set max-delivery-attempts value.
After debugging the Configuration instance I finally find the method. Here's the code:
#Configuration
public class RedeliveryConfiguration implements ArtemisConfigurationCustomizer {
#Override
public void customize(org.apache.activemq.artemis.core.config.Configuration configuration) {
Map<String, AddressSettings> addressesSettings = configuration.getAddressesSettings();
// # is the catch all address or default address
addressesSettings.get("#").setMaxDeliveryAttempts(2);
}
}

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.

Does Spring Boot Actuator have a Java API?

We customize the Spring Boot Actuator Info endpoint to include the application version number generated during our Jenkins build. We're using gradle to do this:
if (project.hasProperty('BUILD_NUMBER')) {
version = "${BUILD_NUMBER}"
} else {
version = "0.0.1-SNAPSHOT"
}
That works great for adding the version to the /info endpoint, but I'd like to access it when the application starts and print it to the application log.
I'm hoping the values are exposed in some property value (similar to spring.profiles.active) or through a Java API. That way, I could do something like this:
public class MyApplication{
public static void main(String[] args) throws Exception {
SpringApplication.run(MyApplication.class, args);
ConfigurableEnvironment environment = applicationContext.getEnvironment();
System.out.println(environment.getProperty("spring.fancy.path.to.info.version"));
}
}
Looking through the docs, I'm not finding a way to access these values easily in code. Has anyone else had luck with this?
To get exactly the same properties of an actuator endpoint that are exposed through the REST endpoints, you can inject in one of your classes an instance of the respective endpoint class. In your case, the "right" endpoint class would be the InfoEndpoint. There are analogous endpoint classes for metrics, health, etc.
The interface has changed a little between Spring Boot 1.5.x and Spring Boot 2.x. So the exact fully qualified class name or read method name may vary based on the Spring Boot version that you are using. In Boot 1.5.x, you can find most of the endpoints in the org.springframework.boot.actuate.endpoint package.
Roughly, this is how you could build a simple component for reading your version property (assuming that the name of the property inside the info endpoint is simply build.version):
#Component
public class VersionAccessor {
private final InfoEndpoint endpoint;
#Autowired
public VersionAccessor(InfoEndpoint endpoint) {
this.endpoint = endpoint;
}
public String getVersion() {
// Spring Boot 2.x
return String.valueOf(getValueFromMap(endpoint.info()));
// Spring Boot 1.x
return String.valueOf(getValueFromMap(endpoint.invoke()));
}
// the info returned from the endpoint may contain nested maps
// the exact steps for retrieving the right value depends on
// the exact property name(s). Here, we assume that we are
// interested in the build.version property
private Object getValueFromMap(Map<String, Object> info) {
return ((Map<String, Object>) info.get("build")).get("version");
}
}

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.

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

Resources