How to intercept a method in java - java

Here is the method:
public static boolean startModule(Module mod, ServletContext servletContext, boolean delayContextRefresh)
Here is the method call in a java file:
WebModuleUtil.startModule(module, getServletContext(), false);
I cannot make any changes to these files, but I want to intercept the method and add some of my code (I want access to the parameters as well)
Code I wrote in another java file but not successful:
public void main(String[] args) throws Exception {
Module module = null;
WebModuleUtil wmb = new WebModuleUtil();
ProxyFactory pf = new ProxyFactory(wmb);
pf.addAdvice(new MethodInterceptor() {
public Object invoke(MethodInvocation invocation) throws Throwable {
if (invocation.getMethod().getName().startsWith("start")) {
System.out.println("method " + invocation.getMethod() + " is called on " + invocation.getThis()
+ " with args " + invocation.getArguments());
System.out.println("********************");
Object ret = invocation.proceed();
System.out.println("method " + invocation.getMethod() + " returns " + ret);
return ret;
}
return null;
}
});
WebModuleUtil proxy = (WebModuleUtil) pf.getProxy();
proxy.startModule(module, getServletContext(), false);
}
private static ServletContext getServletContext() {
// TODO Auto-generated method stub
return null;
}

Use aop programming. For example try to read something about AspectJ.
Ex code:
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Service;
#Aspect
#Service
public class AspectDemo {
#Around("aop1()" )
public Object intercept(ProceedingJoinPoint joinPoint) throws Throwable {
for (Object obj : joinPoint.getArgs()) {
LOG.debug(obj);
}
}
#Pointcut("execution(*my.example.packcage.startModule.*(..))")
public void aop1() {
}

Aspect Oriented Programming (AOP) is made for this purpose, you can use AspectJ:
AspectJ enables clean modularization of crosscutting concerns, such as error checking and handling, synchronization, context-sensitive behavior, performance optimizations, monitoring and logging, debugging support, and multi-object protocols.
Or as you are using Spring you can use Spring 2.0 AOP:
Spring 2.0 introduces a simpler and more powerful way of writing custom aspects using either a schema-based approach or the #AspectJ annotation style. Both of these styles offer fully typed advice and use of the AspectJ pointcut language, while still using Spring AOP for weaving.
This is how to declare an Aspect:
#Aspect
public class NotVeryUsefulAspect {
}
And this is how to declare a pointCut:
#Pointcut("execution(* transfer(..))")// the pointcut expression
private void anyOldTransfer() {}// the pointcut signature
For further information you can refer these tutorials:
Spring AOP Example Tutorial – Aspect, Advice, Pointcut, JoinPoint,
Annotations, XML Configuration.
Spring AOP + AspectJ annotation example.

Have a look at byte code instrumentation. It allows you to intercept methods and change all kinds of things without necessarily having access to the source code (although it helps to have it for reference). Javassist is a great library to use along with the JVM Agent.
Cglib is another library that uses proxies to change the behaviour of targeted code, but I have found javassist easier to use.
This tutorial is a good start: http://rafaeloltra.com/developing-a-jvm-agent-for-bytecode-instrumentation-with-javassist-pt1/.
As well as the Javassist documentation: http://jboss-javassist.github.io/javassist/tutorial/tutorial.html

Related

Fail to use Aspect in parent abstract class method [duplicate]

Please explain, why self invocation on proxy performed on target but not proxy? If that made on purpose, then why? If proxies created by subclassing, it's possible to have some code executed before each method call, even on self invocation. I tried, and I have proxy on self invocation
public class DummyPrinter {
public void print1() {
System.out.println("print1");
}
public void print2() {
System.out.println("print2");
}
public void printBoth() {
print1();
print2();
}
}
public class PrinterProxy extends DummyPrinter {
#Override
public void print1() {
System.out.println("Before print1");
super.print1();
}
#Override
public void print2() {
System.out.println("Before print2");
super.print2();
}
#Override
public void printBoth() {
System.out.println("Before print both");
super.printBoth();
}
}
public class Main {
public static void main(String[] args) {
DummyPrinter p = new PrinterProxy();
p.printBoth();
}
}
Output:
Before print both
Before print1
print1
Before print2
print2
Here each method called on proxy. Why in documentation mentioned that AspectJ should be used in case of self invocation?
Please read this chapter in the Spring manual, then you will understand. Even the term "self-invocation" is used there. If you still do not understand, feel free to ask follow-up questions, as long as they are in context.
Update: Okay, now after we have established that you really read that chapter and after re-reading your question and analysing your code I see that the question is actually quite profound (I even upvoted it) and worth answering in more detail.
Your (false) assumption about how it works
Your misunderstanding is about how dynamic proxies work because they do not work as in your sample code. Let me add the object ID (hash code) to the log output for illustration to your own code:
package de.scrum_master.app;
public class DummyPrinter {
public void print1() {
System.out.println(this + " print1");
}
public void print2() {
System.out.println(this + " print2");
}
public void printBoth() {
print1();
print2();
}
}
package de.scrum_master.app;
public class PseudoPrinterProxy extends DummyPrinter {
#Override
public void print1() {
System.out.println(this + " Before print1");
super.print1();
}
#Override
public void print2() {
System.out.println(this + " Before print2");
super.print2();
}
#Override
public void printBoth() {
System.out.println(this + " Before print both");
super.printBoth();
}
public static void main(String[] args) {
new PseudoPrinterProxy().printBoth();
}
}
Console log:
de.scrum_master.app.PseudoPrinterProxy#59f95c5d Before print both
de.scrum_master.app.PseudoPrinterProxy#59f95c5d Before print1
de.scrum_master.app.PseudoPrinterProxy#59f95c5d print1
de.scrum_master.app.PseudoPrinterProxy#59f95c5d Before print2
de.scrum_master.app.PseudoPrinterProxy#59f95c5d print2
See? There is always the same object ID, which is no surprise. Self-invocation for your "proxy" (which is not really a proxy but a statically compiled subclass) works due to polymorphism. This is taken care of by the Java compiler.
How it really works
Now please remember we are talking about dynamic proxies here, i.e. subclasses and objects created during runtime:
JDK proxies work for classes implementing interfaces, which means that classes implementing those interfaces are being created during runtime. In this case there is no superclass anyway, which also explains why it only works for public methods: interfaces only have public methods.
CGLIB proxies also work for classes not implementing any interfaces and thus also work for protected and package-scoped methods (not private ones though because you cannot override those, thus the term private).
The crucial point, though, is that in both of the above cases the original object already (and still) exists when the proxies are created, thus there is no such thing as polymorphism. The situation is that we have a dynamically created proxy object delegating to the original object, i.e. we have two objects: a proxy and a delegate.
I want to illustrate it like this:
package de.scrum_master.app;
public class DelegatingPrinterProxy extends DummyPrinter {
DummyPrinter delegate;
public DelegatingPrinterProxy(DummyPrinter delegate) {
this.delegate = delegate;
}
#Override
public void print1() {
System.out.println(this + " Before print1");
delegate.print1();
}
#Override
public void print2() {
System.out.println(this + " Before print2");
delegate.print2();
}
#Override
public void printBoth() {
System.out.println(this + " Before print both");
delegate.printBoth();
}
public static void main(String[] args) {
new DelegatingPrinterProxy(new DummyPrinter()).printBoth();
}
}
See the difference? Consequently the console log changes to:
de.scrum_master.app.DelegatingPrinterProxy#59f95c5d Before print both
de.scrum_master.app.DummyPrinter#5c8da962 print1
de.scrum_master.app.DummyPrinter#5c8da962 print2
This is the behaviour you see with Spring AOP or other parts of Spring using dynamic proxies or even non-Spring applications using JDK or CGLIB proxies in general.
Is this a feature or a limitation? I as an AspectJ (not Spring AOP) user think it is a limitation. Maybe someone else might think it is a feature because due to the way proxy usage is implemented in Spring you can in principle (un-)register aspect advices or interceptors dynamically during runtime, i.e. you have one proxy per original object (delegate), but for each proxy there is a dynamic list of interceptors called before and/or after calling the delegate's original method. This can be a nice thing in very dynamic environments. I have no idea how often you might want to use that. But in AspectJ you also have the if() pointcut designator with which you can determine during runtime whether to apply certain advices (AOP language for interceptors) or not.
Solutions
What you can do in order to solve the problem is:
Switch to native AspectJ, using load-time weaving as described in the Spring manual. Alternatively, you can also use compile-time weaving, e.g. via AspectJ Maven plugin.
If you want to stick with Spring AOP, you need to make your bean proxy-aware, i.e. indirectly also AOP-aware, which is less than ideal from a design point of view. I do not recommend it, but it is easy enough to implement: Simply self-inject a reference to the component, e.g. #Autowired MyComponent INSTANCE and then always call methods using that bean instance: INSTANCE.internalMethod(). This way, all calls will go through proxies and Spring AOP aspects get triggered.
#Dolphin
It is late reply but maybe this text will help you: Spring AOP and self-invocation.
In short, the link leads you to a simple example of why running code from another class will work but from "self" it won't.
Notice looking at the example from the link that when you run code from another class you are asking Spring to inject the bean. And Spring sees that in the bean you are asking for a cache, it creates at runtime proxy for that bean.
On the other hand, when you do the same in the "self" class, you create a compile time method call and Spring won't do anything about it.

Is there a way of calling an advice method after execution of certain line of code using spring AOP

I have been wring Aspect for logging purpose. Now i am able to use before and after advice. But is it possible to call an advice after execution of certain line of business logic. Here is my current code and i want to substitute my code with advice. How to do that?
#ComponentScan
#EnableCaching
#EnableAutoConfiguration(exclude = {MetricFilterAutoConfiguration.class, MetricRepositoryAutoConfiguration.class})
public class Application {
private final Logger log = LoggerFactory.getLogger(Application.class);
#Inject
private Environment env;
#Inject
private AppConfig appConfig;
public void myBusinessLogicMethod(){
if (myVariable == 0) {
log.info("No Spring profile configured, running with default configuration");
//rest of the business logic here
} else {
log.info("Running with number profile(s) : {}",myVariable);
// //rest of the business logic here
}
My Aspect class
#Aspect
#Order(0)
public class LoggingAspect {
private final Logger log = LoggerFactory.getLogger(this.getClass());
#Inject
private HttpServletRequest request;
#Inject
private HttpServletResponse response;
#Inject
private Environment env;
#Pointcut("(within(com.repository.*) || within(com.service.*) || "
+ "within(com.web.rest.*)) && "
+ "!#annotation(com.aop.logging.NoLogging)")
public void loggingPoincut() {
}
#Before("within(com.web.rest.*) && "
+ "!#annotation(com.aop.logging.NoLogging)")
public void beforeRest(JoinPoint point) throws UnknownHostException {
String ipAddress = getIpAddress();
if (log.isDebugEnabled()) {
log.debug(">>>>>> From IP {}", isIpAvailble(ipAddress));
log.debug("Enter: {}.{}() with argument[s] = {}", point.getSignature().getDeclaringTypeName(),
point.getSignature().getName(), Arrays.toString(point.getArgs()));
}
}
#After("within(com.web.rest.*) && "
+ "!#annotation(com.aop.logging.NoLogging)")
public void afterRest(JoinPoint point) throws UnknownHostException {
if (log.isDebugEnabled()) {
log.debug("Exit: {}.{}()", point.getSignature().getDeclaringTypeName(), point.getSignature()
.getName());
log.debug("<<<<<< Rest Call Finished {} ", response.getStatus());
}
}
}
How can i replace tightly coupled log with an advice in my aspect class.
The simple answer is: With Spring AOP you can intercept method calls, not single lines of code. Even if you could, it would be a maintenance nightmare because code inside a method changes frequently. Even if you have a stable API of public methods, they are black boxes and you (or one of your colleagues) can change their internal implementation at any time.
But the solution is simple: Apply "Clean Code" principles (I hope you have read the book or know about the software craftsmanship movement from other sources already), i.e. use short methods, factoring out more complex code into smaller, re-useable, well named and maintainable pieces with low complexity. Factor out methods to the granularity level you need for logging, e.g.
public void myBusinessLogicMethod() {
if (myVariable == 0)
smallerBusinessLogicA(myVariable, someParameter);
else
smallerBusinessLogicB(myVariable);
}
Then target those factored out methods with your logging pointcut and log their names, parameters and/or results (whatever you need). In order for this to work with Spring AOP, you need to be careful to
either factor out the helper methods into other Spring component classes because Spring AOP does not support self-invocation interception
or self-inject the bean so you can call the helper methods using the injected bean (i.e. you use the AOP proxy and not the real implementation class underneath that does not know anything about AOP)
or switch from Spring AOP to full AspectJ which does not use proxies and works with self-invocation.
Another difference between Spring AOP and AspectJ is that the former can only target non-private methods, while AspectJ has no such limitation.

