I was trying to create an Aspectj pointcut on method annotation but I failed all the time with different approaches. I'm using aspectj autoproxy (I have no other weaving configured in my spring context). My classes look like this:
public interface Intf
{
#SomeAnnotation
void method1() throws SomeExc;
}
public class Impl implements Intf
{
#Override
public void method1() throws SomeExc
{
//...
}
}
#Aspect
public class MyAspect
{
#AfterThrowing(
pointcut = "execution(* *(..)) && #annotation(SomeAnnotation)",
throwing = "error")
public void afterThrowing(JoinPoint jp, Throwable error)
{
System.err.println(error.getMessage());
}
}
#Component
public class Usage
{
#Autowired
Intf intf;
public void doStuff()
{
intf.method1();
}
}
So I'm wondering why the aspectj won't create the pointcut. I managed to make it work using execution(* *(..) throws SomeExc) which does the job for me but I still want to know what I did wrong.
Also since method1 is defined in an interface and I specify the annotation on implementing class, is there a way to make it work this way? Other proxying mechanisms like transaction management/security works this way in other parts of spring right? And if I'm using interface proxying would specifying the pointcut on implementing class create the pointcut? (I guess not since I'm not using cglib)
try to add #Component to MyAspect class
#Component
#Aspect
public class MyAspect {
...
simply mark your aspect method with
#After("#annotation(package.SomeAnnotation)")
Have a look at this for a step by step guide
Related
I have #Tenantable annotation to decide for pointCut :
#Target({ElementType.TYPE, ElementType.METHOD})
#Retention(RetentionPolicy.RUNTIME)
#Inherited
public #interface Tenantable {
}
this my aspect :
#Slf4j
#Aspect
#Configuration
public class TenancyAspect {
#Pointcut("execution(public * *(..))")
public void publicMethod() {}
#Around("publicMethod() && #within(com.sam.example.aspect.aspectexample.model.Tenantable)")
public Object tenatable(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("my operations ...");
return joinPoint.proceed();
}
}
This is working without any problem for this service class :
#Tenantable
#Service
public class MyService(){
public void doSomething(){
...
}
}
my aspect is running when I call doSomething() method, It is ok but I want to implement aspect for CrudRepository interface that belongs spring data.
I have changed my Aspect to achieve this like below :
#Slf4j
#Aspect
#Configuration
public class TenancyAspect {
#Pointcut("execution(public * *(..))")
public void publicMethod() {}
#Pointcut("this(org.springframework.data.repository.Repository)")
public void repositoryExec(){}
#Around("publicMethod() && repositoryExec() && #within(com.sam.example.aspect.aspectexample.model.Tenantable)")
public Object tenatable(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("my operations ...");
return joinPoint.proceed();
}
}
this is repository :
#Tenantable
#Repository
public interface MyRepository extends CrudRepository{
}
But it doesn't work when I call any method inside of MyRepository.
Is there anyway to do this?
Edit :
It works for all repositories when I apply these :
#Pointcut("execution(public * org.springframework.data.repository.Repository+.*(..))")
and exclude this :
#within(com.sam.example.aspect.aspectexample.model.Tenantable)
But I need this anotation to apply it for specific repositories.
Having taken another look, I think I know what is going on here: You are assuming that just because you made your annotation #Inherited, it will be inherited by implementing classes if you annotate an interface. But this assumption is wrong. #Inherited only works in exactly one case: when extending an annotated base class. It does not work for annotated interfaces, methods etc. This is also documented here:
Note that this meta-annotation type has no effect if the annotated type is used to annotate anything other than a class. Note also that this meta-annotation only causes annotations to be inherited from superclasses; annotations on implemented interfaces have no effect.
As soon as you annotate your implementing class, it works.
Your repositoryExec pointcut should end with + to advice all subclass of Repository
#Pointcut("this(org.springframework.data.repository.Repository+)")
I have an interceptor binding annotation :
#InterceptorBinding
#Target({ElementType.TYPE, ElementType.METHOD})
#Retention(RetentionPolicy.RUNTIME)
public #interface MyBinding {
}
To this CDI interceptor :
#Interceptor
#MyBinding
public class MyInterceptor {
#AroundInvoke
public Object applyPolicy(InvocationContext ctx) throws Exception {
return blablabla;
}
}
And a class annotated, that mean every methods of this class will invoke MyInterceptor
#MyBinding
public class GlobalController {
public void methodA() {...}
public void methodB() {...}
}
All works fine, but I wish methodB not invoking my interceptor.
I tried both annotations #ExcludeClassInterceptors and #ExcludeDefaultInterceptors on my method but it doesn't works for me. I think these annotations are especially for exclude a method for EJB Interceptor, and not CDI Interceptor with Interceptor binding.
Not sure about these annotations but as a workaround you can add an annotation to the method you want to exclude. Get Method from InvocationContext in the interceptor and check whether the method has the annotation. In this case just delegate to the original method.
Try #MyBinding at method level:
public class GlobalController {
#MyBinding
public void methodA() {...}
public void methodB() {...}
}
I have
#Aspect
public class MyAspect {
int x,y,z;
public MyAspect(int _x,int _y,int _z){
x=_x;
y=_y;
z=_z;
}
#After("execution(public * save(..))")
public void methodAfter(JoinPoint joinPoint) {
//code
}
after calling save method,it doesn't execute the methodAfter. However,without constructor,it works.How can I use aspectj with constructors?
I assume you are working in a spring environment, so what I suggest you'll do is:
Add #Component annotation to your aspect.
Use #Inject and #Value annotations to inject it with the required values for x,y,z.
I am using spring aspect -around advice;
For super.method() or inter class method call, I am unable to call my aspect code;
This is my code sample.
//My aspect Class
#Aspect
public class MyAspect {
#Around("execution(* in.test.project.service.myservice.create(..))")
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
// .
//my logic
// .
}
public interface Myservice{
void create(Myclass entity);
void createObject(Myclass entity);
}
class myserviceImpl implements Myservice{
public void create(Myclass entity) {
// TODO Auto-generated method stub
}
void createObject(Myclass entity){
create(entity);
}
}
class Mycontroller {
void test(Myclass entity) {
Myservice myservice = new myserviceImplimplements();
// calls MyAspect code
myservice.create(entity);
// MyAspect not called
myservice.createObject(entity);
}
}
This a limitation of using Spring AOP without having your code know that it is using Spring AOP (you can view Spring's documentation on how you could do this as well as why you shouldn't on their "Understanding AOP proxies" page). Spring AOP is a proxy-based system and differentiates between the proxy object itself (bound to this) and the target object behind the proxy (bound to target), so you are also limited in what kinds of pointcuts you can apply.
Since the call first goes through the proxy and then on the object, calls made inside of the object on that object (like the call you have above that calls a method inside) are called on the Object itself and not the proxy. The calls that go through the proxy can delegate to relevant interceptors, while calls that are made by the Object itself do not proxy, and thus can not be advised by Spring AOP like this. The link I provided above shows to expose the AopContext, but I would highly recommend against doing that.
I have service that has several overloaded methods, for example:
MyService.execute(Long id);
MyService.execute(Collection collection);
And i need to intercept only execution of 'MyService.execute(Long id)' via AOP like:
#Aspect
#Component
public class AopInterseptor{
#After("execution(* my.Service.MyService.execute(..))")
public void intercept(JoinPoint joinPoint) throws Exception {
// Do stuff
}
}
Is it possible to do so?
What about:
#Aspect
#Component
public class AopInterseptor{
#After("execution(* my.Service.MyService.execute(Long))")
public void intercept(JoinPoint joinPoint) throws Exception
{
// Do stuff
}
}
This Poincut designator matches only if there is only one param with type Long given in the method call.