懂SpringAOP源码

coding

1 主要的接口

1.1 Advice 通知

本接口定义了切面的增强方式,如:前置增强 BeforeAdvice,后置增强 AfterAdvice,异常增强 ThrowsAdvice 等。下面看两个主要的子接口的源码。

publicinterfaceMethodBeforeAdviceextendsBeforeAdvice{/***目标方法 method 开始执行前,AOP 会回调此方法*/void before(Method method,Object[] args,Object target)throwsThrowable;}publicinterfaceAfterReturningAdviceextendsAfterAdvice{/***目标方法 method 执行后,AOP 会回调此方法,注意,它还传入了 method 的返回值*/void afterReturning(Object returnValue,Method method,Object[] args,Object target)throwsThrowable;}

1.2 Pointcut 方法的横切面

本接口用来定义需要增强的目标方法的集合,一般使用正则表达式去匹配筛选指定范围内的所有满足条件的目标方法。Pointcut 接口有很多实现,我们主要看一下 JdkRegexpMethodPointcut 和 NameMatchMethodPointcut 的实现原理,前者主要通过正则表达式对方法名进行匹配,后者则通过匹配方法名进行匹配。

// JdkRegexpMethodPointcut 的实现源码privatePattern[] compiledPatterns =newPattern[0];protectedboolean matches(String pattern,int patternIndex){Matcher matcher =this.compiledPatterns[patternIndex].matcher(pattern);return matcher.matches();}// NameMatchMethodPointcut 的实现源码privateList<String> mappedNames =newLinkedList<String>();publicboolean matches(Method method,Class targetClass){for(String mappedName :this.mappedNames){if(mappedName.equals(method.getName())|| isMatch(method.getName(), mappedName)){returntrue;}}returnfalse;}

1.3 Advisor 通知器

将 Pointcut 和 Advice 有效地结合在一起。它定义了在哪些方法(Pointcut)上执行哪些动作(Advice)。下面看一下 DefaultPointcutAdvisor 的源码实现,它通过持有 Pointcut 和 Advice 属性来将两者有效地结合在一起。

