So I have a bean definition for a class and an autowiring of the same class. Can you tell me if these are separate. I think they are, but it does not make sense with the rest of the code (I am following a tutorial).
#Bean
public OAuth2RestTemplate googleOpenIdTemplate(final OAuth2ClientContext clientContext) {
final OAuth2RestTemplate template = new OAuth2RestTemplate(googleOpenId(), clientContext);
return template;
}
#Autowired
private OAuth2RestTemplate restTemplate;
The two snippets of code would created two different instances of the same class with DIFFERENT configurations, correct?
If I had
OAuth2RestTemplate instance = (OAuth2RestTemplate) context.getBean(googleOpenIdTemplate)
I would be retrieving a bean with the same configurations (singleton vs prototype) whereas in the first case, I would just get a bean of OAuth2RestTemplate without the same configurations.
Related
I have the following code:
This is my first class that will to call the
#Component
class DefaultBridge #Autowired constructor(
private val clientConfig: Config,
private val client: world.example.Client
) : Bridge {
override fun doEpicStuff(): String {
val request = createRequest(...)
val response = client.makeCall(request)
return response.responseBody
}
}
The Client being used (world.example.Client) then has the following piece of code:
public class Client {
#Autowired
private RestTemplate restTemplate;
public Response makeCall(Request request) {
restTemplate.exchange(....)
}
}
When running the code. I get the following Error:
NoSuchBeanDefinitionException: No qualifying bean of type
'org.springframework.web.client.RestTemplate' available: expected at
least 1 bean which qualifies as autowire candidate. Dependency
annotations:
{#org.springframework.beans.factory.annotation.Autowired(required=true)}
Where should I declare the bean when the constructor is autowired?
why won't spring automatically create the bean?
I need help understanding the problem so please don't just post the solution.
With Spring dependency injection you can inject a instance of a bean.
In Spring it's called Inversion of Control (IoC) principle. IoC is also known as dependency injection (DI).
You can define depencenies for your bean with member variable or constuctor variables. There are differnt possibilities, for example #Autowire as annotation for member variables like your usage.
The container then injects those dependencies when it creates your bean.
Attention, however, it is necessary that the spring container knows how the dependency to be injected. There are many ways to teach the container this. The simplest variant is to provide a #Bean producer method in a #Configuration class. Spring container "scans" all #Configurations at the start of the container and "registers" the #Bean producer.
Nobody has done a producer for RestTemplate. Not Spring self and also no other lib. With many other beans you use, this has already been done, not with RestTemplate. You have to provide a #Bean producer for RestTemplate.
Do this in a new #Configuration or in one of your existing #Configuration.
A #Configuration indicates that a class declares one or more #Bean methods and may be processed by the Spring container to generate bean definitions and service requests for those beans at runtime, for example:
#Configuration
public class RestTemplateConfig {
#Bean
public RestTemplate restTemplate() {
// New instance or more complex config
return new RestTemplate();
}
}
Define RestTemplate as a bean in your configuration class.
I came across a strange behaviour with respect to #Bean and #Autowired in my #Configuration class. My web project structure is like
Controller → Service → Repository
In my Service I have a dependency on ObjectMapper
#Autowired
public ServiceClass(final ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
}
Since I want to use a Java 8 optional class while deserializing, I wanted to register Jdk8Module. So I created a configuration class like this:
#Configuration
public class JacksonConfig {
#Bean
public ObjectMapper objectMapper(final ObjectMapper objectMapper) {
objectMapper.registerModule(new Jdk8Module());
return objectMapper;
}
}
I initially thought that Spring will inject the objectMapper instance which it has, which I can manipulate and return it, so that when I autowire it in my service class, I get the updated instance of ObjectMapper.
But I get a cyclic dependency error. This is understandable because, my bean configuration depends on objectmapper and returns an objectmapper.
But it is surprising, if I change the method to have #Autowired instead of #Bean, Spring doesn't complain and works as expected.
#Autowired
public ObjectMapper objectMapper(final ObjectMapper objectMapper) {
objectMapper.registerModule(new Jdk8Module());
return objectMapper;
}
Why is that?
The #Bean annotation goal is to provide beans from the Spring BeanFactory. When a method is annotated #Bean, it is supposed to return a new instance of an object. It can use paramaters if Spring is able to instantiate them too.
In your example, when you declare
#Bean
public ObjectMapper objectMapper(final ObjectMapper objectMapper) {
objectMapper.registerModule(new Jdk8Module());
return objectMapper;
}
It means your ObjectMapper is a bean (of course) that takes a parameter which is an instance of ObjectMapper and Spring knows ObjectMapper so it can instantiate it using... the very same method. Here is your cyclic dependency.
In the case of #Autowired, Spring uses an ObjectMapper as a parameter of your method that is already in the BeanFactory. That's why it removes the cyclic dependency.
I hope I'm clear enough.
Little reference here : https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/Bean.html
In
#Autowired
public ObjectMapper objectMapper(final ObjectMapper objectMapper) {
objectMapper.registerModule(new Jdk8Module());
return objectMapper;
}
Someone else is injecting an ObjectMapper (maybe Spring) to this method. I think the Autowired annotation is not necessary in this case, Spring knows you want to inject a bean here.
You aren't creating new beans in this case so you will not have a cyclic dependency error here.
If you want to create a new one, maybe you should play with #Qualifier.
More info: https://dzone.com/articles/spring-configuration-and
We have the following client configuration for our oauth2 clients in place that worked quite well with spring boot 1.4.0:
#Configuration
#ConfigurationProperties(prefix = "pmc.oauth.client")
public class OAuthClientConfig {
#NotNull
private String scope;
#NotNull
private String clientSecret;
#NotNull
private String clientId;
#NotNull
private String accessTokenUri;
private int clientReadTimeout = 60000;
private int clientConnectTimeout = 60000;
#Bean
public OAuth2ProtectedResourceDetails oAuth2ProtectedResourceDetails() {
ClientCredentialsResourceDetails resourceDetails = new ClientCredentialsResourceDetails();
resourceDetails.setAccessTokenUri(accessTokenUri);
resourceDetails.setClientId(clientId);
resourceDetails.setClientSecret(clientSecret);
resourceDetails.setScope(Collections.singletonList(scope));
return resourceDetails;
}
#Bean
public OAuth2ClientContext oauth2ClientContext() {
DefaultOAuth2ClientContext defaultOAuth2ClientContext = new DefaultOAuth2ClientContext();
return defaultOAuth2ClientContext;
}
#Bean
public OAuth2RestTemplate oAuth2RestTemplate(OAuth2ProtectedResourceDetails oAuth2ProtectedResourceDetails, OAuth2ClientContext oauth2ClientContext) {
OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(oAuth2ProtectedResourceDetails, oauth2ClientContext);
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
restTemplate.setRequestFactory(factory);
return restTemplate;
}
}
After updating to Spring-Boot 1.4.1 I've noticed that when autowiring the OAuth2RestTemplate another implementation of OAuth2ProtectedResourceDetails takes precedence (due to the org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ProtectedResourceDetailsConfiguration - autoconfiguration which marks a bean of AuthorizationCodeResourceDetails as primary) over our own defined bean of type ClientCredentialsResourceDetails.
I know I can fix this by not autowiring the resourceDetails and clientContext for the rest template bean and supplying the concrete implementations directly but I was just wondering whether we are configuring our rest template in a way that was not intended by the spring team?
Any thoughts on how to properly configure our rest template for the client_credentials flow?
Cheers,
Ben
I was struggling with the same issue. However, I found that if you add the annotation #EnableOAuth2Client annotation along with:
security.oauth2.client.grant-type = client_credentials
you get the proper injected ClientCredentialsResourceDetails details instance rather than the AuthorizationCodeResourceDetails. In addition, trying to exclude the OAuth2ProtectedResourceDetailsConfiguration does not work. It is a package private class. If you try to exclude it by name, you will get an error stating it is not an auto configuration class. Look at the code for OAuth2RestOperationsConfiguration class. It is what determines which resource to allocate based on inspecting properties within the security.oauth2.client prefix.
I stuck into the same issue right now. My solution is to use a named bean for my ResourceDetails bean and use #Qualifier to inject the proper one when I'm creating the rest template (in your case in the parameters of the oAuth2RestTemplate method).
It would be nice to know the exact cause of this problem with the version upgrade between 1.4.0 and 1.4.1 though.
According to this answer, one RedisTemplate cannot support multiple serializers for values. So I want to create multiple RedisTemplates for different needs, specifically one for string actions and one for object to JSON serializations, to be used in RedisCacheManager. I'm using Spring Boot and the current RedisTemplate is autowired, I'm wondering what's the correct way to declare a second RedisTemplate instance sharing the same Jedis connection factory but has its own serializers?
Tried something like this in two different components,
Component 1 declares,
#Autowired
private RedisTemplate redisTemplate;
redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer(Instance.class));
Component 2 declares,
#Autowired
private StringRedisTemplate stringRedisTemplate;
In this case the two templates actually are the same. Traced into Spring code and found component 1's template got resolved to autoconfigured stringRedisTemplate.
Manually calling RedisTemplate's contructor and then its afterPropertiesSet() won't work either as it complains no connection factory can be found.
I know this request probably is no big difference from defining another bean in a Spring app but not sure with the current Spring-Data-Redis integration what's the best way for me to do. Please help, thanks.
you can follow two ways how to use multiple RedisTemplates within one Spring Boot application:
Named bean injection with #Autowired #Qualifier("beanname") RedisTemplate myTemplate and create the bean with #Bean(name = "beanname").
Type-safe injection by specifying type parameters on RedisTemplate (e.g. #Autowired RedisTemplate<byte[], byte[]> byteTemplate and #Autowired RedisTemplate<String, String> stringTemplate).
Here's the code to create two different:
#Configuration
public class Config {
#Bean
public RedisTemplate<String, String> stringTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, String> stringTemplate = new RedisTemplate<>();
stringTemplate.setConnectionFactory(redisConnectionFactory);
stringTemplate.setDefaultSerializer(new StringRedisSerializer());
return stringTemplate;
}
#Bean
public RedisTemplate<byte[], byte[]> byteTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<byte[], byte[]> byteTemplate = new RedisTemplate<>();
byteTemplate.setConnectionFactory(redisConnectionFactory);
return byteTemplate;
}
}
HTH, Mark
I am using Spring Cloud Angel.SR4. My Configuration class for creating an OAuth2RestTemplate bean is as follows:
#Configuration
public class OAuthClientConfiguration {
#Autowired
private MyClientCredentialsResourceDetails resource;
public OAuthClientConfiguration() {
}
#Bean
#Qualifier("MyOAuthRestTemplate")
public OAuth2RestTemplate restTemplate() {
return new OAuth2RestTemplate(this.resource);
}
}
This configuration is totally fine since I am using this RestTemplate in a Feign RequestInterceptor for injecting access tokens to the feign requests. The problem is that when I annotate an autowired OAuth2RestTemplate with #LoadBalanced the dependency injection engine raises a NoSuchBeanDefinitionException exception. For example, the following would raise an exception:
#LoadBalanced
#Autowired
#Qualifier("MyOAuthRestTemplate")
private OAuth2RestTemplate restTemplate;
and when I remove the #LoadBalanced, everything works fine. What is wrong with #LoadBalanced? Do I need any additional configurations (I already have #EnableEurekaClient)?
I found a workaround. The problem was that I had misunderstood the #LoadBalanced annotation. This is just a qualifier for the auto-created load-balanced RestTemplate bean, and it would not create a proxy around the annotated RestTemplate for injecting the load balancing capability.
After seeing this https://github.com/spring-cloud/spring-cloud-commons/blob/v1.0.3.RELEASE/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/LoadBalancerAutoConfiguration.java, I revised my OAuth2RestTemplate bean definition as follows, and it solved the problem.
#Bean
#Qualifier("MyOAuthRestTemplate")
public OAuth2RestTemplate restTemplate(RestTemplateCustomizer customizer) {
OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(this.resource);
customizer.customize(restTemplate);
return restTemplate;
}
I used #LoadBalanced with restTemplate in spring cloud with ribbon behind the scenes.
adding #LoadBalanced in the bean definition it works
like this:
in my class i have
#Autowired
#LoadBalanced
#Qualifier("bookRepositoryServiceRestTemplate") private RestTemplate bookRepositoryServiceRestTemplate;
and in my configuration class i have:
#Configuration
public class ServiceConfig {
#Bean
#LoadBalanced
public RestTemplate bookRepositoryServiceRestTemplate(SpringClientFactory clientFactory, LoadBalancerClient loadBalancer){
RibbonClientHttpRequestFactory ribbonClientHttpRequestFactory = new RibbonClientHttpRequestFactory(clientFactory,loadBalancer);
return new RestTemplate(ribbonClientHttpRequestFactory);
}
....
}
this works for me
I hope that this can help