成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

重拾-Spring AOP-自動(dòng)代理

Mr_houzi / 1717人閱讀

摘要:是通過判斷當(dāng)前是否匹配,只有匹配的才會(huì)創(chuàng)建代理。實(shí)現(xiàn)分析類結(jié)構(gòu)從上圖類結(jié)構(gòu),我們知道其實(shí)現(xiàn)與類似都是通過實(shí)現(xiàn)接口在完成實(shí)例化后進(jìn)行自動(dòng)代理處理。

概述

在上一篇 重拾-Spring AOP 中我們會(huì)發(fā)現(xiàn) Spring AOP 是通過類 ProxyFactoryBean 創(chuàng)建代理對(duì)象,其有個(gè)缺陷就是只能代理一個(gè)目標(biāo)對(duì)象 bean, 當(dāng)代理目標(biāo)類過多時(shí),配置文件臃腫不方便管理維護(hù),因此 Spring 提供了能夠?qū)崿F(xiàn)自動(dòng)創(chuàng)建代理的類 BeanNameAutoProxyCreator , DefaultAdvisorAutoProxyCreator ;下面我們看下二者是如何實(shí)現(xiàn)自動(dòng)代理的。

BeanNameAutoProxyCreator
BeanNameAutoProxyCreator 是通過判斷當(dāng)前 bean name 是否匹配,只有匹配的 bean 才會(huì)創(chuàng)建代理。
使用示例

Spring xml 配置








    
    
        
            userService
            demoService
        
    
    
    
        
            userAfterAdvice
            userBeforeAdvice
        
    

測(cè)試

ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("/org/springframework/aop/aop.xml");

UserService userService = (UserService) ctx.getBean("userService");

userService.say();

DemoService demoService = (DemoService) ctx.getBean("demoService");

demoService.demo();

運(yùn)行結(jié)果

do before advice ....
do say method
do after return advice ....
do before advice ....
do demo.
do after return advice ....
實(shí)現(xiàn)分析
類結(jié)構(gòu)

如上圖 BeanNameAutoProxyCreator 類結(jié)構(gòu)可以看出,其實(shí)現(xiàn)了接口 BeanPostProcessor ; 那么我們可以大概猜測(cè)出其自動(dòng)代理的實(shí)現(xiàn)原理與自動(dòng)注入類似,都是在 bean 實(shí)例化后進(jìn)行特殊的處理,下面就讓我們看下源碼驗(yàn)證下吧。

