基本概念:
- AOP( Aspect-Oriented Programming):直译过来就是面向切面编程。最早是由AOP联盟(AOP Alliance)组织提出来的概念。解决的问题场景:将一些公共代码(日志记录,性能统计,安全控制,事务处理,异常处理等等)抽离出来,系统运行时可动态的应用到业务系统上。
- 通知(Advice):也称增强,用于实现增强功能的.
- 连接点(Joinpoint):在匹配目标的哪个位置做增强(before、after、around、return、throw).
- 切点(Pointcut):用于匹配类或方法,一个切点可以对应多个连接点.
- 织入 (Weaving):织入是把切面应用到目标对象,一般是通过代理对象实现.
Spring中另外两个术语:
- Advisor:可以理解为是个组件,包含advice和pointcut两个组件
- Advised:它是spring AOP代理工厂的配置类接口,负责操作和管理 Advisor 的
Spring AOP与AspectJ:
AOP是一种概念,Spring AOP和AspectJ都实现了AOP;Spring使用了AspectJ的部分API,生成代理对象Spring用的是JDK动态代理和CGLIB,而AspectJ是通过修改字节码来完成。
Aspectj可参考另外博文:Java Agent【java探针】及AspectJ-优快云博客
PointCut继承体系:
Pointcut:有两部分组成:ClassFilter 、MethodMatcher;ClassFilter用于过滤Class;MethodMatcher用于匹配方法
package org.springframework.aop
import org.springframework.aop.ClassFilter;
import org.springframework.aop.MethodMatcher;
/**
* Pointcut由ClassFilter和MethodMatcher构成
*/
public interface Pointcut {
/**
* 返回用于匹配Class的过滤器
*/
ClassFilter getClassFilter();
/**
* 返回用于匹配方法的过滤器
*/
MethodMatcher getMethodMatcher();
/**
* Pointcut实例: 切点可以匹配适用于所有Class以及方法
*/
Pointcut TRUE = TruePointcut.INSTANCE;
}
package org.spring.aop.pointcut;
import org.springframework.aop.IntroductionAdvisor;
/**
* 切点与目标Class做匹配的过滤器
*
* 可以用作{@link Pointcut}的一部分功能,也可以用在引介增强{@link IntroductionAdvisor}匹配目标类
* 在Spring AOP中主要是为目标类的原有方法增强功能,但是还有一种特殊增强叫引介增强,它不是增强原有的方法而是为原有目标类增加新的方法。
*/
public interface ClassFilter {
/**
* 切点与目标Class进行匹配,判断切点与其是否匹配适用
*/
boolean matches(Class<?> clazz);
/**
* ClassFilter实例,切点可以匹配适用于所有目标Class
*/
ClassFilter TRUE = TrueClassFilter.INSTANCE;
}
package org.springframework.aop;
import java.lang.reflect.Method;
/**
* 切点与目标方法做匹配的过滤器
*/
public interface MethodMatcher {
/**
* 静态匹配:只匹配方法对象
*/
boolean matches(Method method, Class<?> targetClass);
/**
* 标注动态匹配的,如果返回true,进行动态匹配;返回false,不需要动态匹配
*/
boolean isRuntime();
/**
* 动态匹配:匹配方法对象和方法参数对象
* 匹配方法:匹配名称、方法注解、方法返回类型、方法返回类型的注解
* 匹配参数:匹配参数个数、参数的类型、参数类型的注解
*/
boolean matches(Method method, Class<?> targetClass, Object[] args);
/**
* MethodMatcher实例,切点可以匹配适用于所有目标方法
*/
MethodMatcher TRUE = TrueMethodMatcher.INSTANCE;
}
MethodMatcher有个特殊子类IntroductionAwareMethodMatcher,处理<引介增强>这种特殊情况。
<引介增强>与Spring AOP中的普通增强有些不同,普通增强是为目标类的原有方法增强功能,而引介增强是为目标类增加新方法来达到增强的能力
/**
* MethodMatcher的一种特殊子接口。对方法进行匹配时,将<引介增强>考虑进去,做一些特殊逻辑处理
*/
public interface IntroductionAwareMethodMatcher extends MethodMatcher {
/**
* 与目标方法进行静态匹配时.将<引介增强>因素考虑进去
*
* @param hasIntroductions
* 是否有<引介增强>
* @return
*/
boolean matches(Method method, Class<?> targetClass, boolean hasIntroductions);
}
定义一个普通类,用于演示用例
import org.springframework.transaction.annotation.Transactional;
public class UserService {
@Transactional
public void say() {
System.out.println("Hello World!!");
}
}
自定义类,实现接口Pointcut, ClassFilter, MethodMatcher
import org.springframework.aop.Pointcut;
import org.springframework.aop.ClassFilter;
import org.springframework.aop.MethodMatcher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.lang.reflect.Method;
public class CustomPointcut implements Pointcut, ClassFilter, MethodMatcher {
//---------------------------------------------------------------------
// Implementation of Pointcut
//---------------------------------------------------------------------
@Override
public ClassFilter getClassFilter() {
return this;
}
@Override
public MethodMatcher getMethodMatcher() {
return this;
}
//---------------------------------------------------------------------
// Implementation of ClassFilter
//---------------------------------------------------------------------
@Override
public boolean matches(Class<?> clazz) {
//判断目标类是否存在注解@Service
if (clazz.isAnnotationPresent(Service.class)) {
return true;
}
return false;
}
//---------------------------------------------------------------------
// Implementation of MethodMatcher
//---------------------------------------------------------------------
@Override
public boolean matches(Method method, Class<?> targetClass) {
//判断目标方法是否存在注解@Transactional
if (method.isAnnotationPresent(Transactional.class)) {
return true;
}
return false;
}
@Override
public boolean isRuntime() {
return false;
}
@Override
public boolean matches(Method method, Class<?> targetClass, Object[] args) {
throw new UnsupportedOperationException("Illegal MethodMatcher usage");
}
}
测试代码:
public static void main(String[] args) throws Exception {
CustomPointcut pointcut = new CustomPointcut();
boolean matchResult = pointcut.matches(UserService.class);
System.out.println("ClassFilter.matches(Class<?>)===匹配结果==>" + matchResult);
Method method = UserService.class.getDeclaredMethod("say", new Class[]{String.class});
matchResult = pointcut.matches(method, UserService.class);
System.out.println("MethodMatcher.matches(Method, Class<?>)===匹配结果==>" + matchResult);
matchResult = pointcut.matches(method, UserService.class, new Class[]{String.class});
System.out.println("MethodMatcher.matches(Method, Class<?>, args)===匹配结果==>" + matchResult);
}
执行结果:
Spring2.0开始引入AspectJ,AspectJExpressionPointcut是Spring基于AspectJ表达式而实现的一个Pointcut,AspectJExpressionPointcut在目前spring中使用非常频繁,所以非常重要。
package org.springframework.aop.aspectj;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.weaver.BCException;
import org.aspectj.weaver.patterns.NamePattern;
import org.aspectj.weaver.reflect.ReflectionWorld.ReflectionWorldException;
import org.aspectj.weaver.reflect.ShadowMatchImpl;
import org.aspectj.weaver.tools.ContextBasedMatcher;
import org.aspectj.weaver.tools.FuzzyBoolean;
import org.aspectj.weaver.tools.JoinPointMatch;
import org.aspectj.weaver.tools.MatchingContext;
import org.aspectj.weaver.tools.PointcutDesignatorHandler;
import org.aspectj.weaver.tools.PointcutExpression;
import org.aspectj.weaver.tools.PointcutParameter;
import org.aspectj.weaver.tools.PointcutParser;
import org.aspectj.weaver.tools.PointcutPrimitive;
import org.aspectj.weaver.tools.ShadowMatch;
import org.springframework.aop.ClassFilter;
import org.springframework.aop.IntroductionAwareMethodMatcher;
import org.springframework.aop.MethodMatcher;
import org.springframework.aop.ProxyMethodInvocation;
import org.springframework.aop.framework.autoproxy.ProxyCreationContext;
import org.springframework.aop.interceptor.ExposeInvocationInterceptor;
import org.springframework.aop.support.AbstractExpressionPointcut;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
/**
* 基于AspectJ表达式功能实现的一个Pointcut子类
* @since 2.0
*/
public class AspectJExpressionPointcut extends AbstractExpressionPointcut
implements ClassFilter, IntroductionAwareMethodMatcher, BeanFactoryAware {
private static final Set<PointcutPrimitive> SUPPORTED_PRIMITIVES = new HashSe