Saturday, April 14, 2012

Spring AOP–Examples

Source Code:Example

Setting Context

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd  http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd">
    <aop:aspectj-autoproxy/>
    <context:component-scan base-package="org.anotes.springexample.aop"/>
</beans>

Before, After, Around (example1)

Objects

public class Person {
    protected String name;

    public void walk(){
        logger.info(name+" is walking");
    }

@Component
@Scope("prototype")
public class Painter extends Person{

    public void paint(){
        logger.info(name+" is painting");
    }

}

@Component
@Scope("prototype")
public class Teacher extends Person {

    public void teach(){
        logger.info(name+" is teaching");
    }
}

Aspect

@Aspect
@Component("aspectExample1")
public class AspectExample {
    protected final Logger logger = LoggerFactory.getLogger(getClass());


    @Pointcut("execution(* org.anotes.springexample.aop.example1.*.walk(..))")
    private void anyWalking() {
    }


    @Pointcut("execution(* org.anotes.springexample.aop.example1.*.*(..)) && bean(teacher)")
    private void teacherMethods() {
    }


    @Pointcut("within(org.anotes.springexample.aop.example1.*))")
    public void inPainterAndTeacherMethods() {
    }


    @Before("anyWalking()")
    public void logBeforeAnyWalking(JoinPoint joinPoint) {
        logger.info("Before walking:{}", joinPoint.getTarget());
    }


    @After("anyWalking()")
    public void logAfterAnyWalking() {
        logger.info("After walking");
    }


    @Before("teacherMethods() && args(param)")
    public void logPainterAndTeacherMethodWithStringArg(String param) {
        logger.info("Teacher Methods:Before methods with String parameter:{}", param);
    }


    @Around("inPainterAndTeacherMethods()")
    public void logAllMethodsPainterAndTeacher(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        logger.info("Around: Before executing:" + proceedingJoinPoint.getSignature());
        proceedingJoinPoint.proceed();
        logger.info("Around: After executing:" + proceedingJoinPoint.getSignature());
    }

}

Lines

Line 5: Define a Pointcut that point to “walk” method of any Class that are in the “example1” package

Line 8: Define a Pointcut that point to all methods of the bean “teacher”

Line 11: Define a Pointcut that point to any method of  any Class that are in the “example1” package

Line 15: Define a Before Advice that will be called before executing any “walk” method

Line 19: Define a After Advice that will be called before executing any “walk” method

Line 23: Define a Before Advice that will be called before executing any method in the “teacher” bean that has at first parameter a String

Line 27: Define a Around Advice that will be called before executing any method in the “painter” and “teacher” bean

Code to test the Advice

public class Main {
    private static final Logger logger = LoggerFactory.getLogger(Main.class);
    public static void main(String[] args) {
        String configFiles = "classpath*:/app-context.xml";
        ApplicationContext context = new ClassPathXmlApplicationContext(configFiles);
        example1(context);
    }
    private static void example1(ApplicationContext context) {
        logger.info("EXAMPLE 1 - Before, After, Around ");
        Teacher teacher = context.getBean(Teacher.class);
        teacher.setName("Ross");
        Teacher teacher2 = context.getBean(Teacher.class);
        teacher2.setName("Jhon");
        Painter painter = context.getBean(Painter.class);
        painter.setName("Pedro");
        teacher.walk();
        painter.walk();
    }

Output

