0

I am trying to execute a aspect on proxy object

package thispkg;

public class MyLogger {
    public void before() {
        System.out.println("=========Before========");
    }
    public void after() {
        System.out.println("=========After=========");
    }
    public void info() {
        System.out.println("=========Info=========");
    }
}

package thispkg;

public interface MyInterface {
    public void speak();
}

package thispkg;

public class MyInterfaceImpl implements MyInterface {
    @Override
    public void speak() {
        System.out.println("MyInterfaceImpl :: Hello world");
    }
}

package thispkg;

public class RandomClass {
    public void suvichar() {
        System.out.println("RandomClass (suvichar)::Karm kiye jaa, fal ki chinta mat kar");
    }
}

package thispkg;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("thispkg.xml");
        MyInterface in = (MyInterface) context.getBean("randomClass", RandomClass.class);
        in.speak();
    }
}

My XML

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd 
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <context:spring-configured/>
    <bean id="mylogger" class="thispkg.MyLogger"/>
    <bean id="randomClass" class="thispkg.RandomClass"/>
    <bean id="myInterfaceImpl" class="thispkg.MyInterfaceImpl"/>
    <aop:config proxy-target-class="true">
        <aop:aspect id="usageTrackerAspect" ref="mylogger">
            <aop:declare-parents types-matching="thispkg.RandomClass+" implement-interface="thispkg.MyInterface" default-impl="thispkg.MyInterfaceImpl"/>
            <aop:pointcut expression="this(thispkg.MyInterface)" id="randompointcut"/>
            <aop:before pointcut-ref="randompointcut" method="info"/>
        </aop:aspect>
    </aop:config>
</beans>

I have tried both thispkg.MyInterfaceImpl & thispkg.RandomClass in pointcut expression but still can't get the ========Info======== printed. Only prints

MyInterfaceImpl :: Hello world

Any clue ?

mkobit
  • 43,979
  • 12
  • 156
  • 150
S Kr
  • 1,831
  • 2
  • 25
  • 50

2 Answers2

0

I'm not sure if this is a bug or intended behavior.

You're adding MyInterface (and MyInterfaceImpl) as introductions with

<aop:declare-parents ... />

These are implemented with a specific interceptor (call it introduction interceptor) in the proxy object. The aspect is added as a separate interceptor (call it AOP interceptor) in the proxy. One cannot (does not) intercept the other.

If you do the following

RandomClass bean = context.getBean(RandomClass.class);
bean.suvichar();

your advice will get invoked because the AOP interceptor comes into play.

With

MyInterface in = (MyInterface) context.getBean("randomClass", RandomClass.class);
in.speak();

however, it's the introduction interceptor which handles the speak invocation. Your AOP interceptor is not involved and therefore doesn't invoke the before advice.

Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724
  • Yeah , but I wanted to understand this vs target as given in http://stackoverflow.com/questions/11924685/spring-aop-target-vs-this (2nd answer). I was looking for xml based answer of the same question. – S Kr Jan 20 '15 at 05:26
  • @SKr I don't understand where your _but_ applies. The root cause here is that there's a separation of interceptors for implementing **introductions**. This is a technical limitation in the current implementation of Spring's AOP stack. I don't know if it's by design. – Sotirios Delimanolis Jan 20 '15 at 05:31
  • My usual (Groundhog Day) hint in addition to Sotorios' great answer: If you switch from Spring AOP to full AspectJ you can get the desired behaviour because then the class will be modified (byte code instrumentation) and there is no need for any proxies. – kriegaex Jan 20 '15 at 12:47
0

So after some tries and then more reading and then more retries, i found that i can get the desired behaviour when using delegate-ref instead of default-impl, thus allowing spring to manage my implementation. Also correcting my pointcut expression.

<aop:aspect ref="mylogger">
        <aop:declare-parents types-matching="thispkg.RandomClass+" implement-interface="thispkg.MyInterface" delegate-ref="myInterfaceImpl"/>
        <aop:pointcut expression="execution(* thispkg.MyInterface.speak())" id="randompointcut"/>
        <aop:before method="info" pointcut-ref="randompointcut"/>
</aop:aspect>

Output

=========Info=========
MyInterfaceImpl :: Hello world
S Kr
  • 1,831
  • 2
  • 25
  • 50