I have a Feign client that requests a token from a microservice.
Since I am making multiple calls, I would like to cache the responses received from the Feign client and use Spring Guava caching, but it doesn't seem to work. All I have is the configuration class and the annotation on the Feign client.
I read somewhere on stack overflow that Feign might not support #Cacheable annotation. Is this true?
Finally, I managed to solve my issue.
What I did in the end is :
-> Create new #Service annotated class
-> Inject interface with #FeignClient annotation
-> Put all #Cache related annotations ( using #Caching annotation) on the method that calls methods from the interface.
It works! :)
Annotating Feign clients with #Cacheable now works out of the box with Spring Cloud OpenFeign, as per the documentation, since version 3.1.0 (as part of Spring Cloud 2021.0.0).
You only need to make sure that:
you have configured #EnableCaching
you are using spring-cloud-starter-openfeign 3.1.0+ in your dependencies, so this normally means importing spring-cloud-dependencies version 2021.0.0+ (they switched to calver in 2020)
you are using Spring Boot 2.4.1+ (required for this version of Spring Cloud)
What Bianca supposed to do is to add a #Service annotated class to her project where she can use #cacheable annotation.
The traditional way to use FeignClient is to have only an interface annotated with #FeignClient, and then call these methods form other projects/classes. She has added a #Service annotated class, where she call her feignclients methods caching whatever she want.
Traditional:
FeignClient class:
#FeignClient(name="my_feign-client", url = "http://myurl.com/")
public interface MyFeignClient {
#GetMapping("/test")
public ResponseEntity<String> test() throws FeignException;
Class where to call feign client method:
public class TestClass {
#Autowired
private MyFeignClient myFeignClient ;
public String callTest() {
...
return myFeignClient.test();
}
Bianca's method:
Feign client class remains the same.
Service class with cache:
#Service
#CacheConfig(cacheNames={"test"})
public class TestService {
#Autowired
private MyFeignClient myFeignClient ;
#Cacheable
public String callCachedTest() {
...
return myFeignClient.test();
}
And last, the class to call the cached method, that call feignClient:
public class TestClass {
#Autowired
private TestService testService ;
public String callTest() {
...
return testService.callCachedTest();
}
Related
I am writing a small CRUD in Spring and Java. And I want to use a separate file for writing logic, this is very convenient for me, I did this when developing with NestJS. I have a few questions, is it correct to do this in Spring, or should I do everything inside a function in the controller. And if I write logic in a separate file, I should mark the logic class as #Component and the functions inside it as #Bean, right? I am new to Spring and as I understand it, I have to do this in order for the application to work correctly and my functions to be in the application context.
AuthLogic.java
#Component
public class AuthLogic {
#Bean
public void register() {
// code ...
}
}
AuthController.java
#RestController
public class AuthController {
#RequestMapping(value = "/register", method = RequestMethod.POST)
#ResponseStatus(HttpStatus.CREATED)
public void register(#Valid #RequestBody UserDTO newUser) {
// here I call the register function from AuthLogic
}
}
you can mark your logic class with #Service and use that for example you can make a AuthService and use it like
#Service
public class AuthService{
public returnType login(){
//Logic
}
}
and use this like
#RestController
public class AuthController {
AuthService authService;
#RequestMapping(value = "/register", method = RequestMethod.POST)
#ResponseStatus(HttpStatus.CREATED)
public void register(#Valid #RequestBody UserDTO newUser) {
authService.login();
}
}
You can write your business logic in a new separate file at service layer.
Suppose you name it as AuthService and you mark it with annotation #Service.
#Service
public class AuthService{
}
You can then Autowire it in your controller class.
#RestController
public class AuthController {
#Autowired
AuthService authService;
#RequestMapping(value = "/register", method = RequestMethod.POST)
#ResponseStatus(HttpStatus.CREATED)
public void register(#Valid #RequestBody UserDTO newUser) {
// here I call the register function from AuthLogic
}
}
Using separate files, or classes more importantly, is very recommended in Spring, and I assume most other languages.
The #Bean annotation on AuthLogic.java is unneeded and I think may cause startup or compilation errors.
I would change the name of AuthLogic to AuthLogicImpl, create an interface named AuthLogic with the method signature void register(), and have AuthLogicImpl implement AuthLogic. Then you can create a constructor for AuthController which accepts and AuthLogic parameter and sets it to a private field (note using the interface not the implementation in the constructor).
At the core of Spring is the IoC container. This container holds "beans" that can be injected or autowired into other beans. These beans are an instance of their class and can be used by other beans. Remember Spring uses the singleton pattern, so your beans should be stateless. This allows Spring to handle the application startup for you, so you don't need to write a ton of code creating all the different services/classes and wiring them together, it's all automagically done for you.
There are two key annoitations that you appear to be confused about:
#Component Putting this above a class will create an instance of that class (a bean) and put it into the IoC container. Other beans can access this by accepting the original beans interface in its constructor. So if I put #Component above my class FooImpl which implements Foo, then I can create a class, BarImpl with the constructor public BarImpl(Foo foo) {this.foo = foo} and BarImpl can use any public method of Foo (which will use FooImpl's implementation).
#Bean this is to be put on a method of a class that is annotated with #Configuration. This tells Spring that this method should be run at startup, and this method will return a bean that Spring should add to the IoC container. This is a popular way of configuring a bean that requires some parameters, such as the bean that manages the connection to a third party service or datastore, especially when that there is a little bit of logic that needs to go into creating the bean.
Note that the above is very broad, and there are some specifics if you need to dig deep into the spring framework, so there will be more clarification in the Spring documentation or you dig into some established Spring project. However it should suffice to answer the broad question of what is going on with #Component and #Bean.
There is no specific layout or code structure for Spring Boot Projects. However, there are some best practices followed by developers that will help us too. You can divide your project into layers like service layer, entity layer, and repository layer.
We use the entity layer to write all model and POJO classes. We annotate them with #Entity.
We use #Repository to indicate that this is a repository interface that is used to do some basic CRUD operations.
Sidenote:- You don't have to write #Repository for classes that implement or interfaces that extends Repository interfaces provided by Spring Boot framework.
We use #Service to say that this is the service class where your all business logic will be present.
We use the controller layer to receive HTTP requests and send back HTTP Responses or views.
You can learn and understand more from here
You can refer to this Image to understand the structure
project structure
We are using Open Feign in our application, which is running on Spring Boot 2.0.6 and Spring Cloud Finchley.SR2.
We need all of the Feign Clients to add a token from the security context in the header of every call, so we created a configuration, which produces a global Interceptor for all clients:
#Configuration
#Import({FeignClientsConfiguration.class})
public class FeignConfig {
#Value("${a.spring.config}")
private int minTokenLifespan;
#Autowired
private OAuthContext oAuthContext;
#Autowired
private AuthManager authManager;
#Bean
public RequestInterceptor myCustomInterceptor() {
return new CustomInterceptor(oAuthContext, authManager, minTokenLifespan);
}
}
The interceptor works for all Feign Clients but one. In the debugger we can see, that this special feign client (along with its the SynchronousMessageHandler) is created, before the Bean is created in the class FeignConfig. The CustomIntercepter is only created after the first Feign Client, all other clients are created afterward, know of the Interceptors existence and will apply it.
How can we debug this issue? Has anyone had a different problem in the past?
I can't post production code, but I would be happy to answer any question and try to post obfuscated code.
This points to a problem in creating the interceptor at the time the first client gets created.
Try putting a conditional breakpoint in org.springframework.beans.factory.support.DefaultListableBeanFactory#getBeansOfType on RequestInterceptor.class. You might see that a circular dependency exists which requires the first client to be created before the FeignConfig or CustomInterceptor classes can be instantiated.
Consider the following example:
#Configuration
#EnableFeignClients(
clients = {
MyFirstClient.class, // will NOT have CustomInterceptor registered
MySecondClient.class // will have CustomInterceptor registered
})
public class FeignConfig {
#Autowired
private BeanDependentOnMyFirstClient beanDependentOnMyFirstClient;
#Bean
public RequestInterceptor myCustomInterceptor() {
return new CustomInterceptor();
}
}
This will result in the following circular dependency:
Since the dependency between the clients and the interceptor is weak, it will just fail silently if the dependency cannot be met.
I have an spring boot app that has a mongo repository and is using spring data to connect to it. This means there's an "entity" class and then a "repository" class.
However, to actually use the repository I need spring to #Autowire my repo to a variable inside another class (we'll call it X) that might want to use it. But if the X class is itself not a spring bean, it's just a regular pojo created by "new X" somewhere then it can't make use of Autowiring and therefore cant use the repo.
This seems like a show stopper... No one could ever make use of a repo outside of some very specific situations like calling the repo directly from your RestController or whatever without any intervening logic. Yet I am sure people are using this.
So my question is how to structure code so that it can be used? Do I need to do a bunch of processing and then return back up to the controller to interact with the databases? Is there a way to create some kind of other "intermediate helper bean" to mediate the connection? What should that look like?
disclaimer: I am fairly new to spring
Perhaps I can post some excerpts that can clarify your situation.
//nothing spring specific
public class MyPojo {
//properties
}
in a different package:
#Repository
public class MyRepositoryImpl implements MyRepository {
//CRUD implementation or whatever
}
in a different package:
#Service
public class MyServiceImpl implements MyService {
#Autowired //constructor-injection
public MyService(MyRepository myRepository) {
this.myRepository = myRepository;
}
private final MyRepository myRepository;
public void myBusinessLogic() {
MyPojo pojo = new MyPojo(); //not dependent on Spring
myRepository.doSomething();
//place calls to X here as needed
}
}
And finally:
#Controller
public class MyController {
#Autowired
public MyController(MyService myService) {
this.myService = myService;
}
private final MyService myService;
#GetMapping("/myPage")
public String doIt() {
myService.myBusinessLogic();
return "myPage";
}
}
Where MyRepository and MyService are interfaces that would contain the contract for their respective implementations.
Single Responsibility Principle
A major point to note is that your POJO isn't going to "use the repo" as you mention in your question. It represents an entity and shouldn't care about any specific repository. And this seems related to your issue - a POJO shouldn't be making calls to a repository (your "X" class in this case). Seems like the design should be revisited if that is the case.
As you say, you can only autowire fields in objects that themselves are autowired. This is inherent to bean injection. You should annotate X with for instance #Component and inject it where you need it.
I'm new to spring, but not new to java.
I'd like to create base class for all REST services that would send notification through some messaging protocol on requests with chosen methods (POST, PUT, PACTCH) (when resource is changed basically)
So for example If I would create interface
public interface RestService<T, I> {
T get(I id);
T create();
T patch(I id);
T put(I id);
}
How can I use that in spring RestController and somehow decorate it with notifications?
All this spring #Autowire and configuration files is somewhat confusing to me, because while I'm familiar with dependency injection and used constructor dependency injection I haven't used IOC much.
I believe that the best option for you will be to use Spring AOP and put some annotation to the required methods. Please check this:
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/aop.html
You can use any interface or base class for any restcontroller or for any other Spring stereotype. The annotations are just clues for Spring itself to use the class as an endpoint for a rest service for example. Your class otherwise can be anything, like:
#RestController
class MyController {
#Autowired
private MyService myService; //If you use the spring sterotypes you dont need to do anything to use a bean but just to use the autowired annotation
}
#RestController
class AnyotherController extends AbstractController {...}
#RestController
class YetAnotherController extends AbstractController implements Something {}
Are all valid resources (i.e. web-components) for Spring to use.
Suppose I have this:
#Transactional(rollbackFor = NotificationException.class)
public interface PersonManagerService {
public void addPerson(Person person);
}
and an implementation:
public class PersonManagerServiceImpl implements PersonManagerService {
public OtherService otherService;
public void addPerson(Person person) {
// stuff
}
// getter and setter for otherService
}
How would I go about mocking the otherService dependency while still having the addPerson method hit the database?
My scenario is that I want to test that a particular exception causes a rollback of the saving of the person that is being added. This exception would come from the OtherService class, which I don't want to call the real version of. I am currently using Spring Transaction annotations so I have a test like this:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {various locations})
public class Test() {
#Autowired
PersonManagerService service;
#Test
public void test() {
// how to call setOtherService so it can be a mock?
}
If I try to cast the auto wired bean, I get an IllegalArgumentException because it is a proxy. If I made the Impl not use an interface, I could use CGLIB but I don't want to do that. If I create the impl programmatically, then it's not tied into the transaction flow. What other options do I have?
There are various ways you can tackle this program (from best to worst):
take advantage of #Profiles - in Spring 3.1 you can associate profile name with every bean. When you are starting an application context you provide active profiles and only beans without any profile associated or with profile matching provided will be instantiated. This is a very powerful mechanism.
#Profile("prd")
public class PersonManagerServiceImpl implements PersonManagerService
//...
#Profile("test")
public class PersonManagerServiceMock implements PersonManagerService
//...
#ContextConfiguration
#ActiveProfiles(value = "test")
public class Test {
use primary or #Primary - if you are autowiring otherService in PersonManagerServiceImpl you can define a second mock bean with primary="true" attribute or #Primary annotation. Spring will prefer primary beans when autowiring.
unwrap transactional proxy (see: Is it possible to unproxy a Spring bean? and Mocking a property of a CGLIB proxied service not working) to access setter. A bit hacky, but works for others