Custom Aspect style AOP framework

This blog refer to "Architecture Adventure - written from scratch java web framework" section 4.3
1 Proxy Interface:

package smart.myaop.framework;

public interface Proxy {
    /**
     * 执行链式调用
     */
    Object doProxy(ProxyChain proxyChain) throws Throwable;
}

Agent 2 chain (chain of responsibility pattern, the same object may be a plurality of layers Proxy Agent):

package smart.myaop.framework;

import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * 代理链
 */
public class ProxyChain {
    private final Class<?> targetClass; //目标类
    private final Object targetObject; //目标对象
    private final Method targetMethod; //目标方法
    private final MethodProxy methodProxy; //方法代理,cglib提供的方法代理对象
    private final Object[] methodParams; //方法参数

    private List<Proxy> proxyList = new ArrayList<>(); //代理列表
    private int proxyIndex = 0; //代理索引

    public ProxyChain(Class<?> targetClass, Object targetObject, Method targetMethod, MethodProxy methodProxy, Object[] methodParams, List<Proxy> proxyList) {
        this.targetClass = targetClass;
        this.targetObject = targetObject;
        this.targetMethod = targetMethod;
        this.methodProxy = methodProxy;
        this.methodParams = methodParams;
        this.proxyList = proxyList;
    }

    public Class<?> getTargetClass() {
        return targetClass;
    }

    public Method getTargetMethod() {
        return targetMethod;
    }

    public Object[] getMethodParams() {
        return methodParams;
    }

    /**
     * 在Proxy接口的实现中提供相应横切逻辑并调用doProxyChain方法
     * methodProxy的invokeSuper方法执行目标对象的业务逻辑
     * @return
     * @throws Throwable
     */
    public Object doProxyChain() throws Throwable {
        Object methodResult;
        if(proxyIndex < proxyList.size()) {
            methodResult = proxyList.get(proxyIndex++).doProxy(this);
        } else {
            methodResult = methodProxy.invokeSuper(targetObject, methodParams);
        }
        return methodResult;
    }
}

3 tools to create a proxy object:

package smart.myaop.framework;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;
import java.util.List;

/**
 * 代理管理器,输入目标类和一组proxy接口实现,创建一个代理对象并输出
 * 由切面类来调用ProxyManager创建代理链,切面类在目标方法调用前后进行增强
 *
 * 在框架里使用ProxyManager创建代理对象并放入ioc容器,然后将代理对象注入到其它对象中
 */
public class ProxyManager {
    public static <T> T createProxy(final Class<?> targetClass, final List<Proxy> proxyList) {
        return (T) Enhancer.create(targetClass, new MethodInterceptor() {
            @Override
            public Object intercept(Object targetObject, Method targetMethod, Object[] methodParams, MethodProxy methodProxy) throws Throwable {
                return new ProxyChain(targetClass, targetObject, targetMethod, methodProxy, methodParams, proxyList);
            }
        });
    }
}

Abstract achieve 4Proxy interface template method pattern:

package smart.myaop.framework;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Method;

/**
 * 切面代理
 * 该抽象类提供模板方法,由其子类扩展相应的抽象方法
 */
public abstract class AspectProxy implements Proxy {
    private static final Logger logger = LoggerFactory.getLogger(AspectProxy.class);
    @Override
    public Object doProxy(ProxyChain proxyChain) throws Throwable {
        Object result = null;
        Class<?> cls = proxyChain.getTargetClass();
        Method method = proxyChain.getTargetMethod();
        Object[] params = proxyChain.getMethodParams();
        /**
         * 从proxyChain中获取目标类,目标方法和目标参数,通过try ... catch ...finally代码块调用代理框架
         */
        begin();
        try {
            if(intercept(cls, method, params)) {
                before(cls, method, params);
                result = proxyChain.doProxyChain();
                after(cls, method, result);
            }
        } catch (Exception e) {
            logger.error("proxy failure", e);
            error(cls, method, params, e);
        } finally {
            end();
        }
        return result;
    }

    /**
     * 下面几个都是钩子方法,可在子类中有选择性的实现,可以有选择性的实现,所以不定义成抽象方法
     */
    public boolean intercept(Class<?> cls, Method method, Object[] params) {
        return true;
    }

    public void before(Class<?> cls, Method method, Object[] params) {}

    public void after(Class<?> cls, Method method, Object result) {}

    public void begin() {}

    public void end() {}

    public void error(Class<?> cls, Method method, Object[] params, Exception e) {}
}

5 illustrates a specific Proxy implementation:

package smart.myaop;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import smart.myaop.framework.AspectProxy;

import java.lang.reflect.Method;

/**
 * 该示例类继承AspectProxy类,指定拦截Controller所有方法,并在方法前后加日志并记录执行时间
 */
@Aspect(Controller.class)
public class ControllerAspect extends AspectProxy {
    private static final Logger logger = LoggerFactory.getLogger(ControllerAspect.class);
    private long begin;
    @Override
    public void before(Class<?> cls, Method method, Object[] params) {
        logger.debug("----------begin----------");
        logger.debug(String.format("class: %s"), cls.getName());
        logger.debug(String.format("method: %s"), method.getName());
        begin = System.currentTimeMillis();
    }
    @Override
    public void after(Class<?> cls, Method method, Object result) {
        logger.debug(String.format("time: %dms"), System.currentTimeMillis() - begin);
        logger.debug("----------end----------");
    }
}

6 custom annotation @Aspect, as a proxy marker:

package smart.myaop;

import java.lang.annotation.*;