AspectJ weaving for private methods

I've got an AspectJ weaving annotation that works for public methods, but private method are being ignored.
The purpose of this method is to simply log the time it took to run the function.
#Aspect
#Slf4j
public class TimedLogAspect {
#Pointcut("#annotation(timedLogVar)")
public void annotationPointCutDefinition(TimedLog timedLogVar) {}
#Pointcut("execution(* *(..))")
public void atExecution() {}
#Around(value = "annotationPointCutDefinition(timedLogVar) && atExecution()", argNames = "joinPoint,timedLogVar")
public Object around(ProceedingJoinPoint joinPoint, TimedLog timedLogVar) throws Throwable {
Stopwatch stopwatch = Stopwatch.createStarted();
Object returnValue = joinPoint.proceed();
stopwatch.stop();
MessageBuilder messageBuilder = new MessageBuilder(joinPoint.toShortString(), stopwatch.elapsed(TimeUnit.MILLISECONDS))
.attachMessage(timedLogVar.message())
.attachMethodArgs(timedLogVar.shouldAttachMethodArgs(), Stream.of(joinPoint.getArgs()).collect(Collectors.toList()))
.attachReturnValue(timedLogVar.shouldAttachReturnValue(), returnValue);
log.info(messageBuilder.build(), messageBuilder.getArgs().toArray());
return returnValue;
}
}
with this being the actual interface:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface TimedLog {
boolean shouldAttachMethodArgs() default false;
boolean shouldAttachReturnValue() default false;
String message() default "";
}
I've seen a lot of answer, being adding private before the first * in the execution portion, I've seen privileged which isn't supported for annotations, and I'm using AspectJ with no SpringAOP.
any ideas?
The answer is simple: use native AspectJ syntax. You mentioned it by yourself. You even said that you use full AspectJ, not Spring AOP. So switching should not be a problem.
You have lots of advantages:
more power (some features are unavailable in annotation syntax, as you noticed),
syntax highlighting and code completion in IDEs,
more expressive syntax (less verbose and more elegant, i.e. no need to bind thisJoinPoint in advices and easier use of if(), no need for fully-qualified class names because you can just import them).
The annotation-based syntax IMO is just terribly difficult to read, everything is in a single string inside an annotation parameter. I only use it if I have no other choice or when answering questions about it here.

