目录
一直在考虑从哪里开始梳理,看到Spring的Aop包就大概明白了。首先,虽然Aop不是Spring的第二大特性,但是并不是Spring的产物。看一下包就知道了:
包被分为两个部分,一个是aopalliance(Aop联盟)制定的概念或者接口定义;一个是springframework.aop,Spring对联盟提出的概念的一个实现。那么还是需要从几个Aop的概念开始,因为Spring就是对其进行实现。Spring Aop编码实现:
一、Spring Aop编码实现
还是使用动态代理的接口和实现:
public interface DemoService {
String doSomething(String arg);
String doOther(String arg);
}
public class DemoServiceImpl implements DemoService {
@Override
public String doSomething(String arg) {
System.out.println("doSomething!!!");
return "ok";
}
@Override
public String doOther(String arg) {
System.out.println("doOther!!!");
return "other";
}
}
public class AopAdvice /*extends AopInvocationException*/ implements MethodBeforeAdvice,
MethodInterceptor,
org.aopalliance.intercept.MethodInterceptor,
AfterReturningAdvice{
/**
* 前置Aop
* @param method 代理方法
* @param args 方法参数
* @param target 代理对象
* @throws Throwable
* @see MethodBeforeAdvice
*/
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("before 执行了!");
}
/**
* cglib代理特殊处理
* @param o 代理对象
* @param method 方法本身
* @param objects 方法参数
* @param methodProxy 代理对象
* @return
* @throws Throwable
*/
@Override
public Object intercept(Object o, Method method, Object[] objects,
MethodProxy methodProxy) throws Throwable {
System.out.println("实现cglib调用!");
Object invoke = methodProxy.invoke(o, objects);
return invoke;
}
/**
* Around Aop
* @param invocation 方法代理
* @return 执行返回
* @throws Throwable 异常
* @see org.aopalliance.intercept.MethodInterceptor
*/
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("Around 前执行了!");
Object proceed = invocation.proceed();
System.out.println("Around 后执行了!");
return proceed;
}
/**
* 后置 Aop
* @param returnValue 返回值
* @param method 方法
* @param args 参数
* @param target 代理对象
* @throws Throwable 异常
*/
@Override
public void afterReturning(Object returnValue, Method method, Object[] args,
Object target) throws Throwable {
System.out.println("afterReturning 执行了");
}
}
执行测试:
public class AopTest {
public static void main(String[] args) {
// 自动代理
ProxyFactory proxyFactory = new ProxyFactory();
// 目标对象(DemoServiceImpl)
proxyFactory.setTarget(new DemoServiceImpl());
// 增强(AopAdvice)
AopAdvice aopAdvice = new AopAdvice();
// proxyFactory.addAdvice();
// 切点(DemoStaticPointcutAdvisor)
DemoStaticPointcutAdvisor advisor = new DemoStaticPointcutAdvisor();
advisor.setAdvice(aopAdvice);
proxyFactory.addAdvisor(advisor);
// 从代理工厂 获取 切面
DemoService demoService = (DemoService)proxyFactory.getProxy();
System.out.println("----------------------------");
demoService.doSomething("kevin!");
System.out.println("----------------------------");
demoService.doOther("kevin!");
System.out.println("----------------------------");
}
}
执行结果:
二、Spring Aop概念分析
1、目标对象(TargetSource)
Spring Aop使用动态代理机制实现,那么目标对象就比较好理解(动态代理可以参见代理模式-静态代理、JDK和Cglib动态代理)。目标对象就是上面demo中的new DemoServiceImpl(),在Spring中目标对象用TargerSource进行表示,并且引入了很多子类,如下:
比如我们刚才demo中setTarget方法,如下:
public void setTarget(Object target) {
setTargetSource(new SingletonTargetSource(target));
}
@Override
public void setTargetSource(@Nullable TargetSource targetSource) {
this.targetSource = (targetSource != null ? targetSource : EMPTY_TARGET_SOURCE);
}
TargetSource结构如下,比较好理解:
public interface TargetSource extends TargetClassAware {
@Override
@Nullable
Class<?> getTargetClass();
boolean isStatic();
@Nullable
Object getTarget() throws Exception;
rows Exception if the object can't be released
void releaseTarget(Object target) throws Exception;
}
2、增强(Advice)
实现Aop我们可以在被代理的方法前执行,也可以在方法后执行,所以增强还是比较形象的。在Spring中使用Advice接口进行表示。如下:
如上大致可以分为,前置增强(BeforeAdvice)、后置增强(AfterAdvice)、环绕增强(Inteceptor下面的,主要包括MethodInteceptor的invoke回调方法实现的环绕增强,构造增强)、引介增强(DynamicInstroductionAdvice下面的,引介增强就是给目标对象织入没有的方法,拿到代理对象后就可以直接调用其他织入的方法)、AspectJ增强(AbstractAspectJAdvice)。
从上面的执行结果我们看到了执行顺序:
环绕增强(Around)的前增强: MethodInteceptor的invoke回调方法中,invocation.proceed();执行前的代码
前置增强(Before):MethodBeforeAdvice的before回调方法
后置增强(After):AfterReturningAdvice的after回调方法
环绕增强(Around)的后增强:MethodInteceptor的invoke回调方法中,invocation.proceed();执行后的代码
3、连接点(Joinpoint)
我们使用动态代理实现切面功能的时候,默认会对目标对象的所有的方法都进行增强,但是这很多时候并不是我们想要的,比如上面的时候。那么Spring中使用Pointcut表示需要进行增强的目标对象方法,并且Spring只支持方法级别的切面(不支持比如对访问一个字段的切面)。
4、切入点(Pointcut)
理解了连接点,切入点就是一组连接点的集合。
大致分为 DynamicMethodMatchPointcut(动态方法匹配切点)、ExpressionPointcut(Spring Expression的匹配切点)、AnnotationMatchingPointcut(注解匹配切点)、StaticMethodMatchPointcut(静态方法匹配切点)。静态方法连接点只需要变异完之后就可以确认,比如根据方法名称进行判断;动态匹配可能会对参数值进行动态判断等。每种匹配都用的还是比较多的,后面源码分析中非常多。
5、切面(Advisor)
切面就是在哪个切点上进行什么增强。所以我理解:切面 = 切点 + 增强 。在Spring中使用接口Advisor表示切面。主要又分为普通切面(PointcutAdvisor)和引介切面(IntroductionAdvisor)。而普通切面非常多,也经常见,如下:
- 1、StaticMethodMatcherPointcutAdvisor,静态方法匹配切点的切面还是很形象的,我们刚才使用的就是该切面
- 2、AbstractBeanFactoryPointcutAdvisor,Spring Bean工厂相关的切面,很多地方都在使用
- 3、RegexpMethodPointcutAdvisor,正则匹配方法切面
- 4、AspectJExpressionPointcutAdvisor,AspectJ使用Spring的Expression匹配的切面
- 5、NameMatchMethodPointcutAdvisor,匹配方法名称的拦截器
- 6、DefaultPointcutAdvisor,最常用的切面类型,它可以通过任意Pointcut和Advice定义一个切面,唯一不支持的就是引介的切面类型,一般可以通过扩展该类实现自定义的切面。
- 7、AsyncAnnotationAdvisor,我们使用@Async("aaa"),使方法在线程池异步执行,详细可以参见:Spring源码-@Async原理分析
- 8、TransactionAttributeSourceAdvisor,Spring的声明式事务使用的切面,详细可以参见:Spring源码-@EnableTransactionManagement方式事务实现分析(上)
6、织入
上面已经定义了在目标对象的哪些连接点(切点)干什么事(增强),那么这一系列组成的功能块,我理解为切面。比如,我使用Aop实现了一个方法性能监控组件。