AOP原理與自實現

AOP是一種面向切面編程的技術,要實現AOP就不得不提到Proxy模式,具體代理模式的例子能夠參考 設計模式整理 java

因爲代理模式都必須有一個統一的接口,咱們先來寫一個接口spring

public interface Greeting {
    void sayHello(String name);
}

還有一個實現類,是實現了它的主要功能。編程

public class GreetingImpl implements Greeting {
    public void sayHello(String name) {
        System.out.println("Hello! " + name);
    }
}

再寫一個代理類來代理它(在設計模式的例子中,咱們是在須要的時候,乾重活的時候才建立實現類的實例,此處爲直接建立)設計模式

public class GreetingProxy implements Greeting {
    //代理類對實現類的委託
    private GreetingImpl greetingImpl;

    public GreetingProxy(GreetingImpl greetingImpl) {
        this.greetingImpl = greetingImpl;
    }

    public void sayHello(String name) {
        befor();
        greetingImpl.sayHello(name);
        after();
    }
    private void befor() {
        System.out.println("Before");
    }
    private void after() {
        System.out.println("after");
    }
}

經過main方法對它具體調用數組

public class Client {
    public static void main(String[] args) {
        Greeting greetingProxy = new GreetingProxy(new GreetingImpl());
        greetingProxy.sayHello("Jack");
    }
}

運行結果安全

Before
Hello! Jack
afterapp

這樣咱們就對這一個實現類進行了環繞,但若是這樣的實現類很是多怎麼辦呢?這個時候咱們就須要用到動態代理了。異步

public class DynamicProxy<T> implements InvocationHandler {
    private Object target;

    public DynamicProxy(Object target) {
        this.target = target;
    }
    //獲取目標對象的代理類實例
    public T getProxy() {
        return (T) Proxy.newProxyInstance(
                target.getClass().getClassLoader(),  //目標對象類的加載器
                target.getClass().getInterfaces(),  //目標對象類的接口數組(由於一個類可能有幾個接口)
                this
        );
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        before();
        Object result = method.invoke(target,args);
        after();
        return result;
    }
    private void before() {
        System.out.println("Before");
    }
    private void after() {
        System.out.println("After");
    }
}

main方法ide

public class Client {
    public static void main(String[] args) {
        Greeting greetingProxy = new DynamicProxy<Greeting>(new GreetingImpl()).getProxy();
        greetingProxy.sayHello("Jack");
    }
}

運行結果與以前的代理模式相同測試

Before
Hello! Jack
After

動態代理是經過反射來實現的,這裏有一個Proxy.newProxyInstance,咱們來看一下它的源代碼(帶註釋)

//代理類的構造器的參數類型數組
private static final Class<?>[] constructorParams =
    { InvocationHandler.class };
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
                                      Class<?>[] interfaces,
                                      InvocationHandler h)
    throws IllegalArgumentException
{
    //要求動態代理類自己不爲空,若是爲空會拋出異常
    Objects.requireNonNull(h);
    //將接口數組克隆出來
    final Class<?>[] intfs = interfaces.clone();
    //啓動Java安全管理器
    final SecurityManager sm = System.getSecurityManager();
    if (sm != null) {
        //檢查調用類是否有啓動接口的Class實例的加載器的權限
        checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
    }

    /*
     * Look up or generate the designated proxy class.
     * 建立代理類的Class實例
     */
    Class<?> cl = getProxyClass0(loader, intfs);

    /*
     * Invoke its constructor with the designated invocation handler.
     */
    try {
        if (sm != null) {
            //檢查調用類是否有該代理類的權限
            checkNewProxyPermission(Reflection.getCallerClass(), cl);
        }
        //經過構造參數類型來獲取代理類的具體某一個構造器
        final Constructor<?> cons = cl.getConstructor(constructorParams);
        //代理類自己實例
        final InvocationHandler ih = h;
        //獲取代理類Class實例的全部修飾符,並判斷是否爲public,若是不爲public則經過cons.setAccessible(true)設置爲能夠訪問
        if (!Modifier.isPublic(cl.getModifiers())) {
            AccessController.doPrivileged(new PrivilegedAction<Void>() {
                public Void run() {
                    cons.setAccessible(true);
                    return null;
                }
            });
        }
        //經過該具體的構造器來構造代理類自己的實例,以前咱們有說過Class的newInstance只能經過無參構造器來構造,但此處是選擇了具體的有參構造器構造
        return cons.newInstance(new Object[]{h});
    } catch (IllegalAccessException|InstantiationException e) {
        throw new InternalError(e.toString(), e);
    } catch (InvocationTargetException e) {
        Throwable t = e.getCause();
        if (t instanceof RuntimeException) {
            throw (RuntimeException) t;
        } else {
            throw new InternalError(t.toString(), t);
        }
    } catch (NoSuchMethodException e) {
        throw new InternalError(e.toString(), e);
    }
}