分析
public Object postProcessAfterInitialization(Object bean, String name) throws BeansException {
    // Check for special cases. We don"t want to try to autoproxy a part of the autoproxying
    // infrastructure, lest we get a stack overflow.
    if (isInfrastructureClass(bean, name) || shouldSkip(bean, name)) {
        logger.debug("Did not attempt to autoproxy infrastructure class "" + bean.getClass() + """);
        return bean;
    }
    
    TargetSource targetSource = getTargetSource(bean, name);
    
    Object[] specificInterceptors = getInterceptorsAndAdvisorsForBean(bean, name);
    
    // proxy if we have advice or if a TargetSourceCreator wants to do some
    // fancy stuff such as pooling
    if (specificInterceptors != DO_NOT_PROXY || !(targetSource instanceof SingletonTargetSource)) {

        // handle prototypes correctly
        // 獲取容器中配置的 advisors 
        Advisor[] commonInterceptors = resolveInterceptorNames();

        List allInterceptors = new ArrayList();
        if (specificInterceptors != null) {
            allInterceptors.addAll(Arrays.asList(specificInterceptors));
            if (commonInterceptors != null) {
                if (this.applyCommonInterceptorsFirst) {
                    allInterceptors.addAll(0, Arrays.asList(commonInterceptors));
                }
                else {
                    allInterceptors.addAll(Arrays.asList(commonInterceptors));
                }
            }
        }
        if (logger.isInfoEnabled()) {
            int nrOfCommonInterceptors = commonInterceptors != null ? commonInterceptors.length : 0;
            int nrOfSpecificInterceptors = specificInterceptors != null ? specificInterceptors.length : 0;
            logger.info("Creating implicit proxy for bean "" +  name + "" with " + nrOfCommonInterceptors +
                                    " common interceptors and " + nrOfSpecificInterceptors + " specific interceptors");
        }
        ProxyFactory proxyFactory = new ProxyFactory();

        // copy our properties (proxyTargetClass) inherited from ProxyConfig
        proxyFactory.copyFrom(this);
        
        if (!getProxyTargetClass()) {
            // Must allow for introductions; can"t just set interfaces to
            // the target"s interfaces only.
            // 添加設(shè)置代理的接口
            Class[] targetsInterfaces = AopUtils.getAllInterfaces(bean);
            for (int i = 0; i < targetsInterfaces.length; i++) {
                proxyFactory.addInterface(targetsInterfaces[i]);
            }
        }
        
        for (Iterator it = allInterceptors.iterator(); it.hasNext();) {
            Advisor advisor = GlobalAdvisorAdapterRegistry.getInstance().wrap(it.next());
            // 添加 advisor
            proxyFactory.addAdvisor(advisor);
        }
        proxyFactory.setTargetSource(getTargetSource(bean, name));
        
        // 創(chuàng)建代理對(duì)象,依舊采用的 jdk 動(dòng)態(tài)代理; 因?yàn)樯厦嬖O(shè)置了代理的 interface
        return proxyFactory.getProxy();
    }
    else {
        return bean;
    }
}
protected Object[] getInterceptorsAndAdvisorsForBean(Object bean, String beanName) {
    if (this.beanNames != null) {
        // bean name 包含在配置的名稱列表中,說明需要代理
        if (this.beanNames.contains(beanName)) {
            return PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS;
        }
        for (Iterator it = this.beanNames.iterator(); it.hasNext();) {
            String mappedName = (String) it.next();
            // bean name 匹配通配符,說明需要代理
            if (isMatch(beanName, mappedName)) {
                return PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS;
            }
        }
    }
    // 說明 bean 不需要代理
    return DO_NOT_PROXY;
}
protected boolean isMatch(String beanName, String mappedName) {
    // bean name 匹配通配符
    return (mappedName.endsWith("*") && beanName.startsWith(mappedName.substring(0, mappedName.length() - 1))) ||
            (mappedName.startsWith("*") && beanName.endsWith(mappedName.substring(1, mappedName.length())));
}

BeanNameAutoProxyCreator 的源碼大概總結(jié)其自動(dòng)代理流程:

判斷當(dāng)前 bean name 是否匹配配置

加載配置的 advisor, 也就是配置的 interceptorNames

采用 jdk 動(dòng)態(tài)代理創(chuàng)建 bean 的代理對(duì)象

DefaultAdvisorAutoProxyCreator
DefaultAdvisorAutoProxyCreator 會(huì)搜索 BeanFactory 容器內(nèi)部所有可用的 Advisor; 并為容器中匹配的 bean 創(chuàng)建代理。 在上一篇 重拾-Spring AOP 中我們知道 Spring AOP 會(huì)默認(rèn)創(chuàng)建實(shí)例為 DefaultPointcutAdvisorAdvisor; 那么在分析 DefaultAdvisorAutoProxyCreator 之前,我們看下 Spring AOP 還為我們提供了哪些內(nèi)置的 Advisor 。
NameMatchMethodPointcutAdvisor
NameMatchMethodPointcutAdvisor 是按 method name 匹配,只有當(dāng)目標(biāo)類執(zhí)行方法匹配的時(shí)候,才會(huì)執(zhí)行 Advice
public class NameMatchMethodPointcut extends StaticMethodMatcherPointcut {

    // 配置攔截的 method name
    private String[] mappedNames = new String[0];

