Simple examples of Spring AOP

With AOP in mind, we’ll write an annotated example of Spring AOP. There are plenty of examples on the web, and this article will only post some key code

package com.aop.biz;

class BizA {
    public void doSomething(a) {
        //do something...}}class BizB {
    public void doSomething(a) {
        //do something...}}Copy the code

Define two business classes

import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect
public class LogAspect {
    
    @Before("execution(** com.aop.biz.*.*(..) )")
    public void before(a) {
        System.out.println("before");
    }

    @AfterReturning("execution(** com.aop.biz.*.*(..) )")
    public void after(a) {
        System.out.println("after"); }}Copy the code

Implement an Aspect (@aspect) that includes a pre (@before), a post (@afterreturning), and a cut point

(execution (* * com. Aop. Biz. *. * (..) ))Copy the code

Matches all methods under the BIZ package.

It is also possible to extract further, by separating the pointcut into a method, myPointcut, into which other Advice is introduced

@Aspect
public class LogAspect {

    @Pointcut("execution(** com.aop.LogAspect.doSomething(..) )")
    public void myPointcut(a) {}@Before("mypointcut()")
    public void before(a) {
        System.out.println("before");
    }

    @AfterReturning("mypointcut()")
    public void after(a) {
        System.out.println("after"); }}Copy the code

That’s a simple example, but to get a better understanding of Spring AOP, we’ll try implementing an AOP ourselves in the next section

Implement an AOP yourself

Custom annotation

The Aspect annotation class

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Aspect {
    public String value(a) default "";
}
Copy the code

Before annotation class (only defines Before as advice)

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Before {
    String value(a);
}
Copy the code

Pointcut annotation class

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Pointcut {
    String value(a) default "";
}
Copy the code

Define a log aspect

@Aspect
public class MyLogAspect {
    @Pointcut("com.aop.biz.*.*")
    public void pointcut(a) {}@Before("pointcut")
    public void beforeAdvice(Method method,Object object) {
        System.out.println("-------before------"); System.out.println(object.getClass().getName()); }}Copy the code

Implement AOP

final ClassPath cp = ClassPath.from(AspectLoader.class.getClassLoader());
final ImmutableSet<ClassPath.ClassInfo> allClasses = cp.getAllClasses();

//1. Get the class with the @aspect annotation
Class aspectClass = getAspectClass(allClasses.asList());

/ / 2-1. Get before
Before before = getBefore(aspectClass);

//2-2. Get before related methods
Method beforeMethod = getBeforeMethod(aspectClass);

//2-3. Get the pointcut
String methodName = before.value().replace("()"."");
Pointcut pointcut = getPointcut(aspectClass, methodName);

//3. Build the advice and pointcut relationship
/ /...

//4. Locate the pointcut target class
List<Class> targets = getTargetClasses(allClasses.asList(),pointcut.value());

//5-1. Generate an aspect instance
Object aspectObject = aspectClass.newInstance();

//5-2. Through the dynamic proxy, add advice to the interceptor of the proxy class, and finally put the proxy object into a container for invocation
for (Class c : targets) {
    Enhancer enhancer = new Enhancer();
    enhancer.setSuperclass(c);
    enhancer.setCallback(new MethodInterceptor(){
        @Override
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
            // TODO Auto-generated method stub
            beforeMethod.invoke(aspectObject,method,obj);
            proxy.invokeSuper(obj, args);
            returnobj; }}); Object o = enhancer.create();this.beanContainer.put(c.getSimpleName(),o);
}
Copy the code

The previous steps 1 through 4 are based on Java reflection and won’t be covered here. The key is step 5, which implements the object’s proxy based on Cglib, dynamically preempting the advice of type before to the target method call.

call

public static void main(final String[] args) throws Exception {
    AspectLoader aspectLoader = new AspectLoader();
    aspectLoader.init();
    BizA bizA = (BizA) aspectLoader.beanContainer.get(BizA.class.getSimpleName());
    bizA.doSomething();

    BizB bizB = (BizB) aspectLoader.beanContainer.get(BizB.class.getSimpleName());
    bizB.doSomething();
}
Copy the code

Call result:

-------before------
com.aop.biz.BizA$$EnhancerByCGLIB$$6fba1eda
-------before------
com.aop.biz.BizB$$EnhancerByCGLIB$$7b80fb85
Copy the code

Note: We can see that the original BizA class is actually executed as BizA? EnhancerByCGLIB? XXX, this is the dynamic proxy class generated by Cglib