由以上代碼可知,該動態代理必需要有接口才能代理,而不能代理沒有接口的類。

沒有接口的類,咱們能夠使用CGLib來動態代理

要使用CGLib,先要在pom中加入它的引用

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>2.2.2</version>
</dependency>
public class CGLibDynamicProxy<T> implements MethodInterceptor {
    private static CGLibDynamicProxy instance = new CGLibDynamicProxy();

    private CGLibDynamicProxy() {

    }

    /**
     * 經過單例模式獲取代理類的實例
     * @return
     */
    public static CGLibDynamicProxy getInstance() {
        return instance;
    }

    /**
     * 經過實現類的Class實例跟代理類對象關聯
     * @param cls
     * @return
     */
    public T getProxy(Class<T> cls) {
        return (T)Enhancer.create(cls,this);
    }
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        before();
        Object result = methodProxy.invokeSuper(o,objects);
        after();
        return result;
    }
    private void before() {
        System.out.println("Before");
    }
    private void after() {
        System.out.println("After");
    }
}

main方法

public class Client {
    public static void main(String[] args) {
        Greeting greetingProxy = (Greeting) CGLibDynamicProxy.getInstance().getProxy(GreetingImpl.class);
        greetingProxy.sayHello("Jack");
    }
}

運行結果與以前同樣,咱們來簡單看一下Enhancer.create的源碼

public static Object create(Class type, Callback callback) {
    Enhancer e = new Enhancer();  //建立一個加強代理類對象,它能夠攔截被代理的除final,static之外的全部類
    e.setSuperclass(type);  //設置該代理類的父類爲實現類
    e.setCallback(callback);  //設置實現了MethodInterceptor接口的回調類,這裏即爲咱們動態代理類自己的實例,由於MethodInterceptor是繼承於Callback的接口,它是一個
                              //對象方法攔截器
    return e.create();       //返回實現類的加強類(所謂加強便可以對這個類進行攔截和各類處理操做)
}

瞭解了動態代理以後,咱們來了解一下Spring+AspectJ的AOP。咱們主要結合攔截指定註解(@annotation)的方式來大概說明一下用法。

好比說咱們要攔截一個自定義的標籤,對標有該標籤的方法,記錄日誌,經過MQ(具體不限定哪一種MQ)發送到日誌中心,進行存儲。

首先咱們有一個日誌的實體類

@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Log implements Serializable {

   private static final long serialVersionUID = -5398795297842978376L;

   private Long id;
   private String username;
   /** 模塊 */
   private String module;
   /** 參數值 */
   private String params;
   private String remark;
   private Boolean flag;
   private Date createTime;
   private String ip;
   private String area;
}

有一個自定義的標籤,這是一個方法級標籤

/**
 * 日誌註解
 *
 */
