Oct 13 2012

Learning Spring, part III

Category: TechnicalIuliana @ 18:15

I have a new hot question for you:

We have two classes AccountServiceImpl and ClientServiceImpl. Any of these classes inherits from each other, meaning one is a subclass of the other. What will happen if we define a pointcut like this:

"execution( * *..AccountServiceImpl.update(..)) 
       && execution( * *..ClientServiceImpl.update(..)) "

And here are your options:

  1. The pointcut matches any public update methods of the two classes whatever the arguments.
  2. The pointcut matches any update methods of the 2 classes whatever the arguments and the method visibility.
  3. The pointcut matches any update methods of the two classes, with one ore more arguments and whatever the method visibility.
  4. No join point is defined.
  5. Something else will happen.


So what is the correct answer? We can eliminate 2 & 3, because of obvious reasons, quote: “Due to the proxy-based nature of Spring’s AOP framework, protected methods are by definition not intercepted, neither for JDK proxies (where this isn’t applicable) nor for CGLIB proxies (where this is technically possible but not recommendable for AOP purposes). As a consequence, any given pointcut will be matched against public methods only!”.

1 looks to be right, but that pointcut has an &&, which forces the method to be advised to belong to a class which will respect the following condition:

(myInstance instanceof ClientServiceImpl) && (myInstance instanceof AccountServiceImpl) == true

So yes, it is 5, something else will happen. The only update methods which will match that pointcut will be the ones in the subclass, whichever that is.

Here is the sample code I’ve tested:

@Aspect
public class UpdateNoticer {

    @Before("execution( * *..AccountServiceImpl.update(..)) && execution( * *..ClientServiceImpl.update(..)) ")
    public void beforeUpdate(JoinPoint jp){
        System.out.println( " ---> BEFORE: " +  jp.toString());
    }
}

@Component("asl")
public class AccountServiceImpl {
    public void update(){
        System.out.println("AccountServiceImpl.update");
    }
}

@Component("csl")
public class ClientServiceImpl extends  AccountServiceImpl{

    public void update(){
        System.out.println("ClientServiceImpl.update");
    }
}

// Test class
@ContextConfiguration(locations = {"classpath:META-INF/system-test-config.xml"})
@RunWith(SpringJUnit4ClassRunner.class)
public class PerformanceTests {
    @Autowired
    @Qualifier("csl")
    ClientServiceImpl csl;

    @Autowired
    @Qualifier("asl")
    AccountServiceImpl asl;

    @Test
    public void testNoticer(){
        csl.update();
        asl.update();
    }
}

And this is the configuration:

<context:component-scan base-package="pck" />
<bean id="updateNoticer" class="pck.UpdateNoticer"/>
<aop:aspectj-autoproxy>
    <aop:include name="updateNoticer" />
</aop:aspectj-autoproxy>

Result printed in the console:

 ---> BEFORE: execution(void pck.ClientServiceImpl.update())
ClientServiceImpl.update
AccountServiceImpl.update

If you test this and have a different opinion about this, or you get a different result please let’s talk about it!

Tags: ,

Leave a Reply