国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

從零開(kāi)始實(shí)現(xiàn)一個(gè)簡(jiǎn)易的Java MVC框架(六)--加強(qiáng)AOP功能

Loong_T / 2752人閱讀

摘要:在前面的文章中實(shí)現(xiàn)的功能時(shí),目標(biāo)類都只能被一個(gè)切面代理,如果想要生成第二個(gè)代理類,就會(huì)把之前的代理類覆蓋。改裝原有功能現(xiàn)在要改裝原來(lái)的的實(shí)現(xiàn)代碼,讓的功能加入到框架中為了讓切面能夠排序,先添加一個(gè)注解,用于標(biāo)記排序。

前言

在前面從零開(kāi)始實(shí)現(xiàn)一個(gè)簡(jiǎn)易的Java MVC框架(四)--實(shí)現(xiàn)AOP和從零開(kāi)始實(shí)現(xiàn)一個(gè)簡(jiǎn)易的Java MVC框架(五)--引入aspectj實(shí)現(xiàn)AOP切點(diǎn)這兩節(jié)文章中已經(jīng)實(shí)現(xiàn)了AOP功能并且引用aspectj表達(dá)式實(shí)現(xiàn)切點(diǎn)的功能,這篇文章繼續(xù)完善doodle框架的AOP功能。

在前面的文章中實(shí)現(xiàn)的AOP功能時(shí),目標(biāo)類都只能被一個(gè)切面代理,如果想要生成第二個(gè)代理類,就會(huì)把之前的代理類覆蓋。這篇文章就要來(lái)實(shí)現(xiàn)多個(gè)代理的功能,也就是實(shí)現(xiàn)代理鏈。

實(shí)現(xiàn)代理鏈

在com.zbw.aop包下創(chuàng)建一個(gè)類起名為AdviceChain

package com.zbw.aop;

import ...

/**
 * 通知鏈
 */
public class AdviceChain {

    /**
     * 目標(biāo)類
     */
    @Getter
    private final Class targetClass;
    /**
     * 目標(biāo)實(shí)例
     */
    @Getter
    private final Object target;
    /**
     * 目標(biāo)方法
     */
    @Getter
    private final Method method;
    /**
     * 目標(biāo)方法參數(shù)
     */
    @Getter
    private final Object[] args;
    /**
     * 代理方法
     */
    private final MethodProxy methodProxy;
    /**
     * 代理通知列
     */
    private List proxyList;
    /**
     * 代理通知列index
     */
    private int adviceIndex = 0;

    public AdviceChain(Class targetClass, Object target, Method method, Object[] args, MethodProxy methodProxy, List proxyList) {
        this.targetClass = targetClass;
        this.target = target;
        this.method = method;
        this.args = args;
        this.methodProxy = methodProxy;
        this.proxyList = proxyList;
    }

    /**
     * 遞歸執(zhí)行 執(zhí)行代理通知列
     */
    public Object doAdviceChain() throws Throwable {
        ...
    }
}

由于要實(shí)現(xiàn)多個(gè)通知類鏈?zhǔn)綀?zhí)行的功能,這個(gè)類就是代替之前的ProxyAdvisor來(lái)生產(chǎn)代理類,并且通過(guò)doAdviceChain()方法執(zhí)行具體的切面方法以及目標(biāo)代理類的方法。

在最初設(shè)計(jì)這個(gè)方法的時(shí)候,我想的是直接for循環(huán)proxyList這個(gè)屬性里的ProxyAdvisor,然后一個(gè)個(gè)執(zhí)行對(duì)應(yīng)的Advice方法不就行了,后來(lái)發(fā)現(xiàn)這是不行的。因?yàn)樵贏OP的功能設(shè)計(jì)里,多個(gè)切面的執(zhí)行順序是一種"先入后出"的順序。比如說(shuō)有兩個(gè)切面Aspect1Aspect2,那么他們的執(zhí)行順序應(yīng)該是Aspect1@before()->Aspect2@before()->targetClass@method()->Aspect2@after()->Aspect1@after(),先執(zhí)行的Aspect1@before()方法要在最后執(zhí)行Aspect1@after()。

要實(shí)現(xiàn)"先入后出"的功能通常有兩種實(shí)現(xiàn)方式,一是借助棧這個(gè)數(shù)據(jù)結(jié)構(gòu),二是用遞歸的方式,這里我們用遞歸的方式實(shí)現(xiàn)。