@Target({ ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface LogAnnotation {

   String module();

   /**
    * 記錄參數<br>
    * 儘可能記錄普通參數類型的方法,和能序列化的對象
    * 
    * @return
    */
   boolean recordParam() default true;
}

增長日誌所屬的模塊(用戶操做)

/**
 * 日誌模塊定義
 *
 */
public abstract class LogModule {

    public static final Map<String, String> MODULES = new HashMap<>();

    public static final String LOGIN = "LOGIN";
    public static final String LOGOUT = "LOGOUT";

    public static final String ADD_PERMISSION = "ADD_PERMISSION";
    public static final String UPDATE_PERMISSION = "UPDATE_PERMISSION";
    public static final String DELETE_PERMISSION = "DELETE_PERMISSION";

    public static final String ADD_ROLE = "ADD_ROLE";
    public static final String UPDATE_ROLE = "UPDATE_ROLE";
    public static final String DELETE_ROLE = "DELETE_ROLE";
    public static final String SET_PERMISSION = "SET_PERMISSION";

    public static final String SET_ROLE = "SET_ROLE";
    public static final String UPDATE_USER = "UPDATE_USER";
    public static final String UPDATE_ME = "UPDATE_ME";

    public static final String UPDATE_PASSWORD = "UPDATE_PASSWORD";
    public static final String RESET_PASSWORD = "RESET_PASSWORD";

    public static final String ADD_MENU = "ADD_MENU";
    public static final String UPDATE_MENU = "UPDATE_MENU";
    public static final String DELETE_MENU = "DELETE_MENU";
    public static final String SET_MENU_ROLE = "SET_MENU_ROLE";

    public static final String ADD_BLACK_IP = "ADD_BLACK_IP";
    public static final String DELETE_BLACK_IP = "DELETE_BLACK_IP";

    public static final String FILE_UPLOAD = "FILE_UPLOAD";
    public static final String FILE_DELETE = "FILE_DELETE";

    public static final String ADD_MAIL = "ADD_MAIL";
    public static final String UPDATE_MAIL = "UPDATE_MAIL";
    public static final String DELETE_USER = "DELETE_USER";

    static {
        MODULES.put(LOGIN, "登錄");
        MODULES.put(LOGOUT, "退出");

        MODULES.put(ADD_PERMISSION, "添加權限");
        MODULES.put(UPDATE_PERMISSION, "修改權限");
        MODULES.put(DELETE_PERMISSION, "刪除權限");

        MODULES.put(ADD_ROLE, "添加角色");
        MODULES.put(UPDATE_ROLE, "修改角色");
        MODULES.put(DELETE_ROLE, "刪除角色");
        MODULES.put(SET_PERMISSION, "分配權限");
        MODULES.put(SET_ROLE, "分配角色");

        MODULES.put(UPDATE_USER, "修改用戶");
        MODULES.put(UPDATE_ME, "修改我的信息");
        MODULES.put(UPDATE_PASSWORD, "修改密碼");
        MODULES.put(RESET_PASSWORD, "重置密碼");

        MODULES.put(ADD_MENU, "添加菜單");
        MODULES.put(UPDATE_MENU, "修改菜單");
        MODULES.put(DELETE_MENU, "刪除菜單");
        MODULES.put(SET_MENU_ROLE, "分配菜單");

        MODULES.put(ADD_BLACK_IP, "添加黑名單");
        MODULES.put(DELETE_BLACK_IP, "刪除黑名單");

        MODULES.put(FILE_UPLOAD, "文件上傳");
        MODULES.put(FILE_DELETE, "文件刪除");

        MODULES.put(ADD_MAIL, "保存郵件");
        MODULES.put(UPDATE_MAIL, "修改郵件");
        MODULES.put(DELETE_USER, "刪除用戶");

    }

}

而後咱們定義一個AOP的實現類

@Aspect
public class LogAop {

    private static final Logger logger = LoggerFactory.getLogger(LogAop.class);
    //對@LogAnnotation標籤進行環繞加強
    @Around(value = "@annotation(com.cloud.model.log.LogAnnotation)")
    public Object logSave(ProceedingJoinPoint joinPoint) throws Throwable { //ProceedingJoinPoint joinPoint鏈接點,能夠經過該對象獲取方法的任務信息,例如,方
        Log log = new Log();                                                //法名,參數等。
        log.setCreateTime(new Date());
        LoginAppUser loginAppUser = AppUserUtil.getLoginAppUser();
        if (loginAppUser != null) {
            log.setUsername(loginAppUser.getUsername());
        }
        //經過鏈接點獲取方法簽名
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        //經過方法的簽名獲取方法的標籤
        LogAnnotation logAnnotation = methodSignature.getMethod().getDeclaredAnnotation(LogAnnotation.class);
        log.setModule(logAnnotation.module());
        //咱們是否要收集方法的參數,默認爲true
        if (logAnnotation.recordParam()) {
            String[] paramNames = methodSignature.getParameterNames();// 獲取方法參數名
            if (paramNames != null && paramNames.length > 0) {
                Object[] args = joinPoint.getArgs();// 經過鏈接點獲取傳入參數值
                //定義一個HashMap,並將對應的參數名和參數值所有放入該HashMap
                Map<String, Object> params = new HashMap<>();
                for (int i = 0; i < paramNames.length; i++) {
                    params.put(paramNames[i], args[i]);
                }

                try {
                    log.setParams(JSONObject.toJSONString(params)); //Json序列化對應參數信息放入log對象中
                } catch (Exception e) {
                    logger.error("記錄參數失敗:{}", e.getMessage());
                }
            }
        }

        try {
            Object object = joinPoint.proceed();// 執行原方法
            //執行成功處理
            log.setFlag(Boolean.TRUE);

            return object;
        } catch (Exception e) {
            //執行失敗處理
            log.setFlag(Boolean.FALSE);
            log.setRemark(e.getMessage());
            throw e;
        } finally {
            // 異步將Log對象發送到隊列
            CompletableFuture.runAsync(() -> {
                try {
                    /////////此處能夠將日誌對象log發送到消息隊列,因爲在一些系統中,一些用戶的操做大量且頻繁,推薦使用Kafka來做爲推送日誌的消息隊列,好比
                    /////////商品購買,退貨等等,在LogModule中添加對應的操做標誌。
                    logger.info("發送日誌到隊列:{}", log);
                } catch (Exception e2) {
                    e2.printStackTrace();
                }
            });

        }

    }
}

由於@Aspect標籤是未被Spring託管的,因此要對LogAop實行自動配置,在資源文件夾下的spring.factories中

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.cloud.log.autoconfigure.LogAop

有多條以, \分隔成多行。在一些本身開發的jar包導入新的Spring boot工程中,此種方法是最爲有效的依賴注入方式。

好比在用戶模塊要修改我的信息的時候

/**
 * 修改本身的我的信息
 *
 * @param appUser
 * @return
 */
@LogAnnotation(module = LogModule.UPDATE_ME)
@PutMapping("/users/me")
public Map<String, Object> updateMe(@RequestBody AppUser appUser) {
    AppUser user = AppUserUtil.getLoginAppUser();
    appUser.setId(user.getId());

    appUserService.updateAppUser(appUser);

    return ResponseUtils.getDataResult(user);
}

這個updateMe方法就會被AOP環繞加強,將操做的信息,傳遞參數放入log對象,並經過MQ發送到日誌中心進行接收。其實這裏面接入點的具體實現也是經過反射來處理的。而AOP的整個實現也是經過動態代理來實現的。固然不要忘了在本模塊內的配置文件中增長

spring:
  aop:  
    proxy-target-class: true

它的默認值是false,默認只能代理接口(使用JDK動態代理),當爲true時,才能代理目標類(使用CGLib動態代理)。

如今咱們就來本身實現一套AOP.代碼延續於 @Compenent,@Autowired,@PostConstruct自實現

package com.guanjian.annotion;

import java.lang.annotation.*;

/**
 * 切面註解
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Aspect {
    //要攔截標籤的類實例
    Class<? extends Annotation> value();
}
package com.guanjian.proxy;

/**
 * 代理接口
 */
public interface Proxy {
    /**
     * 執行鏈式代理
     * @param proxyChain
     * @return
     * @throws Throwable
     */
    Object doProxy(ProxyChain proxyChain) throws Throwable;
}
package com.guanjian.proxy;

import net.sf.cglib.proxy.MethodProxy;

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

/**
 * 代理鏈
 */
public class ProxyChain {
    //目標Class實例
    private final Class<?> targetClass;
    //目標對象
    private final Object targetObject;
    //目標方法
    private final Method targetMethod;
    //方法代理
    private final MethodProxy methodProxy;
    //方法參數
    private final Object[] methodParams;
    //代理列表,由於同一個目標對象實例可能會有多個AOP的攔截,須要多個代理類實例
    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;
    }

    /**
     * 雙向調用的遞歸,逐個代理對象先把全部的before方法執行一遍,執行到列表中沒有代理對象時執行被代理的對象的本方法
     * 再逐個代理對象把全部的after方法執行一遍
     * @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;
    }
}
package com.guanjian.proxy;

import java.lang.reflect.Method;

/**
 * 切面代理
 */
public abstract class AspectProxy implements Proxy {

    @Override
    public Object doProxy(ProxyChain proxyChain) throws Throwable {
        Object result = null;
        Class<?> cls = proxyChain.getTargetClass();
        Method method = proxyChain.getTargetMethod();
        Object[] params = proxyChain.getMethodParams();

        begin();
        try {
            if (intercept(cls,method,params)) {
                before(cls,method,params);
                //跟代理鏈雙向遞歸
                result = proxyChain.doProxyChain();
                after(cls,method,params,result);
            }else {
                result = proxyChain.doProxyChain();
            }
        } catch (Exception e) {
            System.out.println("proxy failure" + e);
            error(cls,method,params,e);
            throw e;
        } finally {
            end();
        }
        return result;
    }

    public void begin() {
    }

    public boolean intercept(Class<?> cls,Method method,Object[] params) throws Throwable {
        return true;
    }
    public void before(Class<?> cls,Method method,Object[] params) throws Throwable {
    }
    public void after(Class<?> cls,Method method,Object[] params,Object result) throws Throwable {
    }
    public void error(Class<?> cls,Method method,Object[] params,Throwable e) {
    }
    public void end() {
    }
}
package com.guanjian.proxy;

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;

/**
 * 代理管理器,真正實現對實際的目標類實例進行攔截,並初始化調用鏈,執行對代理對象進行
 * 雙向遞歸調用
 */
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).doProxyChain();
            }
        });
    }
}