/**
 * 切面注解
 */
@Target(ElementType.TYPE) //只能用在类上
@Retention(RetentionPolicy.RUNTIME)
public @interface Aspect {
    /**
     * 注解,注解类,用来定义注解
     * @return
     */
    Class<? extends Annotation> value();
}

7 initialize framework and create a proxy object into the ioc container:

package smart.myaop;

import smart.myaop.framework.AspectProxy;
import smart.myaop.framework.Proxy;
import smart.myaop.framework.ProxyManager;

import java.lang.annotation.Annotation;
import java.util.*;

/**
 * 初始化时获取所有目标类和其被拦截的切面类实例,获取AspectProxy抽象类的所有子类和@Aspect注解的所有类
 * 调用ProxyManager#createProxy方法创建代理对象放入ioc容器
 * AopHelper在框架初始化时调用,要在初始化bean之后,ioc容器初始化之前调用,这样ioc容器做属性注入时候才能拿到相应的代理对象
 */
public class AopHelper {
    private static Set<Class<?>> allClassSet = new HashSet<>(); //项目启动时把指定路径下的所有class文件加载为class对象集合,过程略

    static {
        try {
            Map<Class<?>, Set<Class<?>>> proxyMap = createProxyMap();
            Map<Class<?>, List<Proxy>> targetMap = createTargetMap(proxyMap);
            for (Map.Entry<Class<?>, List<Proxy>> targetEntry : targetMap.entrySet()) {
                Class<?> targetClass = targetEntry.getKey();
                List<Proxy> proxyList = targetEntry.getValue();
                Object proxy = ProxyManager.createProxy(targetClass, proxyList);
                //todo 放入targetClass为键,proxy为值放入ioc容器,在ioc容器做属性注入的时候通过class对象拿到的就是代理对象了
            }
        } catch (Exception e) {
            System.out.println("aop failure");
            e.printStackTrace();
        }
    }

    /**
     * 目标类与代理对象列表之间的映射关系,如一个业务类被多个@Aspect注解修饰的AspectProxy子类代理,这里得到这样的1对n映射关系
     * @param proxyMap
     * @return
     * @throws Exception
     */
    private static Map<Class<?>, List<Proxy>> createTargetMap(Map<Class<?>, Set<Class<?>>> proxyMap) throws Exception {
        Map<Class<?>, List<Proxy>> targetMap = new HashMap<>();
        for (Map.Entry<Class<?>, Set<Class<?>>> proxyEntry : proxyMap.entrySet()) {
            Class<?> proxyClass = proxyEntry.getKey();
            Set<Class<?>> targetClassSet = proxyEntry.getValue();
            for (Class<?> targetClass : targetClassSet) {
                Proxy proxy = (Proxy) proxyClass.newInstance();
                if(targetMap.containsKey(targetClass)) {
                    targetMap.get(targetClass).add(proxy);
                } else {
                    List<Proxy> proxyList = new ArrayList<>();
                    proxyList.add(proxy);
                    targetMap.put(targetClass, proxyList);
                }
            }
        }
        return targetMap;
    }

    /**
     * 给createTargetMap方法用
     * 代理类(切面类)与目标类集合之间的一对多映射关系
     * 在全部class对象集合中搜索满足1是AspectProxy子类,2被@Aspect注解,这样的类(代理类),根据@Aspect注解指定的注解属性去获取该注解对应的目标类集合
     * 然后建立代理类与目标类集合之间的映射关系,据此分析出目标类与代理对象列表之间的映射关系
     * @return
     * @throws Exception
     */
    private static Map<Class<?>, Set<Class<?>>> createProxyMap() throws Exception {
        Map<Class<?>, Set<Class<?>>> proxyMap = new HashMap<>();
        Set<Class<?>> proxyClassSet = new HashSet<>();
        for (Class<?> aClass : allClassSet) {
            if(AspectProxy.class.isAssignableFrom(aClass) && !AspectProxy.class.equals(aClass)) {
                proxyClassSet.add(aClass); //获取AspectProxy子类class对象集合
            }
        }
        for (Class<?> aClass : proxyClassSet) {
            if(aClass.isAnnotationPresent(Aspect.class)) {
                Aspect aspect = aClass.getAnnotation(Aspect.class);
                Set<Class<?>> targetClassSet = createTargetClassSet(aspect);
                proxyMap.put(aClass, targetClassSet);
            }
        }
        return proxyMap;
    }

    /**
     * 给createProxyMap方法用
     * 获取被指定aspect注解的所有类对象
     * @param aspect
     * @return
     * @throws Exception
     */
    private static Set<Class<?>> createTargetClassSet(Aspect aspect) throws Exception {
        Set<Class<?>> targetClassSet = new HashSet<>();
        Class<? extends Annotation> annotation = aspect.value();
        if(annotation != null && annotation.equals((Aspect.class))) {
            for (Class<?> aClass : allClassSet) {
                if(aClass.isAnnotationPresent(annotation)) {
                    targetClassSet.add(aClass); //这里从所有的class集合中挑出被annotation类型注解的class对象集合
                }
            }
        }
        return targetClassSet;
    }
}

Note: The code is written from 1 7, from 7-1 understanding helps to understand the overall workflow, with the whole chain of responsibility pattern, the template method pattern, CGLIB dynamic proxy. The book is called Proxy and ProxyChain called the agent and agent chain, change the name and Reinforced chain easier to understand, each Proxy method is to target a class of functional enhancements.

Guess you like

Origin www.cnblogs.com/kibana/p/11762432.html