前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring源码解析之Spring AOP 获取 Proxy

Spring源码解析之Spring AOP 获取 Proxy

作者头像
I Teach You 我教你
发布2023-07-18 14:53:20
1920
发布2023-07-18 14:53:20
举报
文章被收录于专栏:王二麻子IT技术交流园地

下面我们来看看 Spring 的 AOP 的一些相关代码是怎么得到 Proxy 的,让我们我们先看看 AOP 和 Spring AOP 的一些基本概念: Advice: 通知,制定在连接点做什么,在 Sping 中,他主要描述 Spring 围绕方法调用注入的额外的行为,Spring 提供的通知类型有:

代码语言:javascript
复制
1before advice,AfterReturningAdvice,ThrowAdvice,MethodBeforeAdvice

这些都是 Spring AOP 定义的接口类,具体的动作实现需要用户程序来完成。 Pointcut: 切点,其决定一个 advice 应该应用于哪个连接点,也就是需要插入额外处理的地方的集合,例如,被某个 advice 作为目标的一组方法。Spring pointcut 通常意味着标示方法,可以选择一组方法调用作为 pointcut,Spring 提供了具体的切点来给用户使用,比如正则表达式切点 JdkRegexpMethodPointcut 通过正则表达式对方法名进行匹配,其通过使用 AbstractJdkRegexpMethodPointcut 中的对MethodMatcher 接口的实现来完成 pointcut 功能:

代码语言:javascript
复制
 1public final boolean matches(Method method, Class targetClass) { 
 2    //这里通过反射得到方法的全名 
 3    String patt = method.getDeclaringClass().getName() + "." + method.getName(); 
 4    for (int i = 0; i < this.patterns.length; i++) { 
 5        // 这里是判断是否和方法名是否匹配的代码 
 6        boolean matched = matches(patt, i); 
 7        if (matched) { 
 8            for (int j = 0; j < this.excludedPatterns.length; j++) { 
 9                boolean excluded = matchesExclusion(patt, j); 
10                if(excluded) { 
11                    return false; 
12                } 
13            } 
14            return true; 
15        } 
16    } 
17    return false; 
18} 

在 JDKRegexpMethodPointcut 中通过 JDK 中的正则表达式匹配来完成 pointcut 的最终确定:

代码语言:javascript
复制
1protected boolean matches(String pattern, int patternIndex) { 
2    Matcher matcher = this.compiledPatterns[patternIndex].matcher(pattern); 
3    return matcher.matches(); 
4} 

Advisor: 当我们完成额外的动作设计(advice)和额外动作插入点的设计(pointcut)以后,我们需要一个对象把他们结合起来,这就是通知器 - advisor,定义应该在哪里应用哪个通知。Advisor 的实现有:DefaultPointcutAdvisor 他有两个属性 advice 和 pointcut 来让我们配置 advice和 pointcut。

接着我们就可以通过 ProxyFactoryBean 来配置我们的代理对象和方面行为,在 ProxyFactoryBean 中有 interceptorNames 来配置已经定义好的通知器-advisor,虽然这里的名字叫做 interceptNames,但实际上是供我们配置 advisor 的地方,具体的代理实现通过 JDK 的Proxy 或者 CGLIB 来完成。因为 ProxyFactoryBean 是一个 FactoryBean,在 ProxyFactoryBean 中我们通过 getObject()可以直接得到代理对象:

代码语言:javascript
复制
 1public Object getObject() throws BeansException { 
 2    //这里初始化通知器链 
 3    initializeAdvisorChain(); 
 4    if (isSingleton()) { 
 5        //根据定义需要生成单件的 Proxy 
 6        return getSingletonInstance(); 
 7    }else { 
 8        ...
 9        //这里根据定义需要生成 Prototype 类型的 Proxy 
10        return newPrototypeInstance(); 
11    } 
12} 

我们看看怎样生成单件的代理对象:

代码语言:javascript
复制
 1private synchronized Object getSingletonInstance() { 
 2    if (this.singletonInstance == null) { 
 3        this.targetSource = freshTargetSource(); 
 4        if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) { 
 5            // 这里设置代理对象的接口 
 6            setInterfaces(ClassUtils.getAllInterfacesForClass(this.targetSource.getTargetClass())); 
 7        } 
 8        // Eagerly initialize the shared singleton instance. 
 9        super.setFrozen(this.freezeProxy); 
10        // 注意这里的方法会使用 ProxyFactory 来生成我们需要的 Proxy 
11        this.singletonInstance = getProxy(createAopProxy()); 
12        // We must listen to superclass advice change events to recache the singleton 
13        // instance if necessary. 
14        addListener(this); 
15    } 
16    return this.singletonInstance; 
17} 
18
19//使用 createAopProxy 放回的 AopProxy 来得到代理对象。 
20protected Object getProxy(AopProxy aopProxy) { 
21    return aopProxy.getProxy(this.beanClassLoader); 
22} 