publicclassDefaultPointcutAdvisorextendsAbstractGenericPointcutAdvisorimplementsSerializable{privatePointcut pointcut =Pointcut.TRUE;publicDefaultPointcutAdvisor(){}publicDefaultPointcutAdvisor(Advice advice){this(Pointcut.TRUE, advice);}/***自己定义了Pointcut属性,而Advice属性则使用父类中的定义*/publicDefaultPointcutAdvisor(Pointcut pointcut,Advice advice){this.pointcut = pointcut;        setAdvice(advice);}}publicabstractclassAbstractGenericPointcutAdvisorextendsAbstractPointcutAdvisor{//本类是一个抽象类,其持有 Advice 的引用,而对 Pointcut 的引用,则在具体的子类中持有privateAdvice advice;publicvoid setAdvice(Advice advice){this.advice = advice;}publicAdvice getAdvice(){returnthis.advice;}@OverridepublicString toString(){return getClass().getName()+": advice ["+ getAdvice()+"]";}}

2 Spring AOP 的设计与实现

AOP 的实现代码中,主要使用了 JDK 动态代理,在特定场景下(被代理对象没有 implements 的接口)也用到了 CGLIB 生成代理对象。通过 AOP 的源码设计可以看到,其先为目标对象建立了代理对象,这个代理对象的生成可以使用 JDK 动态代理或 CGLIB 完成。然后启动为代理对象配置的拦截器,对横切面(目标方法集合)进行相应的增强,将 AOP 的横切面设计和 Proxy 模式有机地结合起来,实现了在 AOP 中定义好的各种织入方式。

2.1 ProxyFactoryBean

这里我们主要以 ProxyFactoryBean 的实现为例,对 AOP 的实现原理进行分析。ProxyFactoryBean 主要持有目标对象 target 的代理对象 aopProxy,和 Advisor 通知器,而 Advisor 持有 Advice 和 Pointcut,这样就可以判断 aopProxy 中的方法 是否是某个指定的切面 Pointcut,然后根据其配置的织入方向(前置增强/后置增强),通过反射为其织入相应的增强行为 Advice。先看一下 ProxyFactoryBean 的配置和使用。

<!-- 定义自己的 Advisor 实现,其中包含了 Pointcut 和 Advice --><beanid="myAdvisor"class="com.shuitu.MyAdvisor"/><beanid="myAOP"class="org.springframework.aop.framework.ProxyFactoryBean"><!-- 代理类实现的接口 --><propertyname="proxyInterface"><value>com.shuitu.ProxyInterface</value></property><!-- 被代理的对象 --><propertyname="target"><beanclass="com.shuitu.MyTarget"/></property><!-- 配置相应的 Advisor --><propertyname="interceptorNames"><list><value>myAdvisor</value></list></property></bean>

2.2 为配置的 target 生成 AopProxy 代理对象

ProxyFactoryBean 的 getObject() 方法先对通知器链进行了初始化,然后根据被代理对象类型的不同,生成代理对象。

/***返回一个代理对象,当用户从FactoryBean中获取 bean 时调用,*创建此工厂要返回的 AOP 代理的实例,该实例将作为一个单例被缓存*/publicObject getObject()throwsBeansException{// 初始化通知器链        initializeAdvisorChain();// 这里对 Singleton 和 prototype 的类型进行区分,生成对应的 proxyif(isSingleton()){return getSingletonInstance();}else{if(this.targetName ==null){                logger.warn("Using non-singleton proxies with singleton targets is often undesirable. "+"Enable prototype proxies by setting the 'targetName' property.");}return newPrototypeInstance();}}

2.3 初始化 Advisor 链

/***初始化Advisor链,可以发现,其中有通过对IoC容器的 getBean()方法的调用来获取配置好的 advisor 通知器*/privatesynchronizedvoid initializeAdvisorChain()throwsAopConfigException,BeansException{// 如果通知器链已经完成初始化,则直接返回if(this.advisorChainInitialized){return;}if(!ObjectUtils.isEmpty(this.interceptorNames)){if(this.beanFactory ==null){thrownewIllegalStateException("No BeanFactory available anymore (probably due to serialization) "+"- cannot resolve interceptor names "+Arrays.asList(this.interceptorNames));}if(this.interceptorNames[this.interceptorNames.length -1].endsWith(GLOBAL_SUFFIX)&&this.targetName ==null&&this.targetSource == EMPTY_TARGET_SOURCE){thrownewAopConfigException("Target required after globals");}// 这里添加了 Advisor 链的调用,下面的 interceptorNames 是在配置文件中// 通过 interceptorNames 进行配置的。由于每一个 Advisor 都是被配置为 bean 的,// 所以通过遍历 interceptorNames 得到的 name,其实就是 bean 的 id,通过这个 name(id)// 我们就可以从 IoC 容器中获取对应的实例化 beanfor(String name :this.interceptorNames){if(logger.isTraceEnabled()){                    logger.trace("Configuring advisor or advice '"+ name +"'");}if(name.endsWith(GLOBAL_SUFFIX)){if(!(this.beanFactory instanceofListableBeanFactory)){thrownewAopConfigException("Can only use global advisors or interceptors with a ListableBeanFactory");}                    addGlobalAdvisor((ListableBeanFactory)this.beanFactory,                            name.substring(0, name.length()- GLOBAL_SUFFIX.length()));}else{// 对当前的 factoryBean 进行类型判断,是属于单例 bean 还是原型 beanObject advice;if(this.singleton ||this.beanFactory.isSingleton(name)){// 通过 beanFactory 的 getBean() 方法获取 advisor,// 这个 name 是从 interceptorNames 中获取的                        advice =this.beanFactory.getBean(name);}else{// 如果是原型 bean                        advice =newPrototypePlaceholderAdvisor(name);}                    addAdvisorOnChainCreation(advice, name);}}}this.advisorChainInitialized =true;}

生成 singleton 的代理对象在 getSingletonInstance 方法中完成,这是 ProxyFactoryBean 生成 AopProxy 代理对象的调用入口。代理对象会封装对 target 对象的调用,针对 target 对象的方法调用会被这里生成的代理对象所拦截。

2.4 生成单例代理对象

/***返回此类代理对象的单例实例,如果尚未创建该实例,则单例地创建它*/privatesynchronizedObject getSingletonInstance(){if(this.singletonInstance ==null){this.targetSource = freshTargetSource();if(this.autodetectInterfaces && getProxiedInterfaces().length ==0&&!isProxyTargetClass()){// 根据 AOP 框架来判断需要代理的接口Class targetClass = getTargetClass();if(targetClass ==null){thrownewFactoryBeanNotInitializedException("Cannot determine target class for proxy");}// 设置代理对象的接口                setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass,this.proxyClassLoader));}super.setFrozen(this.freezeProxy);// 这里会通过 AopProxy 来得到代理对象this.singletonInstance = getProxy(createAopProxy());}returnthis.singletonInstance;}/***通过 createAopProxy()方法返回的 aopProxy 获取代理对象*/protectedObject getProxy(AopProxy aopProxy){return aopProxy.getProxy(this.proxyClassLoader);}

上面的 createAopProxy() 方法,调用了 ProxyFactoryBean 的父类 ProxyCreatorSupport 中的实现。

publicclassProxyCreatorSupportextendsAdvisedSupport{privateAopProxyFactory aopProxyFactory;publicProxyCreatorSupport(){// 注意这里实例化的是一个 DefaultAopProxyFactory,所以下面的 createAopProxy() 方法// 中调用的也是 DefaultAopProxyFactory 的实现this.aopProxyFactory =newDefaultAopProxyFactory();}protectedfinalsynchronizedAopProxy createAopProxy(){if(!this.active){            activate();}//调用的是 DefaultAopProxyFactory 的实现return getAopProxyFactory().createAopProxy(this);}publicAopProxyFactory getAopProxyFactory(){returnthis.aopProxyFactory;}publicAopProxyFactory getAopProxyFactory(){returnthis.aopProxyFactory;}}

下面看一下 AopProxyFactory 接口的实现类 DefaultAopProxyFactory 的 createAopProxy(AdvisedSupport config)方法。

publicAopProxy createAopProxy(AdvisedSupportconfig)throwsAopConfigException{// AopProxy 代理对象的生成过程:// 首先从 AdvisedSupport 对象中获取配置的 target 目标对象的类型 targetClass,// 然后根据 targetClass 是否为接口采取不同的生成代理对象的策略if(config.isOptimize()||config.isProxyTargetClass()|| hasNoUserSuppliedProxyInterfaces(config)){Class targetClass =config.getTargetClass();if(targetClass ==null){thrownewAopConfigException("TargetSource cannot determine target class: "+"Either an interface or a target is required for proxy creation.");}/***!!!!!!!!!!!!!!!!!!!!!!!!!!*如果目标类是接口,则使用 JDK 动态代理,否则使用 CGLIB*!!!!!!!!!!!!!!!!!!!!!!!!!!*/if(targetClass.isInterface()){returnnewJdkDynamicAopProxy(config);}returnCglibProxyFactory.createCglibProxy(config);}else{returnnewJdkDynamicAopProxy(config);}}

可以看到其根据目标对象是否实现了接口,而决定是使用 JDK 动态代理 还是 CGLIB 去生成代理对象,而 AopProxy 接口的实现类也只有 JdkDynamicAopProxy 和 CglibAopProxy 这两个。

以上是 懂SpringAOP源码 的全部内容, 来源链接: utcz.com/z/509439.html

回到顶部