JavaEE手寫AOP實現,自動代理, AOP 面向切面的編程思想

AOP 面向切面的編程思想。 Spring的主要特性之一,今天我整理了一下,小牛試刀,寫了一個Demo分享給大家。  

切面最主要的功能是在不影響主業務方法邏輯的情況下,在執行業務方法之前或之後加入執行代碼。
在JavaEE中最常見的莫過於事務控制, 使得程序員只需關注核心業務邏輯,而無需關注事務相反非業務而又必須要的代碼。 

切面的主要組件有:  

    1、切面(@Aspect)。 

    2、切點(@Pointcut)、

    3、通知方法(@Advise),主要有3個

             1、執行前通知- @Before

             2、執行後通知- @After

             3、環繞通知- @Around


 關係圖如下:

wKiom1nXZb6BETfJAABcZ2Q2RgM334.png-wh_50

AOP項目展開截圖:


wKioL1nXa3XA65q0AADXVm9ZNt0398.png-wh_50


InstanceFactory 源碼:

package com.hianzuo.aop;


import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/**
 * Created by Ryan
 * On 2017/10/5.
 */
public class InstanceFactory {
    private static final HashMap<Class<?>, Object> classBeanMap = new HashMap<>();
    private static final HashMap<String, Object> beanNameMap = new HashMap<>();
    private static final HashMap<Class<? extends Annotation>, List<AspectAdviceMethod>> mAspectPointcutMethodListMap = new HashMap<>();

    public static <T> T getInstance(Class<T> clazz) {
        return (T) classBeanMap.get(clazz);
    }

    public static <T> T getInstance(String beanName) {
        return (T) classBeanMap.get(beanName);
    }

    public static void init(String pnScan) {
        List<Class<?>> classes = ClassUtil.getClasses(pnScan);
        for (Class<?> clazz : classes) {
            if (isAspectClazz(clazz)) {
                initAspect(clazz);
            }
        }
        for (Class<?> clazz : classes) {
            if (isBeanClazz(clazz)) {
                initBean(clazz);
            }
        }
    }