在實(shí)現(xiàn)doAdviceChain()的功能之前,先修改之前的ProxyAdvisor類。

...

public class ProxyAdvisor {

    ...

    /**
     * 執(zhí)行順序
     */
    private int order;

    /**
     * 執(zhí)行代理方法
     */
    public Object doProxy(AdviceChain adviceChain) throws Throwable {
        Object result = null;
        Class targetClass = adviceChain.getTargetClass();
        Method method = adviceChain.getMethod();
        Object[] args = adviceChain.getArgs();

        if (advice instanceof MethodBeforeAdvice) {
            ((MethodBeforeAdvice) advice).before(targetClass, method, args);
        }
        try {
            result = adviceChain.doAdviceChain(); //執(zhí)行代理鏈方法
            if (advice instanceof AfterReturningAdvice) {
                ((AfterReturningAdvice) advice).afterReturning(targetClass, result, method, args);
            }
        } catch (Exception e) {
            if (advice instanceof ThrowsAdvice) {
                ((ThrowsAdvice) advice).afterThrowing(targetClass, method, args, e);
            } else {
                throw new Throwable(e);
            }
        }
        return result;
    }
}

ProxyAdvisor類中添加一個(gè)屬性order,這是用于存儲(chǔ)這個(gè)切面類的執(zhí)行順序的。然后再修改doProxy()方法,把傳入?yún)?shù)由原來(lái)的很多類相關(guān)的信息改為傳入AdviceChain,因?yàn)槲覀儼杨愋畔⒍挤旁诹?b>AdviceChain中了。然后把原來(lái)在doProxy()方法開(kāi)頭的if (!pointcut.matches(method))這個(gè)切點(diǎn)判斷移除,這個(gè)判斷將會(huì)改在AdviceChain中。然后在原來(lái)要調(diào)用proxy.invokeSuper(target, args);的地方改為調(diào)用adviceChain.doAdviceChain();,這樣就能形成一個(gè)遞歸調(diào)用。

現(xiàn)在來(lái)具體實(shí)現(xiàn)AdviceChaindoAdviceChain()方法。

...

public Object doAdviceChain() throws Throwable {
    Object result;
    while (adviceIndex < proxyList.size()
           && !proxyList.get(adviceIndex).getPointcut().matches(method)) {
        //如果當(dāng)前方法不匹配切點(diǎn),則略過(guò)該代理通知類
        adviceIndex++;
    }
    if (adviceIndex < proxyList.size()) {
        result = proxyList.get(adviceIndex++).doProxy(this);
    } else {
        result = methodProxy.invokeSuper(target, args);
    }
    return result;
}

在這個(gè)方法中,先是通過(guò)一個(gè)while循環(huán)判定proxyList的當(dāng)前ProxyAdvisor是否匹配切點(diǎn)表達(dá)式,如果不匹配日則跳過(guò)這個(gè)ProxyAdvisoradviceIndex這個(gè)計(jì)數(shù)器加一,假如匹配的話,就執(zhí)行ProxyAdvisordoProxy()方法,并且把自己當(dāng)作參數(shù)傳入過(guò)去。直到adviceIndex計(jì)數(shù)器的大小大于等于proxyList的大小,則調(diào)用目標(biāo)類的方法。

這樣就形成一個(gè)遞歸的形式來(lái)實(shí)現(xiàn)代理鏈。

改裝原有AOP功能

現(xiàn)在要改裝原來(lái)的AOP的實(shí)現(xiàn)代碼,讓AdviceChain的功能加入到框架中

為了讓切面能夠排序,先添加一個(gè)Order注解,用于標(biāo)記排序。在zbw.aop包下創(chuàng)建Order注解類

package com.zbw.aop.annotation;

import ...

/**
 * aop順序
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Order {

    /**
     * aop順序,值越大越先執(zhí)行
     */
    int value() default 0;
}

然后再改裝AOP執(zhí)行器,先修改createProxyAdvisor()方法,把Order注解的值存入到ProxyAdvisor中。

// Aop.java
...

/**
 * 通過(guò)Aspect切面類創(chuàng)建代理通知類
 */
