I'm using Spring Boot 1.5.9 version and Feign and Fallback.
I get a strange error when calling a single service through the Feign client.
Help, please.
My Feign config
#Configuration
#Import(HeaderConverter.class)
public class SecuritiesFeignConfig {
private final HeaderConverter headerConverter;
public SecuritiesFeignConfig(HeaderConverter headerConverter) {
this.headerConverter = headerConverter;
}
#Bean
public RequestInterceptor requestInterceptor() {
return requestTemplate -> headerConverter.getCallContextHeaders().forEach(requestTemplate::header);
}
#Bean
public Decoder feignDecoder() {
HttpMessageConverter<?> jacksonConverter = new MappingJackson2HttpMessageConverter(customObjectMapper());
ObjectFactory<HttpMessageConverters> objectFactory = () -> new HttpMessageConverters(jacksonConverter);
return new ResponseEntityDecoder(new SpringDecoder(objectFactory));
}
private ObjectMapper customObjectMapper() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS, true);
objectMapper.configure(DeserializationFeature.FAIL_ON_INVALID_SUBTYPE, false);
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
objectMapper.registerModule(new JavaTimeModule());
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
return objectMapper;
}
}
and my main config class in app
#Configuration
#Import(FiltersConfig.class)
public class frameworkConfig {
#Bean
#Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public MSACallContextImpl callContext() {
return new MSACallContextImpl();
}
#Bean
public CallContextCreator callContextCreator() {
return new CallContextCreator();
}
#Bean
#Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public ContextHeadersBuilder contextHeadersBuilder(MSACallContextImpl callContextImpl) {
return new ContextHeadersBuilder(callContextImpl);
}
#Bean
public RequestContextListener requestContextListener() {
return new RequestContextListener();
}
}
But when I try to make a service call through the Feign client, I get the following error
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.contextHeadersBuilder': Scope 'request' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
I found the solution for the current problem.
Need to add into the application properties file
hystrix:
command:
default:
execution:
timeout:
enabled: false
isolation:
thread:
timeoutInMilliseconds: 6000
strategy: SEMAPHORE
As it seems like Bean creation is not taking place and the #Autowired is not able to create the OBJECT so try
#Service Annotation will be missing as it worked for me when i put #Service Annotation in Class level
Related
I'm using spring-integration-sftp and my goal is to push local file to SFTP (just that for now, without confirmation or anything else). My configuration is as follows:
#EnableIntegration
#IntegrationComponentScan
#Configuration
#Lazy
public class SftpConfiguration {
#Bean(name = "toSftpChannel")
public MessageChannel sftpMessageChannel() {
return new DirectChannel();
}
#Bean
public DefaultSftpSessionFactory sftpSessionFactory(
#Qualifier("sftpDestination") SftpPropertiesService sftpPropertiesService
) {
DefaultSftpSessionFactory factory = new DefaultSftpSessionFactory();
factory.setHost(sftpPropertiesService.getServiceHost());
factory.setPort(22);
factory.setUser(sftpPropertiesService.getUsername());
factory.setPassword(sftpPropertiesService.getPassword());
factory.setAllowUnknownKeys(true);
return factory;
}
#Bean
public SftpRemoteFileTemplate sftpRemoteFileTemplate(DefaultSftpSessionFactory dssf,
#Value("${sftp.output.directory}") String outputDirectory) {
SftpRemoteFileTemplate template = new SftpRemoteFileTemplate(dssf);
template.setRemoteDirectoryExpression(new LiteralExpression(outputDirectory));
return template;
}
#Bean
#ServiceActivator(inputChannel = "toSftpChannel")
public MessageHandler handler(SftpRemoteFileTemplate sftpRemoteFileTemplate) {
SftpOutboundGateway gateway =
new SftpOutboundGateway(sftpRemoteFileTemplate, Command.PUT.getCommand(), "payload");
gateway.setFileExistsMode(FileExistsMode.FAIL);
return gateway;
}
#MessagingGateway
public interface OutputSftpGateway {
#Gateway(requestChannel = "toSftpChannel")
void sendToSftp(File file);
}
}
and sending is just
private final OutputSftpGateway outputSftpGateway;
...
outputSftpGateway.sendToSftp(file);
When I'm running my code I at first get
A bean definition with name 'toSftpChannel' exists, but failed to be created; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'toSftpChannel': Requested bean is currently in creation: Is there an unresolvable circular reference?
which is kind of expected with lazy init (though still will have to fix it), but at the second and subsequent runs I'm getting stuck with
Exception occurred during request processing. org.springframework.messaging.MessageDeliveryException. Dispatcher has no subscribers for channel 'application.toSftpChannel'.; nested exception is org.springframework.integration.MessageDispatchingException: Dispatcher has no subscribers
I'll honestly admit that I'm new with Spring messaging magic, so the cause is probably very stupid but can someone give me a hint why this is happening and how can I fix it?
The #Lazy may have some effect on those beans initialization. Consider to divide your configuration logic to extract only those beans which cannot live with #Lazy. And don't apply it for those Spring Integration components.
I am using Spring Boot 1.5.9.
Is there a way to turn on/off #Controller and #Services?
Something such as #ConditionalOnProperty, #Conditional for beans.
#ConditionalController // <--- something like this
#RestController
public class PingController {
#Value("${version}")
private String version;
#RequestMapping(value = CoreHttpPathStore.PING, method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public ResponseEntity<Map<String, Object>> ping() throws Exception {
HashMap<String, Object> map = new HashMap<>();
map.put("message", "Welcome to our API");
map.put("date", new Date());
map.put("version", version);
map.put("status", HttpStatus.OK);
return new ResponseEntity<>(map, HttpStatus.OK);
}
}
Then use some configuration bean to load it up.
#ConditionalOnProperty should work for Controller (or Service) as well, since it is also a Spring bean.
Add to your PingController
#ConditionalOnProperty(prefix="ping.controller",
name="enabled",
havingValue="true")
#RestController
public class PingController {...}
and to the application.properties to turn it on/off
ping.controller.enabled=false
do you want to try and load the bean programmatically instead?
you could access the application context using one of the two mechanisms
#Autowired private ApplicationContext appContext;
or creating something like a bean factory by extending ApplicationAware
public class ApplicationContextProvider implements
ApplicationContextAware{
once you have a handle to the application context you can add a bean to the context programmatically.
By default in Spring, all the defined beans, and their dependencies, are created when the application context is created.
We can turn it off by configuring a bean with lazy initialization, the bean will only be created, and its dependencies injected, once they're needed.
You can enable lazy initialization by configuring application.properties.
spring.main.lazy-initialization=true
Setting the property value to true means that all the beans in the application will use lazy initialization.
All the defined beans will use lazy initialization, except for those that we explicitly configure with #Lazy(false).
Or you can do it through the #Lazy approach. When we put #Lazy annotation over the #Configuration class, it indicates that all the methods with #Bean annotation should be loaded lazily.
#Lazy
#Configuration
#ComponentScan(basePackages = "com.app.lazy")
public class AppConfig {
#Bean
public Region getRegion(){
return new Region();
}
#Bean
public Country getCountry(){
return new Country();
}
}
I have a Configuration that initializes a Request Scope bean
#Configuration
public class ConfigurationClass {
#Bean(name = "TestBean")
#Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public TestBean getTestBean() {
...
}
}
And a ClientClass that uses the above bean.
#Repository
public class ClientClass {
#Resource(name ="TestBean")
private TestBean testBean;
public void accessRequestBeanMethod() {
testBean.testMethod();
}
}
The request that handles HTTP request spawns n threads that individually call clientClass.accessRequestBeanMethod(). Spring intiailizes a new TestBean instance in each of the n threads. The understanding I had with Request scope is that the bean would be initialized only once for HTTP request, but seems like it is being intiantiated for every thread. I wish to implement caching of the bean for all the spawned threads in the request thread. How can I achieve it?
I am consuming a Soap WebService using spring WebServiceTemplate & below is the bean creation and my bean class but dont know why i am unable to get the value of Default Uri.
Can someone please help with this thing.
ServiceContext.java
#Bean
public Jaxb2Marshaller marshaller() {
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setContextPath("com.canaldigital.tsi.schema.psd.psd_managecustomer.v2");
return marshaller;
}
#Bean
public SaajSoapMessageFactory messageFactory() {
SaajSoapMessageFactory factory=new SaajSoapMessageFactory();
factory.setSoapVersion(SoapVersion.SOAP_12);
return factory;
}
#Bean
public ManageService voucherService(Jaxb2Marshaller marshaller,SaajSoapMessageFactory messageFactory) {
ManageService service = new ManageService();
service.setDefaultUri("http://localhost:7001/CustomerService?WSDL");
service.setMarshaller(marshaller);
service.setUnmarshaller(marshaller);
service.setMessageFactory(messageFactory);
return service;
}
ManageService.java
public class ManageService extends WebServiceGatewaySupport {
try{
System.out.println("Finalyy calllingggg service: "+getWebServiceTemplate());
System.out.println("WebService template URI is: ---- "+getWebServiceTemplate().getDefaultUri());
JAXBElement<GetCustomerInfoRequestType> mustangRequst=new createGetCustomerInfoRequest(customer);
(JAXBElement<GetCustomerInfoResponseType>) getWebServiceTemplate().marshalSendAndReceive(mustangRequst);
}catch(Exception e){
e.printStackTrace();
}
}
you should use #Autowired when you call your client that extends WebServiceGatewaySupport
Check that you don't have #Service annotation on the service.
I want to create a UUID that is unique in a request life cycle.
To do this, I create a UUID bean with the #Scope("request") annotation.
#Bean
#Scope(scopeName = WebApplicationContext.SCOPE_REQUEST)
public UUID requestUUID() {
return UUID.randomUUID();
}
I want to access this bean in my controller. So I inject it with #Autowired.
This works fine.
#Controller
public class DashboardController {
#Autowired
UUID uuid;
#Autowired
WelcomeMessageService welcomeMessageService;
#Autowired
IssueNotificationService issueNotificationService;
#RequestMapping("/")
public String index(Model model) throws InterruptedException, ExecutionException {
System.out.println(uuid);
PortalUserDetails userLog = getPortalUserDetails();
BusinessObjectCollection<WelcomeMessage> welcomeMessages = welcomeMessageService.findWelcomeMessages(
20,
0,
userLog.getZenithUser(),
userLog.getConnectionGroup().getConnectionGroupCode(),
"FR");
if(welcomeMessages!=null) {
model.addAttribute("welcomeMessages", welcomeMessages.getItems());
}
BusinessObjectCollection<IssueNotification> issueNotifications =
issueNotificationService.findIssueNotifications(userLog.getZenithUser());
if(welcomeMessages!=null) {
model.addAttribute("welcomeMessages", welcomeMessages.getItems());
}
model.addAttribute("issueNotifications", issueNotifications);
return "index";
}
}
The controller call multiple services. Every service use a RestTemplate bean. In this RestTemplate bean, I want to get the UUID.
#Component
public class ZenithRestTemplate extends RestTemplate {
#Autowired
private UUID uuid;
public void buildRestTemplate() {
List restTemplateInterceptors = new ArrayList();
restTemplateInterceptors.add(new HeaderHttpRequestInterceptor("UUID", uuid.toString()));
this.setInterceptors(restTemplateInterceptors);
}
}
When I try to inject the UUID here, I have an error :
Error creating bean with name 'zenithRestTemplate': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private java.util.UUID com.geodis.rt.zenith.framework.webui.service.ZenithRestTemplate.uuid; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'requestUUID': Scope 'request' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
What can I do to access my UUID bean inside the RestTemplate bean ?
My project use Spring-MVC, Spring-boot with java configuration.
I already tried to add a RequestContextListener but it doesn't solve the problem.
#Bean public RequestContextListener requestContextListener(){
return new RequestContextListener();
}
I think you need to mark your UUID request scoped bean like:
#Scope(scopeName = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
Where controller is singleton scoped bean you are injecting request scoped bean in it. As singleton beans are injected only once per their lifetime you need to provide scoped beans as proxies which takes care of that.
Another option is to instead use the org.springframework.web.context.annotation.RequestScope annotation:
#Target({ElementType.TYPE, ElementType.METHOD})
#Retention(RetentionPolicy.RUNTIME)
#Documented
#Scope(WebApplicationContext.SCOPE_REQUEST)
public #interface RequestScope {
#AliasFor(annotation = Scope.class)
ScopedProxyMode proxyMode() default ScopedProxyMode.TARGET_CLASS;
}
#RequestScope is a meta-annotation on #Scope that 1) sets the scope to "request" and 2) sets the proxyMode to ScopedProxyMode.TARGET_CLASS so you don't have to do it every time you want to define a request-scoped bean.
Edit:
Note that you may need to add #EnableAspectJAutoProxy on your main configuration class.