為了賬號安全,請及時綁定郵箱和手機立即綁定

第三篇:從Java基礎談Spring AOP--動態代理原理分析AOP技術

2016.08.02 12:22 4339瀏覽

首先讀者務必要理解第二篇的內容(鏈接描述),否則你很難理解這篇文章。
讓我們再做一個動態代理的例子,你就馬上能夠能夠理解AOP是個啥東西。好讓我們開始定義一個Javabean,它十分簡單,也不需要我多做解釋:

package com.learn.chapter1.aop;

/**
 *
 * @author ykzhen2015
 */
public class ConfigBean {

    private boolean flag = false;//標記代理對象是否使用這個類進行處理.
    private boolean useAround = false;//是否啟用環繞通知

    public void before() {
        System.err.println("前置消息");
    }

    public void after() {
        System.err.println("后置消息");
    }

    public void afterReturn() {
        System.err.println("正常返回后的消息");
    }

    public void afterThrowing() {
        System.err.println("返回后的消息");
    }

    public Object around() {
        System.err.println("環繞通知");
        return null;
    }

    public boolean isFlag() {
        return flag;
    }

    public void setFlag(boolean flag) {
        this.flag = flag;
    }

    public boolean isUseAround() {
        return useAround;
    }

    public void setUseAround(boolean useAround) {
        this.useAround = useAround;
    }
}

細心的讀者就看到了,正是我們AOP看到的前置消息,后置消息,環繞消息,正常返回后的消息,異常返回消息。外加一個flag標記,它的作用就等同于一個切點,至于什么叫切點,這里放放,不用管它,我們就知道它是個boolean值,是個開關就成了,而useAround意思是是否啟用環繞通知,也是一個開關。
跟著就是上篇,你們熟悉的兩個類,一個十分簡單的接口和實現類:

package com.learn.chapter1.aop;

/**
 *  @author ykzhen2015
 */
public interface HelloService {

    public void sayHello(String name);
}

實現類:

package com.learn.chapter1.aop;

/**
 *
 * @author ykzhen2015
 */
public class HelloServiceImpl implements HelloService {

    @Override
    public void sayHello(String name) {
        System.err.println("hello " + name);
    }
}

實現類也很簡單,跟著我們改寫一些我們上篇談到的代理類,還是兩個步驟:

  • 綁定HelloServiceImpl生成代理類
  • 實現代理方法
    代碼如下:
package com.learn.chapter1.aop;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * * * @author ykzhen2015.
 */
public class HelloProxy implements InvocationHandler {

    private ConfigBean configBean = null;

    private Object target;

    /**
     * * 生成代理對象,并和真實服務對象綁定. * @param target 真實服務對線下 * @return 代理對象
     */
    public Object bind(Object target) {
        this.target = target; //生成代理對象,并綁定. 
        Object proxy = Proxy.newProxyInstance(target.getClass().getClassLoader(), //類的加載器 
                target.getClass().getInterfaces(), //對象的接口,明確代理對象掛在哪些接口下 
                this);//指明代理類,this代表用當前類對象,那么就要求其實現InvocationHandler接口 
        return proxy;
    }

    /**
     * * 當生成代理對象時,第三個指定使用HelloProxy進行代理時,代理對象調用的方法就會進入這個方法。
     *
     * @param proxy ——代理對象
     * @param method -- 被調用的方法
     * @param args -- 方法參數
     * @return 代理方法返回。
     * * @throws Throwable -- 異常處理
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        ConfigBean config = this.getConfigBean();
        if (!config.isFlag()) {//切點
            return method.invoke(target, args);
        }
        config.before();//前置消息
        Object obj = null;
        try {
             if (config.isUseAround()) {
                 obj = config.around();//環繞通知
             } else {
                 obj = method.invoke(target, args);//相當于sayHello方法調用.
             }
        } catch(Exception ex) {
            config.afterThrowing();//返回異常消息
        }
        config.after();//后置通知
        return obj;
    }

    public ConfigBean getConfigBean() {
        return configBean;
    }

    public void setConfigBean(ConfigBean configBean) {
        this.configBean = configBean;
    }
}

好了,這個bind方法我們上篇論述過了,我們關注的是Invoke方法。
1、首先獲取一個ConfigBean,(如果是Spring就是攔截器)
2、其次判斷是否啟用一個ConfigBean進行處理(Spring切點判斷,它一般用正則式,大同小異),如果不用則直接反射真實對象HelloService的sayHello方法,完成任務,如果用,則走第3步
3、啟動前置通知before(Spring也是一樣)
4、進入try ... catch...,如果環繞通知標志為true(spring是判斷有沒有環繞通知),則執行環繞通知;否則就反射被代理對象的方法。(Spring也是一樣)
5、反射后,可能發生異常或者不發生,不發生就進入afterReturn方法,正常返回通知;發生異常就進入afterThrowing方法,異常返回通知。(Spring也是一樣)
6、最后執行后置通知after方法,完成整個AOP的過程。(Spring也是一樣)

好了,上面就大概是Spring執行各類通知的過程,怎么樣在動態代理的分析是不是比教科書的還要清晰?
最后我們測試一下這段代碼:

package com.learn.chapter1.aop;

/**
 *
 * @author ykzhen2015
 */
public class AopMain {
    public static void main(String[] args) {
        HelloProxy helloProxy = new HelloProxy();
        HelloService helloService = (HelloService) helloProxy.bind(new HelloServiceImpl());
        ConfigBean config = new ConfigBean();
        config.setFlag(true);
        config.setUseAround(true);
        helloProxy.setConfigBean(config);
        helloService.sayHello("張三");
    }
}

好看看執行結果:

前置消息
環繞通知
后置消息

在Spring的AOP中你拿到的就類似于這里的代理對象——proxy,進行了動態代理。好了這里分析了,切點,各類消息它們執行的過程,下一篇我們會更深入的討論AOP的原理,不過到這里你已經基本掌握了AOP的整個過程。

點擊查看更多內容

本文原創發布于慕課網 ,轉載請注明出處,謝謝合作

29人點贊

若覺得本文不錯,就分享一下吧!

評論

相關文章推薦

正在加載中
意見反饋 幫助中心 APP下載
官方微信

舉報

0/150
提交
取消
lpl竞猜