When researching how to customize Spring's RestTemplate, I came across the 4.15.1. RestTemplate Customization section of the official Spring Boot docs (see excerpt and link at the bottom of this question).
It says "make sure to configure your custom instance with a RestTemplateBuilderConfigurer". I searched for "RestTemplateBuilderConfigurer" but found nothing, so apparently this is something that I need to implement.
Just looking at the signature, and comparing to RestTemplateBuilder#configure (link), it seems like the idea is that configurer.configure takes a RestTemplateBuilder and merges the configuration with Spring Boot's default RestTemplateBuilder configuration.
I could write a bunch of imperative code to do this configuration merging, but I suspect that I'm missing something here and there's a much easier way to do this with some out-of-the-box Spring features.
So, how can I implement a RestTemplateBuilderConfigurer? Or did I misunderstand the docs?
4.15.1. RestTemplate Customization (link)
Finally, you can also create your own RestTemplateBuilder bean. To
prevent switching off the auto-configuration of a RestTemplateBuilder
and prevent any RestTemplateCustomizer beans from being used, make
sure to configure your custom instance with a
RestTemplateBuilderConfigurer. The following example exposes a
RestTemplateBuilder with what Spring Boot would auto-configure, except
that custom connect and read timeouts are also specified:
#Bean
public RestTemplateBuilder restTemplateBuilder(RestTemplateBuilderConfigurer configurer) {
return configurer.configure(new RestTemplateBuilder()).setConnectTimeout(Duration.ofSeconds(5))
.setReadTimeout(Duration.ofSeconds(2));
}
Related
I understand that using #SpringbootTest I raise whole spring contex during test, or In my case using #SpringBootTest(classes = SomeController.class) I raise only one bean -> SomeController. If this controller have some dependencies I need to mock them up. Using annotation #WebMvcTest(SoneController.class) I will (based on my knowledge) achieve the same goal.
Question is: Are there any differences between those two annotations used in provided example?
There's a clear difference between #SpringBootTest(classes = SomeController.class) and #WebMvcTest(SomeController.class).
#SpringBootTest(classes = SomeController.class) - starts a server (i.e like Tomcat) + spring application context with the component SomeController.class. In addition to the controller, you should normally specify the context configuration to successfully start the whole app (For ex: when you don't specify the classes, it falls back to #SpringBootApplication).
#WebMvcTest(SomeController.class) - only starts the web layer of the application with SomeController.class.
What's the difference?
#SpringBootTest tests are usually integration tests, you start the full spring-boot application and test against that black box. You can still tweak the application startup by providing configuration, properties, web server type etc in the annotation parameters.
But #WebMvcTest(SomeController.class) is usually a unit test for your controller. These are lightweight and fast. The dependencies like #Service classes are mocked in such tests.
This is a good starting point - https://spring.io/guides/gs/testing-web/
There are several subtle differences between these two ways.
But you will discover a part of them only randomly when you will encounter problems such as bean initialization exception during the spring boot context init or a NullPointerException rising during the test execution.
To make things simpler, focus on intention.
When you write that :
#SpringBootTest(classes = SomeController.class)
you will make Spring to init only the SomeController bean instance.
Is it desirable to test a controller ?
Probably no since you need a way to invoke the controller with a controller approach.
For that a MockMvc instance would help.
With WebMvcTest you get that bean additionally loaded in the test context.
So that way is preferable :
#WebMvcTest(SomeController.class)
public class SomeControllerTest{
#Autowired
private MockMvc mvc;
...
}
Of course you could get a similar behavior with #SpringBootTest and some additional classes but it will be just an overhead : the #WebMvcTest specialized annotation is enough.
At last why make the reading of the test class harder for your follower ?
By weaving a contrived way of using spring boot test annotation, chances are good to come there.
I think for answering your question enough just read the Javadoc for both of these annotations:
1. #WebMvcTest
Annotation that can be used for a Spring MVC test that focuses only on Spring MVC components.
Using this annotation will disable full auto-configuration and instead apply only configuration relevant to MVC tests (i.e. #Controller, #ControllerAdvice, #JsonComponent, Converter/GenericConverter, Filter, WebMvcConfigurer and HandlerMethodArgumentResolver beans but not #Component, #Service or #Repository beans).
By default, tests annotated with #WebMvcTest will also auto-configure Spring Security and MockMvc (include support for HtmlUnit WebClient and Selenium WebDriver). For more fine-grained control of MockMVC the #AutoConfigureMockMvc annotation can be used.
#SpringbootTest
Annotation that can be specified on a test class that runs Spring Boot based tests. Provides the following features over and above the regular Spring TestContext Framework:
Uses SpringBootContextLoader as the default ContextLoader when no specific #ContextConfiguration(loader=...) is defined.
Automatically searches for a #SpringBootConfiguration when nested #Configuration is not used, and no explicit classes are specified.
Allows custom Environment properties to be defined using the properties attribute.
Allows application arguments to be defined using the args attribute.
Provides support for different webEnvironment modes, including the ability to start a fully running web server listening on a defined or random port.
Registers a TestRestTemplate and/or WebTestClient bean for use in web tests that are using a fully running web server.
I'm trying to write a integration test for my SpringBoot microservice that interacts with another service inside the product ecosystem.
Since this kind of testing is consider function/integration testing (depending on what nomenclature you use) it is usually done on some development environment.
However, I wanted to test a basic interaction between my service and a STUB/dummy app which are connected with RPC (so not exactly a typical TestRestTemplate test).
I know that there is a way to embed a service while booting up the Spring Context but have never done it by myself.
Does anyone have any experience with the upper or maybe a few helpful links where I can explore.
I have used WireMock in tests to mock services external to what I want to test that communicate over HTTP.
My test class annotated with #SpringBootTest is also annotated with #ContextConfiguration. In the classes attribute #ContextConfiguration I explicitly specify the configuration classes required to set up the Spring Context for the test in question. Here I can also include additional configuration classes in which I create beans only used in the test. In test configuration classes I can also override beans for the purpose of the test, creating mock beans etc.
Note that Spring Boot 2.1 and later disables bean overriding by default. It can be enabled by setting the following property to true:
spring.main.allow-bean-definition-overriding=true
To set the property for a single test, use the #TestPropertySource annotation like this:
#TestPropertySource(properties = {
"spring.main.allow-bean-definition-overriding=true"
})
This is actually a part of the question that I asked here, which went unanswered and ended up being tagged as duplicate.
Issue : I am able to use the JavaMailSender just by annotating it with #Autowired. I didn't expose it through any configuration class.
#Component
public class EmailUtil {
#Autowired
private JavaMailSender javaMailSender;
}
However, the below doesn't work unless BCryptPasswordEncoder bean is exposed via a configuration class.
#Controller
public class UserController {
#Autowired
private BCryptPasswordEncoder encoder;
}
I'm using Spring Boot 1.5.8
My doubts are:
why JavaMailSender " was successfully injected, whereas the BCryptPasswordEncoder /PasswordEncoder autowiring was successful only after exposing it via a configuration class.
How do I know for sure when to expose beans explicitly via a configuration class and when not to ? How do I know which beans need to be exposed ?
Any sort of help/guidance is highly appreciated.
Basically, an implementation of JavaMailSender is exposed as part of the Spring Boot Autoconfiguration. This is noted in the documentation here:
The Spring Framework provides an easy abstraction for sending email by using the JavaMailSender interface, and Spring Boot provides auto-configuration for it as well as a starter module.
This is not the case with BCryptPasswordEncoder.
If I had to guess, I would think that this approach was chosen because:
Few developers would need to reimplement the JavaMailSender functionality for sending Emails
Many developers choose different hashing algorithms based on speed and security needs, though the BCryptPasswordEncoder is recommended.
Since various developers might opt for an alternative PasswordEncoder, having a BCryptPasswordEncoder already configured would necessitate using #Primary on the one you actually wanted to use (in the case of writing something like #Autowired PasswordEncoder encoder), which might lead to confusion.
How do I know for sure when to expose beans explicitly via a configuration class and when not to ? How do I know which beans need to be exposed ?
Read the reference documentation for the particular bean - it should state whether it is pre-configured or not (and under which conditions, i.e. in the presence of some starter package). Barring that, you might check the implementation to see if there are any components which implement the interface of the bean you wish to inject.
UPDATE: I actually went through some of the sources and noticed that the interfaces implemented by BCryptPasswordEncoder on one hand, and Md5PasswordEncoder/ShaPasswordEncoder on the other, are in different packages, the latter being deprecated. In this case it may be safe to assume that there is no autoconfiguration being done for BCryptPasswordEncoder since:
It could lead to a great deal of confusion to see one interface be implemented, when a completely different one in a different package is being referred to (i.e. different methods being implemented)
The 'default values' that should be used when hashing a password would likely differ from one developer to another, which would necessitate manual configuration anyway.
I migrate project from XML Spring Integration configuration to Java DSL. I prepared some integration tests beforehand. So I can do the migration safely step-by-step.
At some point after moving this XML connector definition
<int:publish-subscribe-channel id="upstreamAckChannel" />
to Java Spring Configuration
#Bean
public PublishSubscribeChannel upstreamAckChannel() {
return MessageChannels.publishSubscribe().get();
}
my integration flow stopped resend test messages to my tests.
After some time and experiments I realized that my Spring Java configuration must have #EnableIntegration annotation together with usual Spring #Configuration annotation for properly work.
The question is what is #EnableIntegration annotation semantic? When I can not use it and when I must use?
I could find only this small Configuration paragraph in official reference manual. Unfortunately, description isn't clear.
The PublishSubscribeChannel class exists inside of the Spring Integration project. The #EnableIntegration annotation is used to adopt a default configuration for Spring Integration, so typically when using Spring Integration you'll want to add it (unless you're using a piece of Spring Integration that doesn't require a context--unlikely). The only time you might want to forego it is if you want to do your own configuration from scratch.
Spring Boot has preconfigured metrics. As I know it uses http://metrics.codahale.com/ library. How can I get MetricRegistry object to add my custom metrics?
Spring boot now supports Codahale Metrics out of the box.
See http://docs.spring.io/spring-boot/docs/1.0.0.RC5/reference/htmlsingle/#production-ready-code-hale-metrics
Spring Boot Does not use Codahale Metrics (yet). The plan is to support it as an option if it is on the classpath. If you prefer to do it that way then a MetricRegistry will be in the application context and you can simply #Autowire it and use it. You can see that work in progress on a branch in my fork.
The Boot interfaces for adding metrics are GaugeService and CounterService. You inject those and use them to record measurements. When Codahale gets support then this will be the recommended entry point for that as well, so you can get started using it now and add the Codahale stuff later if you want.
There's some integration magic accomplished by http://www.ryantenney.com/metrics-spring/ that wires codahale metrics into the actuator /health endpoint.
With this dependency included,
compile 'com.ryantenney.metrics:metrics-spring:3.0.0-RC2'
you can "enableMetrics" in your application configuration
#EnableMetrics
public class ApplicationConfiguration {
...
This allows you to time each request with the #timed annotation:
#Timed
#RequestMapping(method=RequestMethod.GET)
public #ResponseBody
Foo foo() {
...
and to have your other interactions with MetricRegistry aggregate into the actuator /health endpoint.
I've put together an example application which implements this integration:
https://github.com/benschw/consul-cluster-puppet/tree/master/demo
and written a more in depth tutorial here:
http://txt.fliglio.com/2014/10/spring-boot-actuator/