博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring源代码解析(五):Spring AOP获取Proxy
阅读量:2181 次
发布时间:2019-05-01

本文共 4781 字,大约阅读时间需要 15 分钟。

下面我们来看看Spring的AOP的一些相关代码是怎么得到Proxy的,让我们我们先看看AOP和Spring AOP的一些基本概念: 

Advice: 

    通知,制定在连接点做什么,在Sping中,他主要描述Spring围绕方法调用注入的额外的行为,Spring提供的通知类型有: 

    before advice,AfterReturningAdvice,ThrowAdvice,MethodBeforeAdvice,这些都是Spring AOP定义的接口类,具体的动作实现需要用户程序来完成。 

Pointcut: 

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

Java代码  
  1. public 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的最终确定: 

Java代码  
  1. protected 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()可以直接得到代理对象: 

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

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

Java代码  
  1. private 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来得到代理对象。  
  20. protected Object getProxy(AopProxy aopProxy) {  
  21.     return aopProxy.getProxy(this.beanClassLoader);  
  22. }  

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

Java代码  
  1. protected synchronized AopProxy createAopProxy() {  
  2.     if (!this.isActive) {  
  3.         activate();  
  4.     }  
  5.     return getAopProxyFactory().createAopProxy(this);  
  6. }  

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

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

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

Java代码  
  1. public 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是怎样生成的:

Java代码  
  1. public 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而言,其生产出来的对象是封装了目标对象的代理对象。

转载地址:http://tutkb.baihongyu.com/

你可能感兴趣的文章
Leetcode C++《热题 Hot 100-28》19.删除链表的倒数第N个节点
查看>>
Leetcode C++《热题 Hot 100-29》22.括号生成
查看>>
Leetcode C++《热题 Hot 100-44》102.二叉树的层次遍历
查看>>
Leetcode C++《热题 Hot 100-47》236.二叉树的最近公共祖先
查看>>
Leetcode C++《热题 Hot 100-48》406.根据身高重建队列
查看>>
《kubernetes权威指南·第四版》第二章:kubernetes安装配置指南
查看>>
Leetcode C++《热题 Hot 100-49》399.除法求值
查看>>
Leetcode C++《热题 Hot 100-51》152. 乘积最大子序列
查看>>
Leetcode C++ 《第181场周赛-1》 5364. 按既定顺序创建目标数组
查看>>
Leetcode C++ 《第181场周赛-2》 1390. 四因数
查看>>
阿里云《云原生》公开课笔记 第一章 云原生启蒙
查看>>
阿里云《云原生》公开课笔记 第二章 容器基本概念
查看>>
阿里云《云原生》公开课笔记 第三章 kubernetes核心概念
查看>>
阿里云《云原生》公开课笔记 第四章 理解Pod和容器设计模式
查看>>
阿里云《云原生》公开课笔记 第五章 应用编排与管理
查看>>
阿里云《云原生》公开课笔记 第六章 应用编排与管理:Deployment
查看>>
阿里云《云原生》公开课笔记 第七章 应用编排与管理:Job和DaemonSet
查看>>
阿里云《云原生》公开课笔记 第八章 应用配置管理
查看>>
阿里云《云原生》公开课笔记 第九章 应用存储和持久化数据卷:核心知识
查看>>
linux系统 阿里云源
查看>>