動態代理的類就是這些了,而後是跟整個IOC進行整合

在BeanHelper中增長

/**
 * 設置Bean實例
 * @param cls
 * @param object
 */
public static void setBean(Class<?> cls,Object object) {
    BEAN_MAP.put(cls,object);
}

在ClassHelper中增長

/**
 * 在掃描的類集合中獲取指定父類(或接口)的子類(或實現類)
 * @param superClass
 * @return
 */
public static Set<Class<?>> getClassSetBySuper(Class<?> superClass) {
    Set<Class<?>> classSet = new HashSet<>();
    for (Class<?> cls:CLASS_SET) {
        if (superClass.isAssignableFrom(cls) && !superClass.equals(cls)) {
            classSet.add(cls);
        }
    }
    return classSet;
}

/**
 * 在掃描的類集合中獲取有標記指定的標籤類的全部類
 * @param annotationClass
 * @return
 */
public static Set<Class<?>> getClassSetByAnnotation(Class<? extends Annotation> annotationClass) {
    Set<Class<?>> classSet = new HashSet<>();
    for (Class<?> cls:CLASS_SET) {
        if (cls.isAnnotationPresent(annotationClass)) {
            classSet.add(cls);
        }
    }
    return classSet;
}

而後寫一個方法攔截助手類

