Spring boot actuator - Implement custom metrics - spring-boot

I would like to implement custom metric or statistics to my spring boot rest web service using actuator but i am not able to find simple tutorials.
For example:
how to show how many times a certain controller was called and what exact parameter field was filled?
how can i create a metric that when its URL is called, it runs certain query and shows back a json with some result

This seems like a good scenario for AOP (Aspect Oriented Programing) as this will allow you to separate this statistic logic from the business logic.
Have a look at Spring doc for more info about AOP and how to achieve that with Spring.
You can then define a pointcut on your controller and have a service for counting (and probably then storing) the data.
Refer below link
AOP Example

For point two the solution is to create an endpoint class (it can be or not a rest controller class). For example:
#Component
#RestControllerEndpoint(id = "pfm-statistics")
public class StatisticsEndpoint {
#GetMapping(value = "/", produces = "application/vnd.openxmlformats-
officedocument.spreadsheetml.sheet")
#ResponseBody
public byte[] generateStatisticsAsExcel() {
...
Note that the ID is the path to be called from URL. We can create a simple endpoint too and just return a string if we want. In this case instead of #RestControllerEndpoint annotation we can use #Endpoint, as a side note, the id should always contain dash

Related

How to implement request timeout management in an AOP way in Spring Boot

currently I'm exploring approaches to implement 'request timeout management in an AOP way in Spring Boot' with several restrictions. The requirements/restrictions are stated as below:
The original purpose is that if the processing time of an api request exceeds 5 seconds, then directly return timeout result instead of continue processing
The rest api to be monitored is implemented by standard spring mvc rest controller. All apis inside are returning json strings like this:
#RestController
public class xxxxxx {
#RequestMapping(value = "xxxxxxx")
public String xxxxxx(#RequestParam(value = "xxxx", required = true) String xxxx) {
....
return json.toString();
}
}
The timeout logic is required to be implemented by AOP
(The real mean part)
No changes should be made to the controllers, which means: Request generation approach should not be changed; Return type should not be changed(No 'Callable<...>' allowed)
I have already found 1 answer(Async approach) which can perfectly resolve the problem itself with spring async, and the timeout return result is very pretty, but it's changing the return type, and also touching the code in controller. I also found one solution(AOP approach) which is using AOP, but the scenario is quite different from mine. It's already moving some business logic into AOP class, but I'm not allowed to touch the controller code. I would be grateful if anyone can provide a solution. Solutions that can't meet all the restrictions but are minimizing the differences are also admitted.
Since there is still no response to this question, I will put my own temporary solution here.
I'm using Hystrix dependency.
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
<version>1.4.0.RELEASE</version>
</dependency>
It's well integrated with springboot, so the configuration is easy. Once properly configured, need to append an annotation on the request method that requires timeout handling. e.g.
#HystrixCommand(fallbackMethod="fallback")
#RequestMapping(value = "xxxxxxx")
public String xxxxxx(#RequestParam(value = "xxxx", required = true) String xxxx) {
....
return json.toString();
}
And need to add a fallback method with the name mapped to the value of 'fallbackMethod' inside annotation:
public String fallback() {
...
}
The timeout time value can be globally configured inside application.properties
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=3000
hystrix.command.default.circuitBreaker.sleepWindowInMilliseconds=3000
This is still not concise in these points:
Need to copy/paste this annotation for every method
Need to copy/paste the fallback method in every place hystrix is used
For hystrix fallback method itself, the parameter type and number need to be exactly same with the hystrix marked method. Currently I'm using several overloading method called 'fallback' for this, in each controller
But at least it's not changing method return types and code inside methods anymore and is the best solution I can think of currently. Will perform update once I find better solutions.

Identifying Spring MVC architecture pattern

I'm working through a spring mvc video series and loving it!
https://www.youtube.com/channel/UCcawgWKCyddtpu9PP_Fz-tA/videos
I'd like to learn more about the specifics of the exact architecture being used and am having trouble identifying the proper name - so that I can read further.
For example, I understand that the presentation layer is MVC, but not really sure how you would more specifically describe the pattern to account for the use of service and resource objects - as opposed to choosing to use service, DAO and Domain objects.
Any clues to help me better focus my search on understanding the layout below?
application
core
models/entities
services
rest
controllers
resources
resource_assemblers
Edit:
Nathan Hughes comment clarified my confusion with the nomenclature and SirKometa connected the architectural dots that I was not grasping. Thanks guys.
As far as I can tell the layout you have mentioned represents the application which communicates with the world through REST services.
core package represents all the classes (domain, services, repositories) which are not related to view.
model package - Assuming you are aiming for the typical application you do have a model/domain/entity package which represents your data For example: https://github.com/chrishenkel/spring-angularjs-tutorial-10/blob/master/src/main/java/tutorial/core/models/entities/Account.java.
repository package - Since you are using Spring you will most likely use also since spring-data or even spring-data-jpa with Hibernate as your ORM Library. It will most likely lead you to use Repository interfaces (author of videos you watch for some reason decided not to use it though). Anyway it will be your layer to access database, for example: https://github.com/chrishenkel/spring-angularjs-tutorial-10/blob/master/src/main/java/tutorial/core/repositories/jpa/JpaAccountRepo.java
service package will be your package to manipulate data. It's not the best example but this layer doesn't access your database directly, it will use Repositories to do it, but it might also do other things - it will be your API to manipulate data in you application. Let's say you want to have a fancy calculation on your wallet before you save it to DB, or like here https://github.com/chrishenkel/spring-angularjs-tutorial-10/blob/master/src/main/java/tutorial/core/services/impl/AccountServiceImpl.java you want to make sure that the Blog you try to create doesn't exist yet.
controllers package contain all classes which will be used by DispacherServlet to take care of the requests. You will read "input" from the request, process it (use your Services here) and send your responses.
resource_assemblers package in this case is framework specific (Hateoas). As far as I can tell it's just a DTO for your json responses (for example you might want to store password in your Account but exposing it through json won't be a good idea, and it would happen if you didn't use DTO).
Please let me know if that is the answer you were looking for.
This question may be of interest to you as well as this explanation.
You are mostly talking about the same things in each case, Spring just uses annotations so that when it scans them it knows what type of object you are creating or instantiating.
Basically everything request flows through the controller annotated with #Controller. Each method process the request and (if needed) calls a specific service class to process the business logic. These classes are annotated with #Service. The controller can instantiate these classes by autowiring them in #Autowire or resourcing them #Resource.
#Controller
#RequestMapping("/")
public class MyController {
#Resource private MyServiceLayer myServiceLayer;
#RequestMapping("/retrieveMain")
public String retrieveMain() {
String listOfSomething = myServiceLayer.getListOfSomethings();
return listOfSomething;
}
}
The service classes then perform their business logic and if needed, retrieve data from a repository class annotated with #Repository. The service layer instantiate these classes the same way, either by autowiring them in #Autowire or resourcing them #Resource.
#Service
public class MyServiceLayer implements MyServiceLayerService {
#Resource private MyDaoLayer myDaoLayer;
public String getListOfSomethings() {
List<String> listOfSomething = myDaoLayer.getListOfSomethings();
// Business Logic
return listOfSomething;
}
}
The repository classes make up the DAO, Spring uses the #Repository annotation on them. The entities are the individual class objects that are received by the #Repository layer.
#Repository
public class MyDaoLayer implements MyDaoLayerInterface {
#Resource private JdbcTemplate jdbcTemplate;
public List<String> getListOfSomethings() {
// retrieve list from database, process with row mapper, object mapper, etc.
return listOfSomething;
}
}
#Repository, #Service, and #Controller are specific instances of #Component. All of these layers could be annotated with #Component, it's just better to call it what it actually is.
So to answer your question, they mean the same thing, they are just annotated to let Spring know what type of object it is instantiating and/or how to include another class.
I guess the architectural pattern you are looking for is Representational State Transfer (REST). You can read up on it here:
http://en.wikipedia.org/wiki/Representational_state_transfer
Within REST the data passed around is referred to as resources:
Identification of resources:
Individual resources are identified in requests, for example using URIs in web-based REST systems. The resources themselves are conceptually separate from the representations that are returned to the client. For example, the server may send data from its database as HTML, XML or JSON, none of which are the server's internal representation, and it is the same one resource regardless.

Relax Security for a Spring Data REST Projection

I have a User class and I want to authorize access such that only a user gets to see what he is entitled to.
This was easily achievable using Spring Security in conjunction with Spring Data Rest where in JPA Repository I did below -
public interface UserRepository extends JPARepository<User,Integer> {
#PreAuthorize("hasRole('LOGGED_IN') and principal.user.id == #id")
User findOne(#Param("id") Integer id);
}
In this way, a user when visits to Spring Data REST scaffolded URLs like -
/users/{id}
/users/{id}/userPosts
Only those logged in with {id} get to see these and everyone else gets 401 like I would have wanted.
My problem is that I have one of Projections which is a public view of each user and I am crating it using Spring Data Rest projections as below which I want to be accessible for every {id}
#Projection(name = "details", types = User.class)
public interface UserDetailsProjection {
..
}
So, /users/{id1}?projection=details as well as /users/{id2}?projection=details should give 200 OK and show data even though user is logged in by {id1}
I began implementing this by marking projection with #PreAuthorize("permitAll") but that won't work since Repository has harder security check. Can we have this functionality where for a projection we can relax security ?
I am using latest Spring Data Rest and Spring Security distributions
Seems reasonable to add a custom controller for this use-case.
Please also consider:
Evaluate access in projections using #Value annotations
Add another entity for the same database data but with different field set for read-only operations, e.g. using inheritance (be careful with caching, etc.) - depends on your data storage type
Modify model to split User entity into two different entities (profile, account) since they seem to have different access and possibly even operations
You can also add a ResourceProcessor<UserSummaryProjection> to evaluate access programmatically and replace resource content (projection) with a DTO
Example of evaluating access in projections with #Value annotations:
#Projection(types = User.class, name = "summary")
public interface UserSummaryProjection {
#Value("#{#userSecurity.canReadEmail(target) ? target.email: null}")
String getEmail();
}
Added spring security code in the data access layer is not a good idea. I would suggest you to add the #PreAuthorize annotation to the controller/service method. Since you have a query parameter, ?projection=details, you can have separate controller/service method for the details projection.
Add following to your details projection method:
#RequestMapping("/url", params = {"projection"})
#PreAuthorize("hasRole('LOGGED_IN') and principal.user.id == #id")

Spring DTO validation in Service or Controller?

I'm building a straight forward AJAX / JSON web service with Spring. The common data flow is:
some DTO from browser
v
Spring #Controller method
v
Spring #Service method
I'm looking for the most easy way to handle data validation.
I know the #Valid annotation which works pretty well inside #Controller methods.
Why does #Valid not work within #Service methods?
I mean: A service method can be used by any other service and controller. So wouldn't it make much more sense to validate at #Service level?
Let's take this simple example:
MyDTO.java:
public class MyDTO {
#NotNull
public String required
#Min(18)
public int age;
}
MyServiceImpl.java:
public MyDomainObject foo(MyDTO myDTO) {
// persist myDTO
// and return created domain object
}
MyController.java:
#Autowired
MyService myService;
#Autowired // some simple bean mapper like Dozer or Orika
Mapper mapper; // for converting domain objects to DTO
#RequestMapping(...)
public MyDomainObjectDTO doSomething(#RequestBody MyDTO myDTO) {
mapper.map(myService.foo(myDTO), MyDomainObjectDTO.class);
}
Is it common practice that the service method receives the DTO?
If yes: What's the best practice to validate that DTO inside the service method?
If no: Should maybe the controller manipulate the Domain object and just let the service save that object? (this seems pretty useless to me)
In my opinion the service should be responsible for only data consistency.
How do you solve this?
My answer? Both.
The service must check its own contract for validity.
The controller is part of the UI. It should validate and bind for a better user experience, but the service should not rely on it.
The service cannot know how it's being called. What if you wrap it as a REST service?
The service also knows about business logic violations in a way that no UI can. It needs to validate to make sure that the use case is fulfilled appropriately.
Double bag it; do both.
See my other answer: Check preconditions in Controller or Service layer
If you really want to do validation like error handling in your Service layer similar to Spring MVC you can use javax.validation and AspectJ (to advice the methods to validate) which is what I do because I like making reflection do the work and declarative programming (annotations).
Spring MVC doesn't need to do AspectJ/AOP to do the error handling because the methods are being called through reflection (url routing/dispatching).
Finally for you MVC code you should know that #Valid is sort of unofficially deprecated. Instead consider #Validated which will leverage more of the javax.validation features.

How to map a path to multiple controllers?

I'm currently working on a spring based web application and have a special requirement that seems not (at least not out of the box) be provided by spring MVC. The application serves data for multiple users each organized in their own "company". Once a user has logged in, I'm able to identify to which company he belongs to.
The application itself is built with multiple "modules", each with it's own domain objects, DAO, Service and Controller classes. The idea behind this concept is that I can for example extend a certain controller class (let's say to use a different service class) based upon the user and here is my problem.
Since i do not want to change my request paths for certain users, I'm currently looking for a way how to serve a request issued on a certain request path with different instances of a controller based upon the user issuing the request.
I came up with the idea to attach a HTTP Header Field for the company
Example:
X-Company:12345
and have my controllers configured like this:
#Controller
#RequestMapping(value="/foo/")
public class FooController {
// ...
}
#Controller
#RequestMapping(value="/foo" headers="X-Company=12345")
public class SpecialFooController extends FooController {
// ...
}
However this is not possible, since spring MVC treats each header (except Content-Type and Accept) as a kind of restriction, so in my case it would handle all requests with the FooController instead of the SpecialFooController unless i add a "headers" restriction on the FooController as well, which is not practicable.
Is there some way how to customize this behaviour or some direction one could point me to look for? Or maybe someone has another idea how to achieve this. It'll be highly appreciated.
Thanks!
I'am not sure but I think you can do this with HandlerMapping. Have a look at the documentation
To take your own suggestion, you can use the #RequestHeader annotation in your controller methods:
#Controller
public class MyController {
#RequestMapping("/someAction")
public void myControllerMethod(#RequestHeader('X-Company-Id') String companyId) {
}
}
Or you could use #PathVariable:
#Controller
public class MyController {
#RequestMapping("/{companyId}/someAction")
public void myControllerMethod(#PathVariable("companyId") String companyId) {
}
}
Using this approach would mean that it is in fact different URLs for each company, but if you can set the company id header, I guess you also can suffix the URLs with the company id.
But there are also other possibilities. You could write an interceptor that puts the company id in a session or request variable. Then you wouldn't have to add the annotation to every controller method. You could also use a subdomain for each company, but that wouldn't look too pretty if the company id is a random alphanumeric string. E.g: companyone.mydomain.com, companytwo.mydomain.com
Edit
#RequestMapping can be added to the controller level as you know, so you should be able to do
#Controller
#RequestMapping("/controller/{companyId}")
as the base url, if that's a better option.
I was able to meet the requirement by making usage of a customized RequestCondition. By defining your own annotation that can be placed at the type and method level of a controller. Extending the RequestMappingHandlerMapping by your own implementation and overriding the getCustomTypeCondition() and getCustomMethodCondition() methods translates a controller annotation into your own RequestCondition.
When a request comes in, the custom RequestCondition will be evaluated and the annotated controller(method) will then be called to serve the request. However this has the downside, that one needs to remove a servlet-context.xml file and switch to the WebMvcConfigurationSupport class instead in order to be able to use your customized RequestMappingHandlerMapping class.
This question was also discussed here.
Edit:
A pretty good example using this can be found here.

Resources