spring---aop(7)---Spring AOP中expose-proxy介绍
写在前面
expose-proxy。为是否暴露当前代理对象为ThreadLocal模式。
SpringAOP对于最外层的函数只拦截public方法,不拦截protected和private方法(后续讲解),另外不会对最外层的public方法内部调用的其他方法也进行拦截,即只停留于代理对象所调用的方法。
案例分析
public class AServiceImpl implements AService{
@Override
public void barA() {
System.out.println("AServiceImpl.barA()");
barB();
}
@Override
public void barB() {
System.out.println("AServiceImpl.barB()");
}
}
控制台的输出结果:
run my before advice
AServiceImpl.barA()
AServiceImpl.barB()
分析:
发现aop并没有对barB方法进行增强,只是增强了barA方法。
判断上述this.barB()方法是否被拦截的最本质的东西是看this到底是谁?有如下对象B类的对象b,和cglib生成的代理对象bProxy,代理对象bProxy内部拥有b。如果调用b对象的任何方法,肯定不会发生任何拦截,当调用bProxy的方法则都会进入拦截函数。
当我们调用bProxy对象的barA()方法时,先执行cglib之前设置的callback对象的intercept拦截函数,如下: (之前的文章已经分析过代码)
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
Class<?> targetClass = null;
Object target = null;
try {
if (this.advised.exposeProxy) {
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
target = getTarget();
if (target != null) {
targetClass = target.getClass();
}
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object retVal;
if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
retVal = methodProxy.invoke(target, args);
}
else {
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
}
retVal = processReturnType(proxy, target, method, retVal);
return retVal;
}
finally {
if (target != null) {
releaseTarget(target);
}
if (setProxyContext) {
AopContext.setCurrentProxy(oldProxy);
}
}
}
这个过程之前的文章已经分析过,这里就是首先取出拦截器链List<Object> chain,当barA方法不符合我们所配置的pointcut时,拦截器链必然为空,然后就是直接执行目标对象的方法。
当barA方法符合所配置的pointcut时,拦截器链不为空,执行相应的通知advice,currentInterceptorIndex 从-1开始,如下(之前的文章已经分析过代码)
public Object proceed() throws Throwable {
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
return proceed();
}
}
else {
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
随着通知不断的传递执行,最终this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1将会满足条件,将会来到执行目标对象的方法invokeJoinpoint():
protected Object invokeJoinpoint() throws Throwable {
if (this.publicMethod) {
return this.methodProxy.invoke(this.target, this.arguments);
}
else {
return super.invokeJoinpoint();
}
}
在这里不管要拦截的目标方法是不是public方法,最终所传递的对象都是this.target,他是目标对象而不是代理对象,即执行上述barA()函数的对象是目标对象而不是代理对象,所以它内部所调用的this.barB()也是目标对象,因此不会发生拦截,如果是执行的是代理对象.barB()则必然会进入intercept拦截过程。所以上述调用barA函数,其内部调用的barB函数是不会发生拦截的,因为this指的是目标对象,不是代理对象。
实现BarB拦截
如果你想实现barA调用时内部的BarB也进行拦截,就必须把this换成代理对象。这时就要用到了,xml配置中的expose-proxy="true",即暴露出代理对象,它使用的是ThreadLocal设计模式,我们可以这样获取代理对象,AopContext.currentProxy()就是代理对象,然后转换成目标对象或者目标接口,执行相应的方法:
public class AServiceImpl implements AService{
@Override
public void barA() {
System.out.println("AServiceImpl.barA()");
AService proxy=(AService) AopContext.currentProxy();
proxy.barB();
}
@Override
public void barB() {
System.out.println("AServiceImpl.barB()");
}
}
<bean id="aServiceImplProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="exposeProxy">
<value>true</value>
</property>
<property name="interfaces" value="com.xxx.plus.aop.demo.AService"/>
<property name="target">
<ref bean="aServiceImpl"/>
</property>
<property name="interceptorNames">
<list>
<value>myBeforAdvice</value>
</list>
</property>
</bean>
执行结果:
run my before advice
AServiceImpl.barA()
run my before advice
AServiceImpl.barB()
分析:
barA()和barB都被aop拦截实现了增强
最后再给出Spring的文档说明:
Due to the proxy-based nature of Spring’s AOP framework, protected methods are by definition not intercepted, neither for JDK proxies (where this isn’t applicable) nor for CGLIB proxies (where this is technically possible but not recommendable for AOP purposes). As a consequence, any given pointcut will be matched against public methods only!
If your interception needs include protected/private methods or even constructors, consider the use of Spring-driven native AspectJ weaving instead of Spring’s proxy-based AOP framework. This constitutes a different mode of AOP usage with different characteristics, so be sure to make yourself familiar with weaving first before making a decision.
spring---aop(7)---Spring AOP中expose-proxy介绍的更多相关文章
- AOP 与 Spring中AOP使用(上)
AOP简介 在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程, 通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术. AOP是OOP的延续 ...
- JavaWeb_(Spring框架)认识Spring中的aop
1.aop思想介绍(面向切面编程):将纵向重复代码,横向抽取解决,简称:横切 2.Spring中的aop:无需我们自己写动态代理的代码,spring可以将容器中管理对象生成动态代理对象,前提是我们对他 ...
- 你知道Spring是怎么将AOP应用到Bean的生命周期中的吗?
聊一聊Spring是怎么将AOP应用到Bean的生命周期中的? 本系列文章: 听说你还没学Spring就被源码编译劝退了?30+张图带你玩转Spring编译 读源码,我们可以从第一行读起 你知道Spr ...
- 【spring 5】AOP:spring中对于AOP的的实现
在前两篇博客中,介绍了AOP实现的基础:静态代理和动态代理,这篇博客介绍spring中AOP的实现. 一.采用Annotation方式 首先引入jar包:aspectjrt.jar && ...
- spring aop方式配置事务中的三个概念 pointcut advice advisor
AOP的3个关键概念 因为AOP的概念难于理解,所以在前面首先对Java动态代理机制进行了一下讲解,从而使读者能够循序渐进地来理解AOP的思想. 学习AOP,关键在于理解AOP的思想,能够使用AOP. ...
- AOP 与 Spring中AOP使用(下)
AOP通知类型 前置通知 在目标方法执行之前进行操作 UserDao.java public class UserDao { public void add(){ System.out.println ...
- spring(六):spring中AOP的基本使用
AOP:面向切面编程[底层使用动态代理实现],就是在运行期间动态的将某段代码切入到方法的指定位置进行运行的编程方式 基本使用 使用AOP功能需要引入spring的aop以及aspects相关包 < ...
- 04 Spring:01.Spring框架简介&&02.程序间耦合&&03.Spring的 IOC 和 DI&&08.面向切面编程 AOP&&10.Spring中事务控制
spring共四天 第一天:spring框架的概述以及spring中基于XML的IOC配置 第二天:spring中基于注解的IOC和ioc的案例 第三天:spring中的aop和基于XML以及注解的A ...
- Spring aop报错:com.sun.proxy.$Proxy cannot be cast to xxx
准备使用AOP记录所有NamedParameterJdbcTemplate操作数据时的所有日志,没想到出现这个错误,折腾了好久,终于找出原因 解决方案:在 aop-config配置添加上: proxy ...
- Spring的IOC和AOP之深剖
今天,既然讲到了Spring 的IOC和AOP,我们就必须要知道 Spring主要是两件事: 1.开发Bean:2.配置Bean.对于Spring框架来说,它要做的,就是根据配置文件来创建bean实例 ...
随机推荐
- mysql高可用架构 -> MHA简介-01
作者简介 松信嘉範:MySQL/Linux专家2001年索尼公司入职2001年开始使用oracle2004年开始使用MySQL2006年9月-2010年8月MySQL从事顾问2010年-2012年 D ...
- docker stack 部署 mysql 5.6
=============================================== 2018/7/1_第1次修改 ccb_warlock === ...
- vue总结 08状态管理vuex
状态管理 类 Flux 状态管理的官方实现 由于状态零散地分布在许多组件和组件之间的交互中,大型应用复杂度也经常逐渐增长.为了解决这个问题,Vue 提供 vuex:我们有受到 Elm 启发的状态管 ...
- geoserver 启动闪退
跟JDK版本有关: 比如geoserver2.11需要JDK版本为JDK1.8 windows配置两个jdk环境: 网上有方法,但如果只需要满足geoserver的话,可以只安装jdk(注意jdk和j ...
- Java线程:新特征-有返回值的线程《转》
原始文章 在Java5之前,线程是没有返回值的,常常为了“有”返回值,破费周折,而且代码很不好写.或者干脆绕过这道坎,走别的路了. 现在Java终于有可返回值的任务(也可以叫做线程)了. ...
- thinkphp辅助方法,数据库操作
- MongoDB查询用法大全
转载 http://blog.163.com/lgh_2002/blog/static/440175262012052116455/ 详见官方的手册: http://www.mongodb.org/d ...
- Android发送短信界面
package com.example.wang.application1; import android.os.Bundle; import android.support.v7.app.AppCo ...
- chromiumFx编译使用
CEF chormeFx 为针对.Net的CEF框架,下载链接为: https://bitbucket.org/chromiumfx/chromiumfx 点击Download可以下载chromium ...
- c++模板与泛型编程基础
(1)定义函数模板(function template) 函数模板是一个独立于类型的函数,可以产生函数的特定类型版本. // implement strcmp-like generic compare ...