private ProxyAdvisor createProxyAdvisor(Class aspectClass) {
    int order = 0;
    if (aspectClass.isAnnotationPresent(Order.class)) {
        order = aspectClass.getAnnotation(Order.class).value();
    }
    String expression = aspectClass.getAnnotation(Aspect.class).pointcut();
    ProxyPointcut proxyPointcut = new ProxyPointcut();
    proxyPointcut.setExpression(expression);
    Advice advice = (Advice) beanContainer.getBean(aspectClass);
    return new ProxyAdvisor(advice, proxyPointcut, order);
}

然后再增加一個(gè)createMatchProxies()方法,由于之前生成代理類都是用一個(gè)ProxyAdvisor就可以了,而現(xiàn)在是一個(gè)List,所以現(xiàn)在要用該方法用于生成一個(gè)List,其中存放的是匹配目標(biāo)類的切面集合。傳入的參數(shù)proxyList為所有的ProxyAdvisor集合,返回的參數(shù)為目標(biāo)類匹配的代理通知集合,并且這個(gè)集合是根據(jù)order排序的。

// Aop.java
...

/**
 * 獲取目標(biāo)類匹配的代理通知列表
 */
private List createMatchProxies(List proxyList, Class targetClass) {
    Object targetBean = beanContainer.getBean(targetClass);
    return proxyList
        .stream()
        .filter(advisor -> advisor.getPointcut().matches(targetBean.getClass()))
        .sorted(Comparator.comparingInt(ProxyAdvisor::getOrder))
        .collect(Collectors.toList());
}

最后再修改doAop()方法。

// Aop.java
...

/**
 * 執(zhí)行Aop
 */
public void doAop() {
    //創(chuàng)建所有的代理通知列表
    List proxyList = beanContainer.getClassesBySuper(Advice.class)
        .stream()
        .filter(clz -> clz.isAnnotationPresent(Aspect.class))
        .map(this::createProxyAdvisor)
        .collect(Collectors.toList());

    //創(chuàng)建代理類并注入到Bean容器中
    beanContainer.getClasses()
        .stream()
        .filter(clz -> !Advice.class.isAssignableFrom(clz))
        .filter(clz -> !clz.isAnnotationPresent(Aspect.class))
        .forEach(clz -> {
            List matchProxies = createMatchProxies(proxyList, clz);
            if (matchProxies.size() > 0) {
                Object proxyBean = ProxyCreator.createProxy(clz, matchProxies);
                beanContainer.addBean(clz, proxyBean);
            }
        });
}

同樣的,由于代理類從ProxyAdvisor改成AdviceChain,對(duì)應(yīng)的代理類創(chuàng)造器也要做對(duì)應(yīng)的修改。

package com.zbw.aop;

import ...

/**
 * 代理類創(chuàng)建器
 */
public final class ProxyCreator {

    /**
     * 創(chuàng)建代理類
     */
    public static Object createProxy(Class targetClass, List proxyList) {
        return Enhancer.create(targetClass, new AdviceMethodInterceptor(targetClass, proxyList));
    }

    /**
     * cglib MethodInterceptor實(shí)現(xiàn)類
     */
    private static class AdviceMethodInterceptor implements MethodInterceptor {

        /**
         * 目標(biāo)類
         */
        private final Class targetClass;

        /**
         * 代理通知列表
         */
        private List proxyList;

        public AdviceMethodInterceptor(Class targetClass, List proxyList) {
            this.targetClass = targetClass;
            this.proxyList = proxyList;
        }

        @Override
        public Object intercept(Object target, Method method, Object[] args, MethodProxy proxy) throws Throwable {
            return new AdviceChain(targetClass, target, method, args, proxy, proxyList).doAdviceChain();
        }
    }
}

代理鏈的功能又實(shí)現(xiàn)了,現(xiàn)在可以寫測(cè)試用例了。

測(cè)試用例

先實(shí)現(xiàn)兩個(gè)切面DoodleAspectDoodleAspect2

// DoodleAspect
@Slf4j
@Order(1)
@Aspect(pointcut = "@within(com.zbw.core.annotation.Controller)")
public class DoodleAspect implements AroundAdvice {

    @Override
    public void before(Class clz, Method method, Object[] args) throws Throwable {
        log.info("-----------before  DoodleAspect-----------");
        log.info("class: {}, method: {}", clz.getName(), method.getName());
    }

    @Override
    public void afterReturning(Class clz, Object returnValue, Method method, Object[] args) throws Throwable {
        log.info("-----------after  DoodleAspect-----------");
        log.info("class: {}, method: {}", clz, method.getName());
    }