package com.guanjian.util;

import com.guanjian.annotion.Aspect;
import com.guanjian.proxy.AspectProxy;
import com.guanjian.proxy.Proxy;
import com.guanjian.proxy.ProxyManager;

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

/**
 * 方法攔截助手類
 */
public final class AopHelper {

    static {
        try {
            //AOP攔截與標記了該AOP攔截的全部類集合的map映射
            Map<Class<?>,Set<Class<?>>> proxyMap = createProxyMap();
            //目標類與代理類實例集合的map映射
            Map<Class<?>,List<Proxy>> targetMap = createTargetMap(proxyMap);
            //遍歷目標類與代理類實例集合的map
            for (Map.Entry<Class<?>,List<Proxy>> targetEntry:targetMap.entrySet()) {
                //取出目標類
                Class<?> targetClass = targetEntry.getKey();
                //取出代理類集合列表
                List<Proxy> proxyList = targetEntry.getValue();
                //使用代理管理器對目標類進行攔截,並開始執行代理類集合列表的全部加強方法以及目標類的本方法
                Object proxy = ProxyManager.createProxy(targetClass,proxyList);
                //將目標類與代理對象添加進全局映射關係
                BeanHelper.setBean(targetClass,proxy);
            }
            System.out.println("aop Class loaded");
        } catch (Exception e) {
            System.out.println("aop failure" + e);
        }

    }

    /**
     * 建立全部的AOP類與與之對應的目標類集合的映射
     * @return
     * @throws Exception
     */
    private static Map<Class<?>,Set<Class<?>>> createProxyMap() throws Exception {
        Map<Class<?>,Set<Class<?>>> proxyMap = new HashMap<>();
        //獲取切面代理類(抽象類)的全部實現類(子類)
        Set<Class<?>> proxyClassSet = ClassHelper.getClassSetBySuper(AspectProxy.class);
        for (Class<?> proxyClass:proxyClassSet) {
            //實現類是否有@Aspect標籤
            if (proxyClass.isAnnotationPresent(Aspect.class)) {
                //獲取該標籤
                Aspect aspect = proxyClass.getAnnotation(Aspect.class);
                //獲取全部目標類集合
                Set<Class<?>> targetClassSet = createTargetClassSet(aspect);
                //將代理類實例與該集合添加map映射
                proxyMap.put(proxyClass,targetClassSet);
            }
        }
        return proxyMap;
    }