    private static void initAspect(Class<?> aspectClazz) {
        Method[] methods = aspectClazz.getMethods();
        Object obj;
        try {
            obj = aspectClazz.newInstance();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        for (Method method : methods) {
            if (method.isAnnotationPresent(Before.class)) {
                Before adviceBefore = method.getAnnotation(Before.class);
                List<AspectAdviceMethod> adviceList = getAspectAdviceList(Before.class);
                adviceList.add(new AspectAdviceMethod(adviceBefore.value(), adviceBefore.order(), obj, method));
            }
            if (method.isAnnotationPresent(After.class)) {
                After adviceAfter = method.getAnnotation(After.class);
                List<AspectAdviceMethod> adviceList = getAspectAdviceList(After.class);
                adviceList.add(new AspectAdviceMethod(adviceAfter.value(), adviceAfter.order(), obj, method));
            }
            if (method.isAnnotationPresent(Around.class)) {
                Around adviceAround = method.getAnnotation(Around.class);
                List<AspectAdviceMethod> adviceList = getAspectAdviceList(Around.class);
                adviceList.add(new AspectAdviceAroundMethod(adviceAround.value(), adviceAround.order(), obj, method));
            }
        }

    }

    private static List<AspectAdviceMethod> getAspectAdviceList(Class<? extends Annotation> adviceClazz) {
        List<AspectAdviceMethod> methodList = mAspectPointcutMethodListMap.get(adviceClazz);
        if (null == methodList) {
            methodList = new ArrayList<>();
            mAspectPointcutMethodListMap.put(adviceClazz, methodList);
        }
        return methodList;
    }

    private static boolean isAspectClazz(Class<?> aClass) {
        if (aClass.isAnnotationPresent(Aspect.class)) {
            return true;
        }
        return false;
    }

    private static void initBean(Class<?> beanClazz) {
        Class<?>[] interfaces = beanClazz.getInterfaces();
        if (null == interfaces) return;
        for (Class<?> anInterface : interfaces) {
            String beanName = getBeanName(anInterface);
            Object obj = newInstanceProxyClass(anInterface, beanClazz);
            beanNameMap.put(beanName, obj);
            classBeanMap.put(anInterface, obj);
        }
    }

    private static Object newInstanceProxyClass(Class<?> anInterface, Class<?> beanClazz) {
        try {
            Object targetObj = beanClazz.newInstance();
            return Proxy.newProxyInstance(targetObj.getClass().getClassLoader(), new Class<?>[]{anInterface}, new AspectHandler(targetObj, mAspectPointcutMethodListMap));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private static String getBeanName(Class<?> anInterface) {
        return anInterface.getSimpleName();
    }

    private static boolean isBeanClazz(Class<?> aClass) {
        if (aClass.isAnnotationPresent(Component.class)) {
            return true;
        }
        return false;
    }
}
AspectHandler 源碼:
package com.hianzuo.aop;

import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.*;

/**
 * Created by Ryan
 * On 2017/10/5.
 */
class AspectHandler implements InvocationHandler {
    private Object targetObj;
    private HashMap, List> mAspectPointcutMethodListMap;
    private HashMap> mBeforeMethodMap = new HashMap<>();
    private HashMap> mAfterMethodMap = new HashMap<>();
    private HashMap mAroundMethodMap = new HashMap<>();

    public AspectHandler(Object targetObj, HashMap, List> map) {
        this.targetObj = targetObj;
        this.mAspectPointcutMethodListMap = map;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        List beforeMethods = getBeforeMethodList(method);
        JointPoint beforePoint = new JointPoint().setTargetObj(targetObj).setProxy(proxy).setMethod(method).setArgs(args);
        for (AspectAdviceMethod adviceMethod : beforeMethods) {
            adviceMethod.invoke(beforePoint);
        }
        AspectAdviceAroundMethod aroundMethod = getAroundMethodList(method);
        Object obj;
        if (null != aroundMethod) {
            obj = aroundMethod.invoke(beforePoint);
        } else {
            obj = method.invoke(targetObj, args);
        }
        List afterMethods = getAfterMethodList(method);
        JointPoint afterPoint = new JointPoint().setTargetObj(targetObj).setProxy(proxy).setMethod(method).setArgs(args).setResult(obj);
        for (AspectAdviceMethod adviceMethod : afterMethods) {
            adviceMethod.invoke(afterPoint);
        }
        return obj;
    }

    private AspectAdviceAroundMethod getAroundMethodList(Method method) {
        if (mAroundMethodMap.containsKey(method)) return mAroundMethodMap.get(method);
        List adviceMethods = mAspectPointcutMethodListMap.get(Around.class);
        if (null == adviceMethods) return null;
        List list = new ArrayList<>();
        for (AspectAdviceMethod adviceMethod : adviceMethods) {
            AspectAdviceAroundMethod adviceAroundMethod = (AspectAdviceAroundMethod) adviceMethod;
            if (adviceAroundMethod.match(method)) {
                list.add(adviceAroundMethod);
            }
        }
        AspectAdviceAroundMethod aroundMethod = null;
        if (!list.isEmpty()) {
            sortAdviceList(list);
            AspectAdviceAroundMethod upMethod = null;
            for (AspectAdviceAroundMethod adviceAroundMethod : list) {
                if (null == aroundMethod) aroundMethod = adviceAroundMethod;
                if (null != upMethod) {
                    upMethod.setNextMethod(adviceAroundMethod);
                }
                upMethod = adviceAroundMethod;
            }
        }
        mAroundMethodMap.put(method, aroundMethod);
        return aroundMethod;
    }

    private static void sortAdviceList(List<? extends AspectAdviceMethod> list) {
        Collections.sort(list, (Comparator) (o1, o2) -> {
            Integer order1 = o1.getPointMethodOrder();
            Integer order2 = o2.getPointMethodOrder();
            return order1.compareTo(order2);
        });
    }

    private List getAfterMethodList(Method method) {
        return getAspectAdviceMethods(After.class, mAspectPointcutMethodListMap, mAfterMethodMap, method);
    }

    private List getBeforeMethodList(Method method) {
        return getAspectAdviceMethods(Before.class, mAspectPointcutMethodListMap, mBeforeMethodMap, method);
    }

    private static List getAspectAdviceMethods(Class<? extends Annotation> adviceClass, HashMap, List> dataMap, HashMap> methodMap, Method method) {
        List aspectAdviceMethods = methodMap.get(method);
        if (null != aspectAdviceMethods) return aspectAdviceMethods;
        aspectAdviceMethods = new ArrayList<>();
        methodMap.put(method, aspectAdviceMethods);
        List methods = dataMap.get(adviceClass);
        if (null == method) return aspectAdviceMethods;
        for (AspectAdviceMethod adviceMethod : methods) {
            if (adviceMethod.match(method)) {
                aspectAdviceMethods.add(adviceMethod);
            }
        }
        sortAdviceList(aspectAdviceMethods);
        return aspectAdviceMethods;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章