    public boolean matches(Method m, Class targetClass) {
        for (int i = 0; i
RegexpMethodPointcutAdvisor
RegexpMethodPointcutAdvisor 是按照正則表達(dá)式匹配方法,能夠精確定位到需要攔截的方法。
public class RegexpMethodPointcut extends StaticMethodMatcherPointcut implements ClassFilter { 

    public boolean matches(Method m, Class targetClass) { 
        // TODO use target class here?
        // 拼接表達(dá)式
        String patt = m.getDeclaringClass().getName() + "." + m.getName();
        for (int i = 0; i < this.compiledPatterns.length; i++) {
            // 正則匹配
            boolean matched = this.matcher.matches(patt, this.compiledPatterns[i]);
            if (logger.isDebugEnabled()) {
                logger.debug("Candidate is: "" + patt + ""; pattern is " + this.compiledPatterns[i].getPattern() +
                             "; matched=" + matched);
            }
            if (matched) {
                return true;
            }
        }
        return false;
    }

    public boolean matches(Class clazz) {
        // TODO do with regexp
        return true;
    }
    
    public ClassFilter getClassFilter() {
        return this;
    }

}
使用示例

xml 配置



    
    

    
    

    
    
        
            
            save*
        
        
            
        
    

    
        
            
            org.springframework.aop.*.del*.*
        
        
            
        
    

    

測(cè)試

ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("/org/springframework/aop/aop.xml");

UserService userService = (UserService) ctx.getBean("userService");

userService.saveUser();

userService.delUser();

DemoService demoService = (DemoService) ctx.getBean("demoService");

demoService.saveDemo();

demoService.delDemo();

測(cè)試結(jié)果

do before advice ....
do save user ......
do del user ......
do after return advice ....
do before advice ....
do save demo ......
do del demo ......
do after return advice ....
從測(cè)試結(jié)果可以看出,通過配置不同 Advisor 匹配不同的 Method 采用相應(yīng)的 Advice 進(jìn)行處理。
實(shí)現(xiàn)分析
類結(jié)構(gòu)

從上圖 DefaultAdvisorAutoProxyCreator 類結(jié)構(gòu),我們知道其實(shí)現(xiàn)與 BeanNameAutoProxyCreator 類似;都是通過實(shí)現(xiàn)接口 BeanPostProcessor 在 bean 完成實(shí)例化后進(jìn)行自動(dòng)代理處理。

分析

DefaultAdvisorAutoProxyCreatorBeanNameAutoProxyCreator 都繼承了類 AbstractAutoProxyCreator ,所以從源碼中我們可以發(fā)現(xiàn)二者都重寫了方法 getInterceptorsAndAdvisorsForBean ,也就是在獲取當(dāng)前 bean 所匹配的 Advisor 邏輯不一樣之外其他處理一致; 那么下面針對(duì) DefaultAdvisorAutoProxyCreator 的實(shí)現(xiàn)我們主要看下方法 getInterceptorsAndAdvisorsForBean 的處理。

protected Object[] getInterceptorsAndAdvisorsForBean(Object bean, String name) {
    // 查找與當(dāng)前 bean 匹配的 advisor
    List advices = findEligibleAdvisors(bean.getClass());
    if (advices.isEmpty()) {
        return DO_NOT_PROXY;
    }
    // 對(duì) advisor 集合排序
    advices = sortAdvisors(advices);
    return advices.toArray();
}

查找匹配的 Advisor

protected List findEligibleAdvisors(Class clazz) {
    // 查找當(dāng)前容器中所有定義的 advisor
    List candidateAdvice = findCandidateAdvisors();
    List eligibleAdvice = new LinkedList();
    for (int i = 0; i < candidateAdvice.size(); i++) {
        // Sun, give me generics, please!
        Advisor candidate = (Advisor) candidateAdvice.get(i);
        // 判斷 bean 是否可以應(yīng)用 advisor
        if (AopUtils.canApply(candidate, clazz, null)) {
            // 將 advisor 添加到匹配的集合中
            eligibleAdvice.add(candidate);
            logger.info("Candidate Advice [" + candidate + "] accepted for class [" + clazz.getName() + "]");
        }
        else {
            logger.info("Candidate Advice [" + candidate + "] rejected for class [" + clazz.getName() + "]");
        }
    }
    return eligibleAdvice;
}

獲取容器中所有的 Advisor

protected List findCandidateAdvisors() {
    if (!(getBeanFactory() instanceof ListableBeanFactory)) {
        throw new IllegalStateException("Cannot use DefaultAdvisorAutoProxyCreator without a ListableBeanFactory");
    }
    ListableBeanFactory owningFactory = (ListableBeanFactory) getBeanFactory();
    // 從容器中查找所有 bean 定義 type 為 Advisor 的 bean name
    String[] adviceNames = BeanFactoryUtils.beanNamesIncludingAncestors(owningFactory, Advisor.class);
    List candidateAdvisors = new LinkedList();
    for (int i = 0; i < adviceNames.length; i++) {
        String name = adviceNames[i];
        if (!this.usePrefix || name.startsWith(this.advisorBeanNamePrefix)) {
            // 獲取 advisor 實(shí)例
            Advisor advisor = (Advisor) owningFactory.getBean(name);
            candidateAdvisors.add(advisor);
        }
    }
    return candidateAdvisors;
}

判斷 bean 是否匹配 Advisor

public static boolean canApply(Advisor advisor, Class targetClass, Class[] proxyInterfaces) {
    if (advisor instanceof IntroductionAdvisor) {
        return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
    }
    else if (advisor instanceof PointcutAdvisor) {
        PointcutAdvisor pca = (PointcutAdvisor) advisor;
        // 通過 advisor 的 pointcut 判斷 bean 是否匹配
        return canApply(pca.getPointcut(), targetClass, proxyInterfaces);
    }
    else {
        // It doesn"t have a pointcut so we assume it applies
        return true;
    }
}


public static boolean canApply(Pointcut pc, Class targetClass, Class[] proxyInterfaces) {
    // 類是否匹配
    if (!pc.getClassFilter().matches(targetClass)) {
        return false;
    }
    
    // 判斷類中的 method 是否匹配
    // 獲取類下所有的method
    Method[] methods = targetClass.getMethods();
    for (int i = 0; i < methods.length; i++) {
        Method m = methods[i];
        // If we"re looking only at interfaces and this method
        // isn"t on any of them, skip it
        if (proxyInterfaces != null && !methodIsOnOneOfTheseInterfaces(m, proxyInterfaces)) {
            continue;
        }
        // 執(zhí)行 pointcut 的 method match
        if (pc.getMethodMatcher().matches(m, targetClass))
            return true;
    }
    return false;
}

DefaultAdvisorAutoProxyCreator 的源碼分析,可知其自動(dòng)代理流程大概如下:

從容器中獲取所有 Advisor 實(shí)例

匹配 bean 所支持的 Advisor

采用 jdk 動(dòng)態(tài)代理創(chuàng)建 bean 的代理對(duì)象

小結(jié)

BeanNameAutoProxyCreator , DefaultAdvisorAutoProxyCreator 二者的實(shí)現(xiàn)可以看出其相同點(diǎn)

都是基于實(shí)現(xiàn)接口 BeanPostProcessor 的實(shí)現(xiàn)

都是先獲取當(dāng)前 bean 所匹配的 Advisor,后在創(chuàng)建代理對(duì)象

二者的不同點(diǎn)在于:

前者是基于 bean name 判斷是否判斷,后者是通過 Advisor 內(nèi)部的 Ponitcut 匹配判斷

前者的 Advisor 是用戶配置的,后者是容器中所有匹配的 Advisor

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

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

相關(guān)文章

  • 重拾-Spring Transaction

    摘要:當(dāng)存在掛起的事務(wù)時(shí),執(zhí)行恢復(fù)掛起的事務(wù)將掛起的事務(wù)綁定的重新綁定到當(dāng)前上下文事務(wù)的就是將掛起的事務(wù)重新綁定到當(dāng)前上下文中。 問題 面試中是不是有時(shí)經(jīng)常會(huì)被問到 Spring 事務(wù)如何管理的了解嗎? ,Spring 事務(wù)的傳播性有哪些,能聊聊它們的使用場(chǎng)景嗎?, 事務(wù)回滾的時(shí)候是所有異常下都會(huì)回滾嗎?; 下面我們就帶著這些問題來看看 Spring 事務(wù)是如何實(shí)現(xiàn)的吧。 實(shí)現(xiàn)分析 首先我們...

    fasss 評(píng)論0 收藏0
  • 重拾-Spring-AOP

    摘要:簡(jiǎn)單點(diǎn)說也就是當(dāng)前切面將會(huì)攔截哪些類下的哪些方法,攔截過程中會(huì)采用哪些增強(qiáng)處理前置通知,返回通知,異常通知。切面鏈,是一系列的切面的集合。 AOP 術(shù)語 關(guān)于 AOP 的概念描述及相關(guān)術(shù)語可以參考 徹底征服 Spring AOP 之 理論篇 總結(jié)的很好; 本文將著重分析下 AOP 的實(shí)現(xiàn)過程。 使用示例 定義接口 public interface UserService { v...

    468122151 評(píng)論0 收藏0
  • 從源碼入手,一文帶你讀懂Spring AOP面向切面編程

    摘要:,,面向切面編程。,切點(diǎn),切面匹配連接點(diǎn)的點(diǎn),一般與切點(diǎn)表達(dá)式相關(guān),就是切面如何切點(diǎn)。例子中,注解就是切點(diǎn)表達(dá)式,匹配對(duì)應(yīng)的連接點(diǎn),通知,指在切面的某個(gè)特定的連接點(diǎn)上執(zhí)行的動(dòng)作。,織入,將作用在的過程。因?yàn)樵创a都是英文寫的。 之前《零基礎(chǔ)帶你看Spring源碼——IOC控制反轉(zhuǎn)》詳細(xì)講了Spring容器的初始化和加載的原理,后面《你真的完全了解Java動(dòng)態(tài)代理嗎?看這篇就夠了》介紹了下...

    wawor4827 評(píng)論0 收藏0
  • 架構(gòu)~微服務(wù) - 收藏集 - 掘金

    摘要:它就是史上最簡(jiǎn)單的教程第三篇服務(wù)消費(fèi)者后端掘金上一篇文章,講述了通過去消費(fèi)服務(wù),這篇文章主要講述通過去消費(fèi)服務(wù)。概覽和架構(gòu)設(shè)計(jì)掘金技術(shù)征文后端掘金是基于的一整套實(shí)現(xiàn)微服務(wù)的框架。 Spring Boot 配置文件 – 在坑中實(shí)踐 - 后端 - 掘金作者:泥瓦匠鏈接:Spring Boot 配置文件 – 在坑中實(shí)踐版權(quán)歸作者所有,轉(zhuǎn)載請(qǐng)注明出處本文提綱一、自動(dòng)配置二、自定義屬性三、ran...

    church 評(píng)論0 收藏0
  • Spring AOP就是這么簡(jiǎn)單啦

    摘要:是一種特殊的增強(qiáng)切面切面由切點(diǎn)和增強(qiáng)通知組成,它既包括了橫切邏輯的定義也包括了連接點(diǎn)的定義。實(shí)際上,一個(gè)的實(shí)現(xiàn)被拆分到多個(gè)類中在中聲明切面我們知道注解很方便,但是,要想使用注解的方式使用就必須要有源碼因?yàn)槲覀円? 前言 只有光頭才能變強(qiáng) 上一篇已經(jīng)講解了Spring IOC知識(shí)點(diǎn)一網(wǎng)打盡!,這篇主要是講解Spring的AOP模塊~ 之前我已經(jīng)寫過一篇關(guān)于AOP的文章了,那篇把比較重要的知...

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

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

0條評(píng)論

閱讀需要支付1元查看
<