    /**
     * 建立目標類集合
     * @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)) {
            //將掃描到的全部標記了該標籤的全部類實例添加到集合中
            targetClassSet.addAll(ClassHelper.getClassSetByAnnotation(annotation));
        }
        return targetClassSet;
    }

    /**
     * 建立目標類與代理類集合的map映射
     * @param proxyMap
     * @return
     * @throws Exception
     */
    private static Map<Class<?>,List<Proxy>> createTargetMap(Map<Class<?>,Set<Class<?>>> proxyMap) throws Exception {
        //目標類與它全部代理集合的映射map
        Map<Class<?>,List<Proxy>> targetMap = new HashMap<>();
        //遍歷全部的AOP攔截與標記了該AOP攔截的全部類集合的map
        for (Map.Entry<Class<?>,Set<Class<?>>> proxyEntry:proxyMap.entrySet()) {
            //取出AOP攔截類
            Class<?> proxyClass = proxyEntry.getKey();
            //取出標記了該攔截類的目標類集合
            Set<Class<?>> targetClassSet = proxyEntry.getValue();
            //遍歷全部的目標類
            for (Class<?> targetClass:targetClassSet) {
                //實例化該AOP攔截類
                Proxy proxy = (Proxy)proxyClass.newInstance();
                //若是map中有該目標類
                if (targetMap.containsKey(targetClass)) {
                    //添加攔截類實例進列表
                    targetMap.get(targetClass).add(proxy);
                }else {
                    //若是沒有,建立代理類實例列表
                    List<Proxy> proxyList = new ArrayList<>();
                    //將該代理類實例添加進列表
                    proxyList.add(proxy);
                    //建立新的目標類與該列表的映射
                    targetMap.put(targetClass,proxyList);
                }
            }
        }
        return targetMap;
     }
}

注意以上代碼都是針對整個目標類的全部方法進行攔截的,若是有須要能夠改寫對個別方法的攔截

此時咱們就能夠寫測試代碼了

測試標籤類,由於是針對整個目標類的,因此是@Target(ElementType.TYPE)

package com.guanjian.annotion;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * Created by Administrator on 2019-03-15.
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnotationTest {
}

編寫一個AOP實現類,打印方法執行時間,該類必須放在掃描包中進行掃描。

package com.guanjian.test.aop;

import com.guanjian.annotion.AnnotationTest;
import com.guanjian.annotion.Aspect;
import com.guanjian.proxy.AspectProxy;

import java.lang.reflect.Method;


/**
 * Created by Administrator on 2019-03-15.
 */

@Aspect(AnnotationTest.class)
public class AopTest extends AspectProxy{
    private long begin;
    @Override
    public void before(Class<?> cls, Method method, Object[] params) throws Throwable {
        begin = System.currentTimeMillis();
    }

    @Override
    public void after(Class<?> cls, Method method, Object[] params, Object result) throws Throwable {
        System.out.println("time: " + (System.currentTimeMillis() - begin));
    }
}
package com.guanjian.test.compent;

import com.guanjian.annotion.AnnotationTest;

/**
 * Created by Administrator on 2019-03-16.
 */

@AnnotationTest
public class Test3 {
    public void show() {
        System.out.println("你好,你好");
    }
}

注意,這些都是沒有加以前的@Component標籤的,由於這裏不是Spring,因此它們都會被掃描到並被代理類實例加強執行。

最後是main方法

public class Test {
    public static void main(String[] args) {
        //掃描包
        Manager.scanAndImp("com.guanjian.test");
        //初始化AopHelper
        ClassUtil.loadClass(AopHelper.class.getName(),true);
        //這裏其實拿到的是代理類的實例,代理類是目標類的子類
        Test3 test3 = (Test3)Manager.getBean(Test3.class);
        test3.show();
    }
}

運行結果:

aop Class loaded 你好,你好 time: 11

相關文章
相關標籤/搜索