在之前的三篇文章中已经梳理了spring aop的核心内容:
- AnnotationAwareAspectJAutoProxyCreator的注入
- AnnotationAwareAspectJAutoProxyCreator获取Advisor集、bean匹配、创建代理等
- 切面拦截器的执行流程
但是由于时间和个人水平限制,有几个内容记录的不是很详细,比如:
- 事件通知何时创建
- cglib代理的原理
- Pointcut如何匹配
本文将继续阅读spring aop源码,并结合示例代码,深入分析上述的问题。
创建事件通知
创建代理回顾
前面的文章分析过,创建代理入口在AbstractAutoProxyCreator的postProcessAfterInitialization方法:
// Create a proxy with the configured interceptors
// if the bean is identified as one to proxy by the subclass.
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// 略
// 获取通知
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 创建代理
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// Return whether the given bean is to be proxied,
// what additional advices (e.g. AOP Alliance interceptors) and advisors to apply.
protected Object[] getAdvicesAndAdvisorsForBean(
Class<?> beanClass, String beanName, TargetSource targetSource) {
List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
if (advisors.isEmpty()) {
return DO_NOT_PROXY;
}
return advisors.toArray();
}
// Find all eligible Advisors for auto-proxying this class.
// 查找可以用于当前bean的所有通知
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
// 查找所有通知,此方法里面有查找、创建通知的逻辑
List<Advisor> candidateAdvisors = findCandidateAdvisors();
// 查找可以用于当前bean的所有通知,下一章节分析这个方法
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
// 排序
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
查找所有通知集
查找、创建通知的逻辑在findCandidateAdvisors方法中:
// Find all candidate Advisors to use in auto-proxying.
protected List<Advisor> findCandidateAdvisors() {
// Add all the Spring advisors found according to superclass rules.
List<Advisor> advisors = super.findCandidateAdvisors();
// Build Advisors for all AspectJ aspects in the bean factory.
if (this.aspectJAdvisorsBuilder != null) {
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}
aspectJAdvisorsBuilder.buildAspectJAdvisors方法:
- Look for AspectJ-annotated aspect beans in the current bean factory, and return to a list of Spring AOP Advisors representing them.
- Creates a Spring Advisor for each AspectJ advice method.
public List<Advisor> buildAspectJAdvisors() {
List<String> aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
synchronized (this) {
aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
List<Advisor> advisors = new ArrayList<>();
aspectNames = new ArrayList<>();
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Object.class, true, false);
for (String beanName : beanNames) {
if (!isEligibleBean(beanName)) {
continue;
}
// We must be careful not to instantiate beans eagerly as in this case they
// would be cached by the Spring container but would not have been weaved.
Class<?> beanType = this.beanFactory.getType(beanName, false);
if (beanType == null) {
continue;
}
// 判断是切面bean
if (this.advisorFactory.isAspect(beanType)) {
aspectNames.add(beanName);
AspectMetadata amd = new AspectMetadata(beanType, beanName);
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
MetadataAwareAspectInstanceFactory factory =
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
if (this.beanFactory.isSingleton(beanName)) {
this.advisorsCache.put(beanName, classAdvisors);
} else {
this.aspectFactoryCache.put(beanName, factory);
}
advisors.addAll(classAdvisors);
} else {
// Per target or per this.
if (this.beanFactory.isSingleton(beanName)) {
throw new IllegalArgumentException("...");
}
MetadataAwareAspectInstanceFactory factory =
new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
this.aspectFactoryCache.put(beanName, factory);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
}
this.aspectBeanNames = aspectNames;
return advisors;
}
}
}
if (aspectNames.isEmpty()) {
return Collections.emptyList();
}
List<Advisor> advisors = new ArrayList<>();
for (String aspectName : aspectNames) {
List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
if (cachedAdvisors != null) {
advisors.addAll(cachedAdvisors);
} else {
MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
return advisors;
}
getAdvisors
ReflectiveAspectJAdvisorFactory.getAdvisors方法:
// Build Spring AOP Advisors for all annotated At-AspectJ methods on the specified aspect instance.
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
validate(aspectClass);
// We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
// so that it will only instantiate once.
MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
List<Advisor> advisors = new ArrayList<>();
// 获取到Aspect Bean中的切面方法,比如被@Before、@After等
for (Method method : getAdvisorMethods(aspectClass)) {
// 创建Advisor
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName);
if (advisor != null) {
advisors.add(advisor);
}
}
// If it's a per target aspect, emit the dummy instantiating aspect.
// Aspect Bean为prototype时执行此分支
if (!advisors.isEmpty() &&
lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
Advisor instantiationAdvisor =
new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
advisors.add(0, instantiationAdvisor);
}
// Find introduction fields.
// IntroductionAdvisor和@DeclareParents注解支持
for (Field field : aspectClass.getDeclaredFields()) {
Advisor advisor = getDeclareParentsAdvisor(field);
if (advisor != null) {
advisors.add(advisor);
}
}
return advisors;
}
// Build a Spring AOP Advisor for the given AspectJ advice method.
public Advisor getAdvisor(
Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
int declarationOrderInAspect, String aspectName) {
// 创建AspectJExpressionPointcut
// 这个Pointcut实现支持@annotation(..)、execution(..)表达式
AspectJExpressionPointcut expressionPointcut = getPointcut(
candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
if (expressionPointcut == null) {
return null;
}
// 创建Advisor
return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}
创建Advisor和Advice
public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut,
Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory,
MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
this.declaredPointcut = declaredPointcut;
this.declaringClass = aspectJAdviceMethod.getDeclaringClass();
this.methodName = aspectJAdviceMethod.getName();
this.parameterTypes = aspectJAdviceMethod.getParameterTypes();
this.aspectJAdviceMethod = aspectJAdviceMethod;
// ReflectiveAspectJAdvisorFactory对象
this.aspectJAdvisorFactory = aspectJAdvisorFactory;
this.aspectInstanceFactory = aspectInstanceFactory;
this.declarationOrder = declarationOrder;
this.aspectName = aspectName;
if (aspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
// 略
} else {
// A singleton aspect.
this.pointcut = this.declaredPointcut;
this.lazy = false;
// 创建Advisor
this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
}
}
private Advice instantiateAdvice(AspectJExpressionPointcut pointcut) {
Advice advice = this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pointcut,
this.aspectInstanceFactory, this.declarationOrder, this.aspectName);
return (advice != null ? advice : EMPTY_ADVICE);
}
创建Advice
创建Advice
aspectJAdvisorFactory.getAdvice创建Advice对象:
public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
validate(candidateAspectClass);
AspectJAnnotation<?> aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
if (aspectJAnnotation == null) {
return null;
}
// 判断目标类是Aspect
if (!isAspect(candidateAspectClass)) {
throw new AopConfigException("...");
}
AbstractAspectJAdvice springAdvice;
switch (aspectJAnnotation.getAnnotationType()) {
case AtPointcut:
// 方法被Pointcut标注,什么都不做
return null;
case AtAround:
// Around通知
springAdvice = new AspectJAroundAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtBefore:
// Before通知
springAdvice = new AspectJMethodBeforeAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtAfter:
// After通知
springAdvice = new AspectJAfterAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtAfterReturning:
// AfterReturning通知
springAdvice = new AspectJAfterReturningAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
if (StringUtils.hasText(afterReturningAnnotation.returning())) {
// 设置return注入参数名
springAdvice.setReturningName(afterReturningAnnotation.returning());
}
break;
case AtAfterThrowing:
// AfterThrowing通知
springAdvice = new AspectJAfterThrowingAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
// 设置throw注入参数名
springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
}
break;
default:
throw new UnsupportedOperationException("...");
}
// Now to configure the advice...
springAdvice.setAspectName(aspectName);
springAdvice.setDeclarationOrder(declarationOrder);
String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
if (argNames != null) {
// 切面方法参数列表名称
springAdvice.setArgumentNamesFromStringArray(argNames);
}
springAdvice.calculateArgumentBindings();
return springAdvice;
}
AspectJAroundAdvice
AspectJMethodBeforeAdvice
AspectJAfterAdvice
AspectJAfterReturningAdvice
AspectJAfterThrowingAdvice
匹配事件通知
上一章节,介绍了创建、查找通知的逻辑,查找到通知后,就需要将通知与当前Bean进行匹配,以确定是否需要为当前Bean创建代理。
入口
// 查找可以用于当前bean的所有通知
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
List<Advisor> candidateAdvisors = findCandidateAdvisors();
// 查找可以用于当前bean的所有通知
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
// 排序
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
// Search the given candidate Advisors to find all Advisors that can apply to the specified bean.
protected List<Advisor> findAdvisorsThatCanApply(
List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
ProxyCreationContext.setCurrentProxiedBeanName(beanName);
try {
return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
} finally {
ProxyCreationContext.setCurrentProxiedBeanName(null);
}
}
通知匹配
AopUtils.findAdvisorsThatCanApply方法:
// Determine the sublist of the candidateAdvisors list that is applicable to the given class.
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
List<Advisor> eligibleAdvisors = new ArrayList<>();
// 匹配IntroductionAdvisor
for (Advisor candidate : candidateAdvisors) {
if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
eligibleAdvisors.add(candidate);
}
}
boolean hasIntroductions = !eligibleAdvisors.isEmpty();
// 匹配非IntroductionAdvisor
for (Advisor candidate : candidateAdvisors) {
if (candidate instanceof IntroductionAdvisor) {
// already processed
continue;
}
if (canApply(candidate, clazz, hasIntroductions)) {
eligibleAdvisors.add(candidate);
}
}
return eligibleAdvisors;
}
public static boolean canApply(Advisor advisor, Class<?> targetClass) {
return canApply(advisor, targetClass, false);
}
public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
if (advisor instanceof IntroductionAdvisor) {
return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
} else if (advisor instanceof PointcutAdvisor) {
// 在上一章节介绍了,spring aop创建的是InstantiationModelAwarePointcutAdvisorImpl对象
// Pointcut是AspectJExpressionPointcut对象
PointcutAdvisor pca = (PointcutAdvisor) advisor;
return canApply(pca.getPointcut(), targetClass, hasIntroductions);
} else {
return true;
}
}
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
if (!pc.getClassFilter().matches(targetClass)) {
return false;
}
// methodMatcher是AspectJExpressionPointcut对象
// 里面封装着切面表达式和切入点信息
MethodMatcher methodMatcher = pc.getMethodMatcher();
if (methodMatcher == MethodMatcher.TRUE) {
return true;
}
IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
}
Set<Class<?>> classes = new LinkedHashSet<>();
if (!Proxy.isProxyClass(targetClass)) {
classes.add(ClassUtils.getUserClass(targetClass));
}
classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
for (Class<?> clazz : classes) {
Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
for (Method method : methods) {
// 判断与目标方法是否匹配
if (introductionAwareMethodMatcher != null ?
introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
methodMatcher.matches(method, targetClass)) {
return true;
}
}
}
return false;
}
AspectJExpressionPointcut
实现了AbstractExpressionPointcut和IntroductionAwareMethodMatcher接口。
这个类里面封装着:
- PointcutExpression - 当前切面表达式对象,这个类由aspectj提供,底层使用aspectj框架的api做的切面匹配
- String expression - 当前切面表达式字符串
- BeanFactory - spring工厂
- Class pointcutDeclarationScope - 当前切面类,可以用于获取@Pointcut信息
看一下match方法:
public boolean matches(Method method, Class<?> targetClass, boolean hasIntroductions) {
// 封装PointcutExpression
obtainPointcutExpression();
// 匹配
ShadowMatch shadowMatch = getTargetShadowMatch(method, targetClass);
if (shadowMatch.alwaysMatches()) {
return true;
} else if (shadowMatch.neverMatches()) {
return false;
} else {
if (hasIntroductions) {
return true;
}
RuntimeTestWalker walker = getRuntimeTestWalker(shadowMatch);
return (!walker.testsSubtypeSensitiveVars() || walker.testTargetInstanceOfResidue(targetClass));
}
}
private PointcutExpression obtainPointcutExpression() {
if (this.pointcutExpression == null) {
this.pointcutClassLoader = determinePointcutClassLoader();
// 构建PointcutExpression
this.pointcutExpression = buildPointcutExpression(this.pointcutClassLoader);
}
return this.pointcutExpression;
}
// 构建PointcutExpression
// 使用aspectj框架的api
// 不做深入解析了
private PointcutExpression buildPointcutExpression(ClassLoader classLoader) {
PointcutParser parser = initializePointcutParser(classLoader);
// 解析切面方法的参数列表
PointcutParameter[] pointcutParameters = new PointcutParameter[this.pointcutParameterNames.length];
for (int i = 0; i < pointcutParameters.length; i++) {
pointcutParameters[i] = parser.createPointcutParameter(
this.pointcutParameterNames[i], this.pointcutParameterTypes[i]);
}
// 构建PointcutExpression
// 第1个参数是切面字符串表达式
// 第2个参数是切面类Class对象,用于获取@Pointcut信息
// 第3个参数是切面的参数列表
return parser.parsePointcutExpression(replaceBooleanOperators(resolveExpression()),
this.pointcutDeclarationScope, pointcutParameters);
}
private ShadowMatch getTargetShadowMatch(Method method, Class<?> targetClass) {
// ...
// 使用PointcutExpression来匹配目标方法
return getShadowMatch(targetMethod, method);
}
匹配目标方法的逻辑封装在aspectj框架中,此处就不继续深入分析了,只使用一个例子看一下aspectj框架如何匹配切面和目标方法。
Aspectj框架PointcutExpression示例
import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Executable;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.aspectj.lang.annotation.Pointcut;
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.junit.Test;
import org.springframework.asm.ClassReader;
import org.springframework.asm.ClassVisitor;
import org.springframework.asm.Label;
import org.springframework.asm.MethodVisitor;
import org.springframework.asm.Opcodes;
import org.springframework.asm.SpringAsmInfo;
import org.springframework.asm.Type;
import org.springframework.util.ClassUtils;
public class AspectjExpressionPointcutTest {
private final static Set<PointcutPrimitive> SUPPORTED_PRIMITIVES = new HashSet<PointcutPrimitive>() {{
add(PointcutPrimitive.EXECUTION);
add(PointcutPrimitive.ARGS);
add(PointcutPrimitive.REFERENCE);
add(PointcutPrimitive.THIS);
add(PointcutPrimitive.TARGET);
add(PointcutPrimitive.WITHIN);
add(PointcutPrimitive.AT_ANNOTATION);
add(PointcutPrimitive.AT_WITHIN);
add(PointcutPrimitive.AT_ARGS);
add(PointcutPrimitive.AT_TARGET);
}};
// 演示@annotation(..)表达式匹配
@Test
public void testAnnotation() throws Exception {
// 创建PointcutParser
PointcutParser parser = PointcutParser
.getPointcutParserSupportingSpecifiedPrimitivesAndUsingSpecifiedClassLoaderForResolution(
SUPPORTED_PRIMITIVES, AspectjExpressionPointcutTest.class.getClassLoader());
// 获取目标方法
Method method = LogService.class.getDeclaredMethod("testServiceLog");
// 获取切面方法
Method before = ServiceAop.class.getDeclaredMethod("before", ServiceLog.class);
// 获取切面方法参数列表
Parameter[] parameters = before.getParameters();
// 使用asm获取切面方法参数名
String[] parameterNames = getParameterNames(before);
// 构建aspectj切面解析器
// 参数列表只有一个ServiceLog sl
PointcutParameter[] pointcutParameters = new PointcutParameter[parameters.length];
for (int i = 0; i < pointcutParameters.length; i++) {
pointcutParameters[i] = parser.createPointcutParameter(
parameterNames[i], parameters[i].getType());
}
PointcutExpression pointcutExpression = parser
.parsePointcutExpression("@annotation(sl)", ServiceAop.class, pointcutParameters);
// 使用aspectj切面解析器判断目标方法与切面方法是否匹配
ShadowMatch shadowMatch = pointcutExpression.matchesMethodExecution(method);
System.out.println(shadowMatch.alwaysMatches());
System.out.println(shadowMatch.neverMatches());
System.out.println(shadowMatch.maybeMatches());
}
// 演示@execution(..)表达式匹配
@Test
public void testExecution() throws Exception {
PointcutParser parser = PointcutParser
.getPointcutParserSupportingSpecifiedPrimitivesAndUsingSpecifiedClassLoaderForResolution(
SUPPORTED_PRIMITIVES, AspectjExpressionPointcutTest.class.getClassLoader());
// 获取目标方法
Method method = LogService.class.getDeclaredMethod("testServiceLog1", List.class);
// 构建aspectj切面解析器
// 此时需要ServiceAop.class中存在serviceAopPointCut()切入点
PointcutExpression pointcutExpression = parser.parsePointcutExpression(
"serviceAopPointCut()",
ServiceAop.class, new PointcutParameter[]{});
// 使用aspectj切面解析器判断目标方法与切面方法是否匹配
ShadowMatch shadowMatch = pointcutExpression.matchesMethodExecution(method);
System.out.println(shadowMatch.alwaysMatches());
System.out.println(shadowMatch.neverMatches());
System.out.println(shadowMatch.maybeMatches());
}
private static String[] getParameterNames(Method before) throws IOException {
InputStream is = ServiceAop.class.getClassLoader().getResourceAsStream(
"org/net5ijy/mybatis/test/AspectjExpressionPointcutTest$ServiceAop.class");
assert is != null;
ClassReader classReader = new ClassReader(is);
Map<Executable, String[]> map = new ConcurrentHashMap<>(32);
classReader.accept(new ParameterNameDiscoveringVisitor(ServiceAop.class, map), 0);
return map.get(before);
}
public static class ServiceAop {
@Pointcut("execution(public * org.net5ijy.mybatis.test..*.*(..))")
public void serviceAopPointCut() {}
public void before(ServiceLog sl) {
System.out.println("ServiceAop.before");
System.out.printf("ServiceAop.before: %s\n", sl.toString());
}
}
public static class LogService {
@ServiceLog
public void testServiceLog() {
System.out.println(this.getClass().getName() + ".testServiceLog");
}
public void testServiceLog1(List<String> list) {
System.out.println(this.getClass().getName() + ".testServiceLog1");
}
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ServiceLog {}
/**
* 以下为从spring源码拷贝的asm工具类
*/
private static class ParameterNameDiscoveringVisitor extends ClassVisitor {
private static final String STATIC_CLASS_INIT = "<clinit>";
private final Class<?> clazz;
private final Map<Executable, String[]> executableMap;
public ParameterNameDiscoveringVisitor(Class<?> clazz,
Map<Executable, String[]> executableMap) {
super(SpringAsmInfo.ASM_VERSION);
this.clazz = clazz;
this.executableMap = executableMap;
}
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature,
String[] exceptions) {
if (!isSyntheticOrBridged(access) && !STATIC_CLASS_INIT.equals(name)) {
return new LocalVariableTableVisitor(this.clazz, this.executableMap, name, desc,
isStatic(access));
}
return null;
}
private static boolean isSyntheticOrBridged(int access) {
return (((access & Opcodes.ACC_SYNTHETIC) | (access & Opcodes.ACC_BRIDGE)) > 0);
}
private static boolean isStatic(int access) {
return ((access & Opcodes.ACC_STATIC) > 0);
}
}
private static class LocalVariableTableVisitor extends MethodVisitor {
private static final String CONSTRUCTOR = "<init>";
private final Class<?> clazz;
private final Map<Executable, String[]> executableMap;
private final String name;
private final Type[] args;
private final String[] parameterNames;
private final boolean isStatic;
private boolean hasLvtInfo = false;
/*
* The nth entry contains the slot index of the LVT table entry holding the
* argument name for the nth parameter.
*/
private final int[] lvtSlotIndex;
public LocalVariableTableVisitor(Class<?> clazz, Map<Executable, String[]> map, String name,
String desc, boolean isStatic) {
super(SpringAsmInfo.ASM_VERSION);
this.clazz = clazz;
this.executableMap = map;
this.name = name;
this.args = Type.getArgumentTypes(desc);
this.parameterNames = new String[this.args.length];
this.isStatic = isStatic;
this.lvtSlotIndex = computeLvtSlotIndices(isStatic, this.args);
}
@Override
public void visitLocalVariable(String name, String description, String signature, Label start,
Label end, int index) {
this.hasLvtInfo = true;
for (int i = 0; i < this.lvtSlotIndex.length; i++) {
if (this.lvtSlotIndex[i] == index) {
this.parameterNames[i] = name;
}
}
}
@Override
public void visitEnd() {
if (this.hasLvtInfo || (this.isStatic && this.parameterNames.length == 0)) {
// visitLocalVariable will never be called for static no args methods
// which doesn't use any local variables.
// This means that hasLvtInfo could be false for that kind of methods
// even if the class has local variable info.
this.executableMap.put(resolveExecutable(), this.parameterNames);
}
}
private Executable resolveExecutable() {
ClassLoader loader = this.clazz.getClassLoader();
Class<?>[] argTypes = new Class<?>[this.args.length];
for (int i = 0; i < this.args.length; i++) {
argTypes[i] = ClassUtils.resolveClassName(this.args[i].getClassName(), loader);
}
try {
if (CONSTRUCTOR.equals(this.name)) {
return this.clazz.getDeclaredConstructor(argTypes);
}
return this.clazz.getDeclaredMethod(this.name, argTypes);
} catch (NoSuchMethodException ex) {
throw new IllegalStateException("Method [" + this.name +
"] was discovered in the .class file but cannot be resolved in the class object", ex);
}
}
private static int[] computeLvtSlotIndices(boolean isStatic, Type[] paramTypes) {
int[] lvtIndex = new int[paramTypes.length];
int nextIndex = (isStatic ? 0 : 1);
for (int i = 0; i < paramTypes.length; i++) {
lvtIndex[i] = nextIndex;
if (isWideType(paramTypes[i])) {
nextIndex += 2;
} else {
nextIndex++;
}
}
return lvtIndex;
}
private static boolean isWideType(Type aType) {
// float is not a wide type
return (aType == Type.LONG_TYPE || aType == Type.DOUBLE_TYPE);
}
}
}
创建cglib代理
入口
在《spring-aop源码分析(2)_AnnotationAwareAspectJAutoProxyCreator后置处理器》一文中,我们了解到,spring使用CglibAopProxy.getProxy方法创建代理。
当时的那篇文章没有详细介绍这个过程,本文将继续深入分析一下,最后会给一个示例。
public Object getProxy(ClassLoader classLoader) {
try {
// ...
// Configure CGLIB Enhancer...
Enhancer enhancer = createEnhancer();
if (classLoader != null) {
enhancer.setClassLoader(classLoader);
if (classLoader instanceof SmartClassLoader &&
((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
enhancer.setUseCache(false);
}
}
// 继承的父类
enhancer.setSuperclass(proxySuperClass);
// 实现的接口
enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(classLoader));
// 通过advisor创建cglib代理callback
// 返回的是MethodInterceptor集:
// aopInterceptor、targetInterceptor、EqualsInterceptor、HashCodeInterceptor等
Callback[] callbacks = getCallbacks(rootClass);
Class<?>[] types = new Class<?>[callbacks.length];
for (int x = 0; x < types.length; x++) {
types[x] = callbacks[x].getClass();
}
// 由于上面的callbacks是多个,此处的Filter将确定出最终使用哪个MethodInterceptor拦截目标方法
enhancer.setCallbackFilter(
new ProxyCallbackFilter(
this.advised.getConfigurationOnlyCopy(),
this.fixedInterceptorMap,
this.fixedInterceptorOffset));
enhancer.setCallbackTypes(types);
// Generate the proxy class and create a proxy instance.
// 使用cglib生成代理对象并返回
return createProxyClassAndInstance(enhancer, callbacks);
} catch (CodeGenerationException | IllegalArgumentException ex) {
// throw new AopConfigException
} catch (Throwable ex) {
// throw new AopConfigException
}
}
示例
public class SpringCglibDemo {
public static void main(String[] args) throws InstantiationException, IllegalAccessException {
// 设置cglib生成的class文件存放位置
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:/download");
ClassLoader classLoader = SpringCglibDemo.class.getClassLoader();
Enhancer enhancer = createEnhancer();
// 设置目标类型
enhancer.setSuperclass(LogService.class);
enhancer.setClassLoader(classLoader);
enhancer.setUseCache(false);
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(classLoader));
// callback集
Callback[] callbacks = new Callback[]{
new MyMethodInterceptor(),
new MyMethodInterceptor2()
};
Class<?>[] types = new Class<?>[callbacks.length];
for (int x = 0; x < types.length; x++) {
types[x] = callbacks[x].getClass();
}
enhancer.setCallbackTypes(types);
// Filter选择使用第1个MethodInterceptor拦截目标方法
enhancer.setCallbackFilter(method -> 0);
// 创建代理类并实例化
Class<?> proxyClass = enhancer.createClass();
Object proxyInstance = proxyClass.newInstance();
// 设置callback
((Factory) proxyInstance).setCallbacks(callbacks);
LogService o = (LogService) proxyInstance;
o.testServiceLog();
}
private static Enhancer createEnhancer() {
return new Enhancer();
}
private static class MyMethodInterceptor implements MethodInterceptor {
@Override
public Object intercept(
Object enhancedConfigInstance, Method beanMethod,
Object[] beanMethodArgs, MethodProxy cglibMethodProxy) throws Throwable {
System.out.printf("MyMethodInterceptor %s args: %s\n",
beanMethod.getName(), Arrays.toString(beanMethodArgs));
return cglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs);
}
}
private static class MyMethodInterceptor2 implements MethodInterceptor {
@Override
public Object intercept(
Object enhancedConfigInstance, Method beanMethod,
Object[] beanMethodArgs, MethodProxy cglibMethodProxy) throws Throwable {
System.out.printf("MyMethodInterceptor2 %s args: %s\n",
beanMethod.getName(), Arrays.toString(beanMethodArgs));
return cglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs);
}
}
}
反编译cglib生成的class文件
cglib为目标类生成了一个子类,我们可以找到这个类的class文件,然后使用工具做反编译,得到下面的java文件,此处只记录相对重要的代码段,不做过多描述:
import java.lang.reflect.Method;
import org.net5ijy.mybatis.test.service.LogService;
import org.springframework.cglib.core.ReflectUtils;
import org.springframework.cglib.core.Signature;
import org.springframework.cglib.proxy.Callback;
import org.springframework.cglib.proxy.Factory;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
public class LogService$$EnhancerBySpringCGLIB$$e25335ef extends LogService implements Factory {
private boolean CGLIB$BOUND;
public static Object CGLIB$FACTORY_DATA;
private static ThreadLocal CGLIB$THREAD_CALLBACKS;
private static Callback[] CGLIB$STATIC_CALLBACKS;
// MethodInterceptor相关字段,示例中是两个,spring aop是六个
private MethodInterceptor CGLIB$CALLBACK_0;
private MethodInterceptor CGLIB$CALLBACK_1;
private static Object CGLIB$CALLBACK_FILTER;
private static Method CGLIB$testServiceLog$0$Method;
private static MethodProxy CGLIB$testServiceLog$0$Proxy;
private static Object[] CGLIB$emptyArgs;
private static Method CGLIB$equals$1$Method;
private static MethodProxy CGLIB$equals$1$Proxy;
private static Method CGLIB$toString$2$Method;
private static MethodProxy CGLIB$toString$2$Proxy;
private static Method CGLIB$hashCode$3$Method;
private static MethodProxy CGLIB$hashCode$3$Proxy;
private static Method CGLIB$clone$4$Method;
private static MethodProxy CGLIB$clone$4$Proxy;
static {
try {
LogService$$EnhancerBySpringCGLIB$$e25335ef.CGLIB$STATICHOOK1();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
static void CGLIB$STATICHOOK1() throws Exception {
// 很多初始化代码,略
}
// 业务方法
public final void testServiceLog() {
// 因为我们的Filter返回0所以使用了CALLBACK_0来拦截目标方法
MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0;
if (methodInterceptor == null) {
LogService$$EnhancerBySpringCGLIB$$e25335ef.CGLIB$BIND_CALLBACKS((Object)this);
methodInterceptor = this.CGLIB$CALLBACK_0;
}
if (methodInterceptor != null) {
try {
// 执行拦截方法
Object object = methodInterceptor.intercept(
(Object)this,
CGLIB$testServiceLog$0$Method,
CGLIB$emptyArgs,
CGLIB$testServiceLog$0$Proxy);
} catch (Throwable e) {
throw new RuntimeException(e);
}
return;
}
super.testServiceLog();
}
public void setCallback(int n, Callback callback) {
switch (n) {
case 0: {
this.CGLIB$CALLBACK_0 = (MethodInterceptor)callback;
break;
}
case 1: {
this.CGLIB$CALLBACK_1 = (MethodInterceptor)callback;
break;
}
}
}
public void setCallbacks(Callback[] callbackArray) {
this.CGLIB$CALLBACK_0 = (MethodInterceptor)callbackArray[0];
Callback[] callbackArray2 = callbackArray;
LogService$$EnhancerBySpringCGLIB$$e25335ef logService$$EnhancerBySpringCGLIB$$e25335ef = this;
this.CGLIB$CALLBACK_1 = (MethodInterceptor)callbackArray[1];
}
}