Spring AOP with custom Annotation without AspectJ example!

A what example did you say?

Directory Layout
.
├── pom.xml
└── src
    └── main
        └── java
            └── biz
                └── tugay
                    └── springaopexamples
                        ├── App.java
                        ├── aop
                        │   ├── Loggable.java
                        │   ├── advice
                        │   │   └── TimeLoggingInterceptorImpl.java
                        │   ├── advisor
                        │   │   └── ByAnnotationLoggingAspectImpl.java
                        │   └── pointcut
                        │       └── LogPointcutImpl.java
                        └── service
                            ├── MyLoggable.java
                            └── MyLoggableClassImpl.java

pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
                             http://maven.apache.org/maven-v4_0_0.xsd">
 
    <modelVersion>4.0.0</modelVersion>
 
    <groupId>biz.tugay</groupId>
    <artifactId>${project.name}</artifactId>
    <packaging>jar</packaging>
 
    <version>1.0-SNAPSHOT</version>
 
    <name>${project.name}</name>
    <url>http://www.tugay.biz</url>
 
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.3.12.RELEASE</version>
        </dependency>
    </dependencies>
 
    <properties>
        <project.name>springaopexamples</project.name>
        <maven.compiler.source>1.7</maven.compiler.source>
        <maven.compiler.target>1.7</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
</project>

Loggable.java
package biz.tugay.springaopexamples.aop;
 
import java.lang.annotation.*;
 
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Loggable {
}

TimeLoggingInterceptorImpl.java
package biz.tugay.springaopexamples.aop.advice;
 
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
 
public class TimeLoggingInterceptorImpl implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        final long start = System.currentTimeMillis();
        final Object proceed = invocation.proceed();
        final long end = System.currentTimeMillis();
        System.out.println("Your time has been logged: " + (end - start) + " milliseconds.");
        return proceed;
    }
}

LogPointcutImpl.java
package biz.tugay.springaopexamples.aop.pointcut;
 
import biz.tugay.springaopexamples.aop.Loggable;
import org.springframework.aop.ClassFilter;
import org.springframework.aop.MethodMatcher;
import org.springframework.aop.Pointcut;
import org.springframework.aop.support.annotation.AnnotationClassFilter;
import org.springframework.aop.support.annotation.AnnotationMethodMatcher;
 
 
public class LogPointcutImpl implements Pointcut {
 
    private final Class<Loggable> loggableAnnotation = Loggable.class;
 
    @Override
    public ClassFilter getClassFilter() {
        return new AnnotationClassFilter(loggableAnnotation);
    }
 
    @Override
    public MethodMatcher getMethodMatcher() {
        return new AnnotationMethodMatcher(loggableAnnotation);
    }
}

ByAnnotationLoggingAspectImpl.java
package biz.tugay.springaopexamples.aop.advisor;
 
import biz.tugay.springaopexamples.aop.advice.TimeLoggingInterceptorImpl;
import biz.tugay.springaopexamples.aop.pointcut.LogPointcutImpl;
import org.springframework.aop.support.DefaultPointcutAdvisor;
 
public class ByAnnotationLoggingAspectImpl extends DefaultPointcutAdvisor {
    public ByAnnotationLoggingAspectImpl() {
        setPointcut(new LogPointcutImpl());
        setAdvice(new TimeLoggingInterceptorImpl());
    }
}

MyLoggable.java
package biz.tugay.springaopexamples.service;
 
public interface MyLoggable {
    void logMePlease();
    void doNotLogMePlease();
}

MyLoggableImpl.java
package biz.tugay.springaopexamples.service;
 
import biz.tugay.springaopexamples.aop.Loggable;
 
@Loggable
public class MyLoggableClassImpl implements MyLoggable {
 
    @Loggable
    public void logMePlease() {
        System.out.println("Log my time please!");
    }
 
    public void doNotLogMePlease() {
        System.out.println("Do not log me please!");
    }
}

App.java
package biz.tugay.springaopexamples;
 
import biz.tugay.springaopexamples.aop.advisor.ByAnnotationLoggingAspectImpl;
import biz.tugay.springaopexamples.service.MyLoggableClassImpl;
import biz.tugay.springaopexamples.service.MyLoggable;
import org.springframework.aop.Advisor;
import org.springframework.aop.framework.ProxyFactory;
 
public class App {
 
    public static void main(String[] args) {
        final MyLoggable myLoggable = new MyLoggableClassImpl();
        final Advisor byAnnotationLoggingAspect = new ByAnnotationLoggingAspectImpl();
 
        final ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.setTarget(myLoggable);
        proxyFactory.addAdvisor(byAnnotationLoggingAspect);
 
        final MyLoggable proxy = (MyLoggable) proxyFactory.getProxy();
        proxy.logMePlease();
        proxy.doNotLogMePlease();
    }
}

In Action
Log my time please!
Your time has been logged: 26 milliseconds.
Do not log me please!

Notes

There is a connivence class you can use: AnnotationMatchingPointcut. Here is how we could have used it:
package biz.tugay.springaopexamples.aop.advisor;
 
import biz.tugay.springaopexamples.aop.Loggable;
import biz.tugay.springaopexamples.aop.advice.TimeLoggingInterceptorImpl;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.aop.support.annotation.AnnotationMatchingPointcut;
 
public class ByAnnotationLoggingAspectImpl extends DefaultPointcutAdvisor {
    public ByAnnotationLoggingAspectImpl() {
        setPointcut(new AnnotationMatchingPointcut(Loggable.class, Loggable.class));
        setAdvice(new TimeLoggingInterceptorImpl());
    }
}