    @Override
    public void afterThrowing(Class clz, Method method, Object[] args, Throwable e) {
        log.error("-----------error  DoodleAspect-----------");
        log.error("class: {}, method: {}, exception: {}", clz, method.getName(), e.getMessage());
    }
}
// DoodleAspect2
@Slf4j
@Order(2)
@Aspect(pointcut = "@within(com.zbw.core.annotation.Controller)")
public class DoodleAspect2 implements AroundAdvice {

    @Override
    public void before(Class clz, Method method, Object[] args) throws Throwable {
        log.info("-----------before  DoodleAspect2-----------");
        log.info("class: {}, method: {}", clz.getName(), method.getName());
    }

    @Override
    public void afterReturning(Class clz, Object returnValue, Method method, Object[] args) throws Throwable {
        log.info("-----------after  DoodleAspect2-----------");
        log.info("class: {}, method: {}", clz, method.getName());
    }

    @Override
    public void afterThrowing(Class clz, Method method, Object[] args, Throwable e) {
        log.error("-----------error  DoodleAspect2-----------");
        log.error("class: {}, method: {}, exception: {}", clz, method.getName(), e.getMessage());
    }
}

然后在AopTest測(cè)試類中調(diào)用DoodleControllerhello()方法。

@Slf4j
public class AopTest {
    @Test
    public void doAop() {
        BeanContainer beanContainer = BeanContainer.getInstance();
        beanContainer.loadBeans("com.zbw");
        new Aop().doAop();
        new Ioc().doIoc();
        DoodleController controller = (DoodleController) beanContainer.getBean(DoodleController.class);
        controller.hello();
    }
}

在結(jié)果的圖中可以看出DoodleAspectDoodleAspect2兩個(gè)代理方法都執(zhí)行了,并且是按照預(yù)期的執(zhí)行順序執(zhí)行的。

從零開(kāi)始實(shí)現(xiàn)一個(gè)簡(jiǎn)易的Java MVC框架(一)--前言

從零開(kāi)始實(shí)現(xiàn)一個(gè)簡(jiǎn)易的Java MVC框架(二)--實(shí)現(xiàn)Bean容器

從零開(kāi)始實(shí)現(xiàn)一個(gè)簡(jiǎn)易的Java MVC框架(三)--實(shí)現(xiàn)IOC

從零開(kāi)始實(shí)現(xiàn)一個(gè)簡(jiǎn)易的Java MVC框架(四)--實(shí)現(xiàn)AOP

從零開(kāi)始實(shí)現(xiàn)一個(gè)簡(jiǎn)易的Java MVC框架(五)--引入aspectj實(shí)現(xiàn)AOP切點(diǎn)

從零開(kāi)始實(shí)現(xiàn)一個(gè)簡(jiǎn)易的Java MVC框架(六)--加強(qiáng)AOP功能

從零開(kāi)始實(shí)現(xiàn)一個(gè)簡(jiǎn)易的Java MVC框架(七)--實(shí)現(xiàn)MVC

從零開(kāi)始實(shí)現(xiàn)一個(gè)簡(jiǎn)易的Java MVC框架(八)--制作Starter

從零開(kāi)始實(shí)現(xiàn)一個(gè)簡(jiǎn)易的Java MVC框架(九)--優(yōu)化MVC代碼

源碼地址:doodle

原文地址:從零開(kāi)始實(shí)現(xiàn)一個(gè)簡(jiǎn)易的Java MVC框架(六)--加強(qiáng)AOP功能

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/71611.html