AOP based logging in Guice

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.

Code injection via custom annotation

Here's my use case:
I need to do some generic operation before and after each method of a given class, which is based on the parameter(s) of the method. For example:
void process(Processable object) {
LOGGER.log(object.getDesc());
object.process();
}
class BaseClass {
String method1(Object o){ //o may or may not be Processable(add process logic only in former case)
if(o intstanceof Prcessable){
LOGGER.log(object.getDesc());
object.process();
}
//method logic
}
}
My BaseClass has a lot of methods and I know for a fact that the same functionality will be added to several similar classes as well in future.
Is something like the following possible?
#MarkForProcessing
String method1(#Process Object o){
//method logic
}
PS: Can AspectJ/guice be used? Also want to know how to implement this from scratch for understanding.
Edit: Forgot to mention, what I have tried.(Not complete or working)
public #interface MarkForProcessing {
String getMetadata();
}
final public class Handler {
public boolean process(Object instance) throws Exception {
Class<?> clazz = instance.getClass();
for(Method m : clazz.getDeclaredMethods()) {
if(m.isAnnotationPresent(LocalSource.class)) {
LocalSource annotation = m.getAnnotation(MarkForProcessing.class);
Class<?> returnType = m.getReturnType();
Class<?>[] inputParamTypes = m.getParameterTypes();
Class<?> inputType = null;
// We are interested in just 1st param
if(inputParamTypes.length != 0) {
inputType = inputParamTypes[0];
}
// But all i have access to here is just the types, I need access to the method param.
}
return false;
}
return false;
}
Yes, it can be done. Yes, you can use AspectJ. No, Guice would only be tangentially related to this problem.
The traditional aspect approach creates a proxy which is basically a subclass of the class you've given it (e.g. a subclass of BaseClass) but that subclass is created at runtime. The subclass delegates to the wrapped class for all methods. However, when creating this new subclass you can specify some extra behavior to add before or after (or both) the call to the wrapped class. In other words, if you have:
public class Foo() {
public void doFoo() {...}
}
Then the dynamic proxy would be a subclass of Foo created at runtime that looks something like:
public class Foo$Proxy {
public void doFoo() {
//Custom pre-invocation code
super.doFoo();
//Custom post-invocation code
}
}
Actually creating a dynamic proxy is a magical process known as bytecode manipulation. If you want to to do that yourself you can use tools such as cglib or asm. Or you can use JDK dynamic proxies. The main downside to JDK proxies are that they can only wrap interfaces.
AOP tools like AspectJ provide an abstraction on top of the raw bytecode manipulation for doing the above (you can do a lot with bytecode manipulation, adding behavior before and after methods is all aspects allow). Typically they define 'Aspect's which are classes that have special methods called 'advice' along with a 'pointcut' which defines when to apply that advice. In other words you may have:
#Aspect
public class FooAspect {
#Around("#annotation(MarkForProcessing)")
public void doProcessing(final ProceedingJoinPoint joinPoint) throws Throwable
{
//Do some before processing
joinPoint.proceed(); //Invokes the underlying method
//Do some after processing
}
}
The aspect is FooAspect, the advice is doProcessing, and the pointcut is "#annotation(MarkForProcessing)" which matches all methods that are annotated with #MarkForProcessing. It's worth pointing out that the ProceedingJoinPoint will have a reference to the actual parameter values (unlike the java.lang.reflect.Method)
The last step is actually applying your aspect to an instance of your class. Typically this is either done with a container (e.g. Guice or Spring). Most containers have some way of knowing about a collection of aspects and when to apply them to classes constructed by that container. You can also do this programmatically. For example, with AspectJ you would do:
AspectJProxyFactory factory = new AspectJProxyFactory(baseClassInstance);
factory.addAspect(FooAspect.class);
BaseClass proxy = factory.getProxy();
Last, but not least, there are AOP implementations which use compile-time "weaving" which is a second compilation step run on the class files that applies the aspects. In other words, you don't have to do the above or use a container, the aspect will be injected into the class file itself.

Categories

Resources