I have a Java class which is something like the following:
public class Foo{
public void doSomething(){
StageA a = new StageA();
StageB b = new StageB();
StageC c = new StageC();
a.execute();
b.execute();
c.execute();
}
}
Now, assuming I can't really edit this class itself, could I still use spring AOP to apply logging around the execute methods? (presumably without using aspect4j)
Well you can log method and it's required time(for performance) but I don't think you would be able to log what method is doing.
From Spring Docs :
Around advice: Advice that surrounds a join point such as a method invocation. This is the most powerful kind of advice. Around advice can perform custom behavior before and after the method invocation. It is also responsible for choosing whether to proceed to the join point or to shortcut the advised method execution by returning its own return value or throwing an exception.
If you are using log4j loggers internally in your methods you can log what method is doing by configuring log4j.
(presumably without using aspect4j)
--> Spring internally uses aspectJ
Check here for reference and example
EDITED:
I don't think that it is possible to log execution of the each "execute" method in your case without changing Foo or Stage classes. Because Stage... classes are not managed by container. You can only log when your doSomething method will start execution (if Foo class is managed by Spring container), you cannot control it's execution flow.
If your classes are to be managed by Spring container, then you can easy do this. You should simply write Spring AOP "around" aspect for Stage... classes, not for Foo class.
Here is an example of simple logging aspect:
#Component
#Aspect
#Order(value=2)
public class LoggingAspect {
#Around("execution(* com.blablabla.server..*.*(..))")
public Object logMethod(ProceedingJoinPoint joinPoint) throws Throwable{
final Logger logger = LoggerFactory.getLogger(joinPoint.getTarget().getClass().getName());
Object retVal = null;
try {
StringBuffer startMessageStringBuffer = new StringBuffer();
startMessageStringBuffer.append("Start method ");
startMessageStringBuffer.append(joinPoint.getSignature().getName());
startMessageStringBuffer.append("(");
Object[] args = joinPoint.getArgs();
for (int i = 0; i < args.length; i++) {
startMessageStringBuffer.append(args[i]).append(",");
}
if (args.length > 0) {
startMessageStringBuffer.deleteCharAt(startMessageStringBuffer.length() - 1);
}
startMessageStringBuffer.append(")");
logger.trace(startMessageStringBuffer.toString());
StopWatch stopWatch = new StopWatch();
stopWatch.start();
retVal = joinPoint.proceed();
stopWatch.stop();
StringBuffer endMessageStringBuffer = new StringBuffer();
endMessageStringBuffer.append("Finish method ");
endMessageStringBuffer.append(joinPoint.getSignature().getName());
endMessageStringBuffer.append("(..); execution time: ");
endMessageStringBuffer.append(stopWatch.getTotalTimeMillis());
endMessageStringBuffer.append(" ms;");
logger.trace(endMessageStringBuffer.toString());
} catch (Throwable ex) {
StringBuffer errorMessageStringBuffer = new StringBuffer();
// Create error message
logger.error(errorMessageStringBuffer.toString(), e)
throw ex;
}
return retVal;
}
}
Yes, you can write an #Around advice with execution pointcut targeting methods whose name is execute() as follows:
#Around("execution(* execute(..))")
public Object execute(ProceedingJoinPoint pjp) throws Throwable
{
// Log statements before the call;
Object obj = pjp.proceed();
// Log statements after the call;
return obj;
}
Related
I have Service.class with start() and asychronous() method :
public ResponseEntity<Object> start() throws APICommandConstructionException, APICommunicationException, APIReplyParseException,
APIErrorResponse, IOException {
List<Company> companiesList = dbHandler.retrieveCompaniesList();
Company company = null;
for (int i = 0; i < companiesList.size(); i++) {
asychronousMethod(companiesList, i, company);
}
return new ResponseEntity<Object>("Start method has Finished", HttpStatus.OK);
}
#Async("threadPoolTaskExecutor")
public void asychronousMethod(List<Company> companiesList, int i, Company company) throws APICommandConstructionException, APIReplyParseException, APICommunicationException, APIErrorResponse, IOException {
company = companiesList.get(i);
company = utils.websiteScrap(company);
companiesRepository.save(company);
}
Everything that is inside a loop doesn't run in parallel, but it starts second loop after first finished. Why is that? How to do it parallel?
In brief: you shouldn't call explicitly methods with Spring annotations.
More detailed:
Spring creates special proxies that on back-stage do 'magic' for you. So if you have async annotation, that means that (depending on compile- and runtime-configuration of Spring) there was some hidden part of code that is not executed when you invoke this.asynchronousMethod.
How to fix:
First of all method should match public CompletableFuture<Void> - such way you know when thread is complete.
Second instead of this you need resolve self-instance as Spring proxy.
The simplest way over #Autowired:
#Autowired
MyClass zhis;
.... //in for loop:
future = zhis.asychronousMethod(companiesList, i, company);
P.s please see good example at https://spring.io/guides/gs/async-method/
I have complex #RestController method, something like this:
#PostMapping("{id}")
#PreAuthorize("hasRole('ADMIN')")
#Transactional
public Response handleRequest(#PathVariable("id") long id, #RequestBody #Valid Request request) {
return service.handleRequest(id, request);
}
Our request handling is quite slow so we want to check how much time is spent on particular request handling tasks. Unfortunately lot of things are done outside of my method, like:
deserializing request
validating
permission checks
starting and ending transaction
serializing response
Is there way to simply measure all those parts? Maybe set of loggers that receive trace messages so I can pull timestamps at the end of each step?
The only way I see to do it now is change that method to accept HttpServletRequest and HttpServletResponse and do those parts inside method body. But that way I will lose lot of Spring Boot benefits.
you can also check a tuto for adding a custom metrics for actuator, but it seems a little bit complicate (but you'll you have to code your own metrics bean and inject it in your code, override objectMapper for mapping, etc...
)
or maybe activate logging info on jackson,spring-security, javax.validation for checking the time in the log for each operation, but not very precise
what you exactly need is Java Thread Profiler which will tell you what is exactly going wrong and for it you can use any APM Tools and my favourite is GLOWROOT .which I have used in the similar scenarios to measure the performance of APIs and identify the slow traces which will clearly tell you which method is taking time and you can see the entire trace starting from method call to all the methods called inside and even identify slow queries if there are any . Hope this helps
Ths site: https://glowroot.org/
example trace :
https://demo.glowroot.org/transaction/thread-profile?transaction-type=Web&transaction-name=%2Fhot-sauces
There is no need to change the method to expect HttpServletRequest. You can use AspectJ
Using it, you can collect the time spent on each method and that analyze the data from it.
Create a methodTiming annotarion
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface MethodTiming {
}
In your Request, create a map that will keep all the methods and the time it took them:
public class Request {
private Map<String, Long> methodTimings = new TreeMap<String, Long>();
public void addMethodTiming(String classAndMethodName, long executionTimeMillis) {
Long value = methodTimings.get(classAndMethodName);
if (value != null) {
executionTimeMillis += value;
}
methodTimings.put(classAndMethodName, executionTimeMillis);
}
}
Than, create the Aspect class that will handle it:
#Aspect
#Component
public class MethodTimingAspect {
private static final String DOT = ".";
#Around("#annotation(MethodTiming)")
public Object timeAround(ProceedingJoinPoint joinPoint) throws Throwable {
Object result = null;
StopWatch watch = new StopWatch();
try {
watch.start();
result = joinPoint.proceed();
} finally {
watch.stop();
long executionTime = watch.getLastTaskTimeMillis();
String className = joinPoint.getTarget().getClass().getSimpleName();
String methodName = joinPoint.getSignature().getName();
String classAndMethodName = className + DOT + methodName;
Object[] methodArgs = joinPoint.getArgs();
if (methodArgs != null) {
for (Object arg : methodArgs) {
if (arg instanceof Request) {
// inject time back into Request
Request request = (Request) arg;
request.addMethodTiming(classAndMethodName, executionTime);
break;
}
}
}
}
return result;
}
Finally, simply add the #MethodTiming on the methods you wish measure:
#MethodTiming
public Request handleRequest(Request request) {
// handle the Request
return request
}
Your request object will than have after the process something like
"methodTimings": {
"RequestService.handleRequest": 2610,
"AnotherRequestService.anotherMethod": 1351
}
I have service calls in my application that make remote network calls to other services as well as DB calls. Spring Boot has good support for rolling back bad transactions with #Transactional, but I wanted to know if I could define a custom rollback procedure using an annotation.
I would need to rollback the data on the other services as well as the database.
In code, I could do it like this:
#Transactional
public void doSomethingComplicated() {
try {
srvcOne.makeRemoteNetworkCall();
srvcTwo.makeDatabaseCall();
} catch(Exception e) {
srvcOne.rollBackNetworkCall();
}
}
but I was hoping I could do something like this:
#Transactional
#MyCustomRollbackListener(handler = MyCustomRollBackHandler.class)
public void doSomethingComplicated() {
srvcOne.makeRemoteNetworkCall();
srvcTwo.makeDatabaseCall();
}
and in the handler:
public class MyCustomRollBackHandler {
public void handleRollback() {
srvcOne.rollBackNetworkCall();
}
}
I implemented a global exception listener and I am able to get the class the exception came from, but I have no way to get the method and to retrieve any annotations on it. Here is my initial attempt:
#ControllerAdvice
public class RollbackExceptionListener{
private static final Logger logger = LoggerFactory.getLogger(RollbackExceptionListener.class);
#ExceptionHandler(Exception.class)
public void lookForAnnotationClassForException(final Exception exception) {
logger.error("Exception thrown", exception);
final StackTraceElement topElement = exception.getStackTrace()[0];
final Class callingClass = topElement.getClass();
final String methodName = topElement.getMethodName();
try {
// Can't get the method with just the name, need to
// know the params as well.
final Method method = callingClass.getMethod(methodName);
// Retrieve the annotation on the method and call the handler
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
}
Is there anyway to do something like this?
Arguments are not part of the Stacktrace. If the method is unique, i.e. not overloaded, you can probably find it with getMethods()? Something else that comes to mind, maybe you can look at Aspects to wrap the method in some handler before it is executed. Can be done either at compile time or runtime.
The aspect can do the rollback itself, it can enrich the exception with the information you need, or it can set some ThreadLocal variable with the handler class that was defined in the method before re-throwing the exception. You can then get this value from the ThreadLocal at the point where you catch the exception.
I am trying to implement AOP based logging in Google - Guice. I have used MethodInterceptor for this but it doesn't work. I have used same in Spring by defining point-cuts. Everything is working fine there.
Spring Code for AOP based logging -
#Aspect
public class LoggingAspect {
private static Logger logger = LoggerFactory.getLogger(LoggingAspect.class);
#Around("requiredLog()")
public Object bentoBoxAround(ProceedingJoinPoint proceedingJoinPoint) {
Object returnValue = null;
try {
logger.info("Entered into the method -> " + proceedingJoinPoint.getSignature().toShortString()
+ " and input arguments are -> " + Arrays.asList(proceedingJoinPoint.getArgs()));
returnValue = proceedingJoinPoint.proceed();
logger.info("Method Execution over !! " + proceedingJoinPoint.getSignature().toShortString());
} catch (Throwable e) {
logger.error("Method has an exception " + e.getMessage());
}
return returnValue;
}
#Pointcut("within(org.cal.bento..*)")
public void allRequiredPakageLog() {
}
}
From above code we can log all the class and method executions inside the org.cal.bento.* package.
Guice code for AOP based logging -
public class GuiceLoggingInterceptor implements MethodInterceptor {
private static Logger logger = LoggerFactory
.getLogger(GuiceLoggingInterceptor.class);
#Override
public Object invoke(MethodInvocation invocation) throws Throwable {
Object returnValue = null;
try {
logger.info("GUICE - Entered into the method -> " + invocation.getMethod().getName()
+ " and input arguments are -> " + Arrays.asList(invocation.getArguments()));
returnValue = invocation.proceed();
logger.info("Method Execution over !! " + invocation.getMethod().getName());
} catch (Throwable e) {
logger.error("GUICE - Method has an exception " + e.getMessage());
}
return returnValue;
}
}
Binding Class -
public class GuiceAopModule extends AbstractModule {
#Override
protected void configure() {
bindInterceptor(Matchers.any(), Matchers.any(), new GuiceLoggingInterceptor());
}
}
Can we do similar in Guice for logging (by defining only one Aspect based class for whole logging system). I don't want to modify every class.
Refered Tutorial - https://schakrap.wordpress.com/2009/07/30/method-entry-exit-logging-in-guice-with-aop/
Any help would be highly appreciated.
Your issue appears to be that you are not using guice for creation. From the guice docs:
This approach imposes limits on what classes and methods can be
intercepted:
[...]
Instances must be created by Guice by an #Inject-annotated or
no-argument constructor It is not possible to use method interception
on instances that aren't constructed by Guice.
So this means, that because your instances are created by spring and likely added to guice, guice has no chance of proxying those classes for interception.
Source:
https://github.com/google/guice/wiki/AOP
Edit:
what you can do (as workaround) to be able to make this work would be:
Spring creates your instances.
Put them into guice
Create a delegate object that is created by Guice and inject the bean of (1) into the wrapper.
Use the wrapper instead of the object in 1 and then the methods will get intercepted.
I write simple application. I don't want to use any frameworks. Please suggest me right place to hold annotation processing.
I have a few lines in main method:
String myString = (#NonNull String)list;
And I created #interface:
#Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
public #interface NonNull {
}
Which step should I take next? Can I work with annotations without using reflection? Could you expose for me samples of such annotation processing code?
There is no way (AFAIK) to work with annotations without reflection.
If you don't want to use any framework, first step is to write kind of proxy class handling the method requests. It is an example of method processing with annotation use over method:
public class MyProxy {
private <T> T getProxy(T t) {
return (T) Proxy.newProxyInstance(t.getClass().getClassLoader(), new Class<?>[]{MyClass.class}, new MyInvocationHandler(t));
}
}
And then implement InvocationHandler:
public class MyInvocationHandler implements InvocationHandler {
private Object obj;
MyInvocationHandler (Object obj) {
this.obj = obj;
}
#Override
public Object invoke(Object proxy, final Method method, final Object[] args) throws Throwable {
boolean isNotNull = method.isAnnotationPresent(NotNull.class);
if (isNotNull) {
/* process annotated method. Or go through proxy object fields etc.. */
}
}
}
I hope it will help you.
You didn't say what kind of annotation processing you want to do.
Do you want to add a run-time check that will cause your code to crash if list is ever null at run time? For this, reflection will work.
Do you want to add a compile-time check that will reject your code if it cannot prove that list is never null at run time? For this, an annotation processor such as the Checker Framework will work.
Your question does not explain why you don't want to use a framework. Doing so will save you from re-implementing a lot of functionality that others have already created.