ProxyFactoryBean 的父类是 AdvisedSupport,Spring 使用 AopProxy 接口把 AOP 代理的实现与框架的其他部分分离开来;在AdvisedSupport 中通过这样的方式来得到 AopProxy,当然这里需要得到 AopProxyFactory 的帮助 - 下面我们看到 Spring 为我们提供的实现,来帮助我们方便的从 JDK 或者 cglib 中得到我们想要的代理对象:

代码语言:javascript
复制
1protected synchronized AopProxy createAopProxy() { 
2    if (!this.isActive) { 
3        activate(); 
4    } 
5    return getAopProxyFactory().createAopProxy(this); 
6} 

而在 ProxyConfig 中对使用的 AopProxyFactory 做了定义:

代码语言:javascript
复制
1//这个 DefaultAopProxyFactory 是 Spring 用来生成 AopProxy 的地方, 
2//当然了它包含 JDK 和 Cglib 两种实现方式。 
3private transient AopProxyFactory aopProxyFactory = new DefaultAopProxyFactory(); 

其中在 DefaultAopProxyFactory 中是这样生成 AopProxy 的:

代码语言:javascript
复制
 1public AopProxy createAopProxy(AdvisedSupport advisedSupport) throws AopConfigException { 
 2    //首先考虑使用 cglib 来实现代理对象,当然如果同时目标对象不是接口的实现类的话 
 3    if (advisedSupport.isOptimize() || advisedSupport.isProxyTargetClass() || 
 4        advisedSupport.getProxiedInterfaces().length == 0) { 
 5        //这里判断如果不存在 cglib 库,直接抛出异常。 
 6        if (!cglibAvailable) { 
 7            throw new AopConfigException( 
 8            "Cannot proxy target class because CGLIB2 is not available. " + 
 9            "Add CGLIB to the class path or specify proxy interfaces."); 
10        } 
11        // 这里使用 Cglib 来生成 Proxy,如果 target 不是接口的实现的话,返回 cglib 类型的 AopProxy 
12        return CglibProxyFactory.createCglibProxy(advisedSupport); 
13    } 
14    else { 
15        // 这里使用 JDK 来生成 Proxy,返回 JDK 类型的 AopProxy 
16        return new JdkDynamicAopProxy(advisedSupport); 
17    } 
18} 

于是我们就可以看到其中的代理对象可以由 JDK 或者 Cglib 来生成,我们看到 JdkDynamicAopProxy 类和 Cglib2AopProxy 都实现的是AopProxy 的接口,在 JdkDynamicAopProxy 实现中我们可以看到 Proxy 是怎样生成的:

代码语言:javascript
复制
 1public Object getProxy(ClassLoader classLoader) { 
 2    if (logger.isDebugEnabled()) { 
 3        Class targetClass = this.advised.getTargetSource().getTargetClass(); 
 4        logger.debug("Creating JDK dynamic proxy" + 
 5        (targetClass != null ? " for [" + targetClass.getName() + "]" : "")); 
 6    } 
 7    Class[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised); 
 8    findDefinedEqualsAndHashCodeMethods(proxiedInterfaces); 
 9    //这里我们调用 JDK Proxy 来生成需要的 Proxy 实例 
10    return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); 
11} 

这样用 Proxy 包装 target 之后,通过 ProxyFactoryBean 得到对其方法的调用就被 Proxy 拦截了, ProxyFactoryBean 的 getObject()方法得到的实际上是一个 Proxy 了,我们的 target 对象已经被封装了。对 ProxyFactoryBean 这个工厂 bean 而言,其生产出来的对象是封装了目标对象的代理对象

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020/07/27 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云顾问
云顾问(Tencent Cloud Smart Advisor)是一款提供可视化云架构IDE和多个ITOM领域垂直应用的云上治理平台,以“一个平台,多个应用”为产品理念,依托腾讯云海量运维专家经验,助您打造卓越架构,实现便捷、灵活的一站式云上治理。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档