相關(guān)文章

  • 從零開(kāi)始實(shí)現(xiàn)一個(gè)簡(jiǎn)易Java MVC框架

    摘要:不過(guò)仔細(xì)了解了一段時(shí)候發(fā)現(xiàn),其實(shí)他的原理是很簡(jiǎn)單的,所以想要自己也動(dòng)手實(shí)現(xiàn)一個(gè)功能類似的框架。原文地址從零開(kāi)始實(shí)現(xiàn)一個(gè)簡(jiǎn)易的框架 前言 最近在看spring-boot框架的源碼,看了源碼之后更是讓我感受到了spring-boot功能的強(qiáng)大。而且使用了很多的設(shè)計(jì)模式,讓人在看的時(shí)候覺(jué)得有點(diǎn)難以下手。 不過(guò)仔細(xì)了解了一段時(shí)候發(fā)現(xiàn),其實(shí)他的原理是很簡(jiǎn)單的,所以想要自己也動(dòng)手實(shí)現(xiàn)一個(gè)功能類似的...

    neuSnail 評(píng)論0 收藏0
  • 從零開(kāi)始實(shí)現(xiàn)一個(gè)簡(jiǎn)易Java MVC框架(五)--引入aspectj實(shí)現(xiàn)AOP切點(diǎn)

    摘要:接下來(lái)就可以把這個(gè)切點(diǎn)類加入到我們之前實(shí)現(xiàn)的功能中了。實(shí)現(xiàn)的切點(diǎn)功能首先改裝注解,把之前改成來(lái)存儲(chǔ)表達(dá)式。測(cè)試用例在上一篇文章從零開(kāi)始實(shí)現(xiàn)一個(gè)簡(jiǎn)易的框架四實(shí)現(xiàn)中的測(cè)試用例的基礎(chǔ)上修改測(cè)試用例。 前言 在上一節(jié)從零開(kāi)始實(shí)現(xiàn)一個(gè)簡(jiǎn)易的Java MVC框架(四)--實(shí)現(xiàn)AOP中我們實(shí)現(xiàn)了AOP的功能,已經(jīng)可以生成對(duì)應(yīng)的代理類了,但是對(duì)于代理對(duì)象的選擇只能通過(guò)指定的類,這樣確實(shí)不方便也不合理。...

    wupengyu 評(píng)論0 收藏0
  • 從零開(kāi)始實(shí)現(xiàn)一個(gè)簡(jiǎn)易Java MVC框架(八)--制作Starter

    摘要:服務(wù)器相關(guān)配置啟動(dòng)類資源目錄目錄靜態(tài)文件目錄端口號(hào)目錄目錄實(shí)現(xiàn)內(nèi)嵌服務(wù)器在上一章文章從零開(kāi)始實(shí)現(xiàn)一個(gè)簡(jiǎn)易的框架七實(shí)現(xiàn)已經(jīng)在文件中引入了依賴,所以這里就不用引用了。 spring-boot的Starter 一個(gè)項(xiàng)目總是要有一個(gè)啟動(dòng)的地方,當(dāng)項(xiàng)目部署在tomcat中的時(shí)候,經(jīng)常就會(huì)用tomcat的startup.sh(startup.bat)的啟動(dòng)腳本來(lái)啟動(dòng)web項(xiàng)目 而在spring-b...

    AprilJ 評(píng)論0 收藏0
  • 從零開(kāi)始實(shí)現(xiàn)一個(gè)簡(jiǎn)易Java MVC框架(九)--優(yōu)化MVC代碼

    摘要:前言在從零開(kāi)始實(shí)現(xiàn)一個(gè)簡(jiǎn)易的框架七實(shí)現(xiàn)中實(shí)現(xiàn)了框架的的功能,不過(guò)最后指出代碼的邏輯不是很好,在這一章節(jié)就將這一部分代碼進(jìn)行優(yōu)化。 前言 在從零開(kāi)始實(shí)現(xiàn)一個(gè)簡(jiǎn)易的Java MVC框架(七)--實(shí)現(xiàn)MVC中實(shí)現(xiàn)了doodle框架的MVC的功能,不過(guò)最后指出代碼的邏輯不是很好,在這一章節(jié)就將這一部分代碼進(jìn)行優(yōu)化。 優(yōu)化的目標(biāo)是1.去除DispatcherServlet請(qǐng)求分發(fā)器中的http邏...

    ruicbAndroid 評(píng)論0 收藏0
  • 從零開(kāi)始實(shí)現(xiàn)一個(gè)簡(jiǎn)易Java MVC框架(二)--實(shí)現(xiàn)Bean容器

    摘要:容器實(shí)際上就是存放所有的地方,即以及相關(guān)信息對(duì)應(yīng)其實(shí)體的容器,為什么稱之為呢,因?yàn)樵谥校x信息和實(shí)例的東西叫。了解到這個(gè)以后接下來(lái)就可以開(kāi)始編寫容器了,在包下創(chuàng)建一個(gè)類叫。獲取容器實(shí)例至此,這個(gè)容器就完成了。 項(xiàng)目準(zhǔn)備 首先確保你擁有以下環(huán)境或者工具 idea java 8 maven 3.3.X lombok插件 然后我們創(chuàng)建一個(gè)maven工程,編寫pom.xml引入一些需要的...

    paulquei 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<