            aop.Main EXAMPLE 1 - Before, After, Around  [INFO ]
aspect.AspectExample Teacher Methods:Before methods with String parameter:Ross [INFO ]
aspect.AspectExample Around: Before executing:void org.anotes.springexample.aop.example1.Person.setName(String) [INFO ]
aspect.AspectExample Around: After executing:void org.anotes.springexample.aop.example1.Person.setName(String) [INFO ]
aspect.AspectExample Teacher Methods:Before methods with String parameter:Jhon [INFO ]
aspect.AspectExample Around: Before executing:void org.anotes.springexample.aop.example1.Person.setName(String) [INFO ]
aspect.AspectExample Around: After executing:void org.anotes.springexample.aop.example1.Person.setName(String) [INFO ]
aspect.AspectExample Around: Before executing:void org.anotes.springexample.aop.example1.Person.setName(String) [INFO ]
aspect.AspectExample Around: After executing:void org.anotes.springexample.aop.example1.Person.setName(String) [INFO ]
aspect.AspectExample Before walking:org.anotes.springexample.aop.example1.Teacher@1989b5 [INFO ]
aspect.AspectExample Around: Before executing:void org.anotes.springexample.aop.example1.Person.walk() [INFO ]
    example1.Teacher Ross is walking [INFO ]
aspect.AspectExample After walking [INFO ]
aspect.AspectExample Around: After executing:void org.anotes.springexample.aop.example1.Person.walk() [INFO ]
aspect.AspectExample Before walking:org.anotes.springexample.aop.example1.Painter@c3c315 [INFO ]
aspect.AspectExample Around: Before executing:void org.anotes.springexample.aop.example1.Person.walk() [INFO ]
    example1.Painter Pedro is walking [INFO ]
aspect.AspectExample After walking [INFO ]
aspect.AspectExample Around: After executing:void org.anotes.springexample.aop.example1.Person.walk() [INFO ]

Introductions / Mixins (example2)

Objects

public interface Resource {
     public void setContent(String content);
     public String getContent();

}
@Component
@Scope("prototype")
public class ResourceImpl implements Resource{
    protected final Logger logger = LoggerFactory.getLogger(getClass());

    private String content;
    @Override
    public void setContent(String content) {
        this.content=content;
        logger.info("Current Content:"+content);
    }

public interface Lockable {
    boolean isLocked();
    void lock();
    void unlock();
}
public class LockableImpl implements Lockable {
    private boolean lock = false;

    @Override
    public boolean isLocked() {
        return lock;
    }

    @Override
    public void lock() {
        lock= true;
    }

    @Override
    public void unlock() {
        lock =false;
    }
}

Aspect

@Aspect
@Component("aspectExample2")
public class AspectExample {
    protected final Logger logger = LoggerFactory.getLogger(getClass());


    @DeclareParents(value = "org.anotes.springexample.aop.example2.Resource*", defaultImpl = LockableImpl.class)
    private Lockable lockableSupport;


    @Pointcut("execution(* org.anotes.springexample.aop.example2.Resource.setContent(..))")
    private void settingContent() {
    }


    @Around("settingContent() && this(lockable)")
    private void onSettingContent(ProceedingJoinPoint joinPoint, Lockable lockable) throws Throwable {
        logger.info("Before Setting Content on Resource. Locked:" + lockable.isLocked());
        if (!lockable.isLocked()) {
            joinPoint.proceed();
            logger.info("After Setting Content:");
        } else {
            logger.info("The resource is locked so it is not possible to set its content");
        }
    }
}

Lines

Line 5: Define that the beans which class name begin with “Resource” and are in the example2 package will implement the “Lockable” interface and the default implementation will be provided by “LockableImpl” class

Line 7: Define a Pointcut that point to the “setContent” method of the beans of type Resource

Line 10: Define a Around Advice that will be called before executing the method “setContent” also the bean will be sent as a parameter implementing the Lockable interface

Code to test the introduction

public class Main {
    private static final Logger logger = LoggerFactory.getLogger(Main.class);
    public static void main(String[] args) {
        String configFiles = "classpath*:/app-context.xml";
        ApplicationContext context = new ClassPathXmlApplicationContext(configFiles);
        example1(context);
example2(context);
    }

    private static void example2(ApplicationContext context) {
        logger.info("EXAMPLE 2 - Using Introductions ");
        Resource resource = context.getBean(Resource.class);
        resource.setContent("String resource 1");
        Lockable lockable = (Lockable) resource;
        lockable.lock();
        resource.setContent("String resource 2");
        lockable.unlock();
        resource.setContent("String resource 3");
    }


}

Output

aspect.AspectExample Before Setting Content on Resource. Locked:false [INFO ]
example2.ResourceImpl Current Content:String resource 1 [INFO]
aspect.AspectExample After Setting Content: [INFO ]
aspect.AspectExample Before Setting Content on Resource. Locked:true [INFO ]
aspect.AspectExample The resource is locked so it is not possible to set its content [INFO ]
aspect.AspectExample Before Setting Content on Resource. Locked:false [INFO ]
example2.ResourceImpl Current Content:String resource 3 [INFO ]
aspect.AspectExample After Setting Content: [INFO]

2 comments:

Unknown said...

Interesting information about AOP, I think this Introduction / Mixin feature is new to me.

Mario Guerrero said...

Hi,

Very good post.

Thanks.

Post a Comment