1. 程式人生 > >手寫 簡單 aop 框架

手寫 簡單 aop 框架

cglib 手寫 簡單 aop 框架,實現方法級別的攔截


0 緣起

一直對 java 的動態代理 還有 spring 的 aop 理解不深刻, 所以打算實現一個簡單的 aop 目的是用於學習 cglib 和 aop 思想。

1 思路

1 掃描 aop 包, 獲取 aspect 的類

2 根據 切點 獲取該切點的 類 和 方法

3 根據配置的 類 和 方法 為該類生成一個代理物件 

4 將改代理物件放入 bean Map5 呼叫的時候 將代理物件 轉換成需要的物件

2 使用

Step 1: 定義被代理的實體類

public
class Test { public void doSomeThing() { System.out.println("do some thing..."); } public void doWtihNotProxy() { System.out.println("do some thing with not proxy"); } }

Step 2: 定義切點和切面, 並且繼承 AbsMethodAdvance

package org.aop.demo;

import org.aop.annotion.aspect.Aspect;
import
org.aop.annotion.aspect.PointCut; import org.aop.proxy.AbsMethodAdvance; /** * @Author: huangwenjun * @Description: * @Date: Created in 15:53 2018/4/18 **/ @Aspect public class TestAspect extends AbsMethodAdvance { /** * 全類名_方法名 (被攔截的類_被攔截的方法) */ @PointCut("org.aop.demo.Test_doSomeThing") public void testAspect() { } @Override public void doBefore() { System.out.println("do before"); } @Override public void doAfter() { System.out.println("do after"); } }

Step 3: 測試

    public static void main(String[] args) {
        // 模擬容器初始化
        ApplicationContext applicationContext = new ApplicationContext();
        ConcurrentHashMap<String, Object> proxyBeanMap = ApplicationContext.proxyBeanMap;

        // 生成的代理物件 預設為該類名的小寫
        Test test = (Test) proxyBeanMap.get("test");
        test.doSomeThing();

        System.out.println("-------------");

        test.doWtihNotProxy();
    }

輸出:

do before
do some thing...
do after
-------------
do some thing with not proxy

3 核心程式碼

3.1 ApplicationContext

public class ApplicationContext {

    /**
     * 存放代理類的集合
     */
    public static ConcurrentHashMap<String, Object> proxyBeanMap = new ConcurrentHashMap<String, Object>();

    static {
        initAopBeanMap("org.aop.demo");
    }

    /**
     * 初始化 aop 容器
     */
    public static void initAopBeanMap(String basePath) {
        try {
            Set<Class<?>> classSet = ClassUtil.getClassSet(basePath);

            for (Class clazz : classSet) {
                if (clazz.isAnnotationPresent(Aspect.class)) {
                    //找到切面
                    Method[] methods = clazz.getMethods();

                    for(Method method : methods) {

                        if (method.isAnnotationPresent(PointCut.class)) {
                            // 找到切點
                            PointCut pointCut = (PointCut) method.getAnnotations()[0];
                            String pointCutStr = pointCut.value();
                            String[] pointCutArr = pointCutStr.split("_");

                            // 被代理的類名
                            String className = pointCutArr[0];
                            // 被代理的方法名
                            String methodName = pointCutArr[1];

                            // 根據切點 建立被代理物件
                            Object targetObj = ReflectionUtil.newInstance(className);
                            // 根據切面類建立代理者
                            AbsMethodAdvance proxyer = (AbsMethodAdvance) ReflectionUtil.newInstance(clazz);
                            // 設定代理的方法
                            proxyer.setProxyMethodName(methodName);

                            Object object = proxyer.createProxyObject(targetObj);

                            if (object != null) {
                                proxyBeanMap.put(targetObj.getClass().getSimpleName().toLowerCase(), object);
                            }
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

3.2 AbsMethodAdvance

public abstract class AbsMethodAdvance implements MethodInterceptor {

    /**
     * 要被代理的目標物件
     */
    private Object targetObject;

    /**
     * 被代理的方法名
     */
    private String proxyMethodName;

    /**
     * 根據被代理物件 建立代理物件
     * @param target
     * @return
     */
    public Object createProxyObject(Object target) {
        this.targetObject = target;
        // 該類用於生成代理物件
        Enhancer enhancer = new Enhancer();
        // 設定目標類為代理物件的父類
        enhancer.setSuperclass(this.targetObject.getClass());
        // 設定回撥用物件為本身
        enhancer.setCallback(this);

        return enhancer.create();
    }

    @Override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        Object result;

        String proxyMethod = getProxyMethodName();

        if (StringUtils.isNotBlank(proxyMethod) && proxyMethod.equals(method.getName())) {
            doBefore();
        }

        // 執行攔截的方法
        result = methodProxy.invokeSuper(proxy, args);

        if (StringUtils.isNotBlank(proxyMethod) && proxyMethod.equals(method.getName())) {
            doAfter();
        }

        return result;
    }

    public abstract void doBefore();

    public abstract void doAfter();

    public String getProxyMethodName() {
        return proxyMethodName;
    }

    public void setProxyMethodName(String proxyMethodName) {
        this.proxyMethodName = proxyMethodName;
    }
}

4 完整程式碼

GitHub

https://github.com/junjun888/Simple_Aop