源码分析如何注解使用AOP
如何注解使用AOP
定义注解
/**
* 在函数上面注解,打印函数调用前后,异常等日志信息
*
* <p>用法:@LoggerManage(description="方法描述")
*
* <p>在{@link LoggerAdvice}类中处理
*
* @author lishaofeng [email protected]
* @date 2018年11月13日 下午2:39:10
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LoggerManage {
/**
* 方法描述信息
* @return
*/
String description();
}
AOP增强处理
/**
* 通过注解{@link LoggerManage}来打印日志
* @author lishaofeng [email protected]
* @date 2018年11月13日 下午2:39:06
*/
@Aspect
@Component
@Slf4j
public class LoggerAdvice {
@Around(value= "within(com.jlpay..*) && @annotation(loggerManage)")
public Object addAroundLogger(ProceedingJoinPoint joinPoint, LoggerManage loggerManage)
{
log.info("执行【{}】开始,函数名【{}】,传入参数【{}】", loggerManage.description(),joinPoint.getSignature().getName(),JSON.toJSONString(joinPoint.getArgs()));
Object oj = null;
try {
oj = joinPoint.proceed();
log.info("执行【{}】结束,函数名【{}】,返回数据【{}】" , loggerManage.description(),joinPoint.getSignature().getName(),JSON.toJSONString(oj));
} catch ( Throwable e) {
e.printStackTrace();
log.error("执行【{}】,函数名【{}】,异常【{}】" ,loggerManage.description(),joinPoint.getSignature().getName(),e.getMessage());
}
return oj;
}
}
配置
/**
*自动配置类,注入{@link LoggerAdvice}类到容器
* @author 39619
*/
@Configuration
@EnableAspectJAutoProxy
@Import(LoggerAdvice.class)
public class LoggerConfig {
}
以上就是注解AOP的使用方法。
知其然不知其所以然可不行,究竟是如何将自定义注解注入到函数方法中的参数?
如何将注解注入到函数方法中的参数?
通过断点到LoggerAdvice.addAroundLogger(),堆栈信息如下:
addAroundLogger:24, LoggerAdvice (com.jlpay.common.log)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
invokeAdviceMethodWithGivenArgs:644, AbstractAspectJAdvice (org.springframework.aop.aspectj)
invokeAdviceMethod:633, AbstractAspectJAdvice (org.springframework.aop.aspectj)
invoke:70, AspectJAroundAdvice (org.springframework.aop.aspectj)
proceed:174, ReflectiveMethodInvocation (org.springframework.aop.framework)
invoke:92, ExposeInvocationInterceptor (org.springframework.aop.interceptor)
proceed:185, ReflectiveMethodInvocation (org.springframework.aop.framework)
intercept:688, CglibAopProxy$DynamicAdvisedInterceptor (org.springframework.aop.framework)
gateway:-1, ApiTransController$$EnhancerBySpringCGLIB$$39469408 (com.jlpay.quickpass.api.trans.controller)
...
AbstractAspectJAdvice
发现是在 invokeAdviceMethod:633, AbstractAspectJAdvice (org.springframework.aop.aspectj)中注入方法参数的
// As above, but in this case we are given the join point.
protected Object invokeAdviceMethod(JoinPoint jp, @Nullable JoinPointMatch jpMatch,
@Nullable Object returnValue, @Nullable Throwable t) throws Throwable {
return invokeAdviceMethodWithGivenArgs(argBinding(jp, jpMatch, returnValue, t));
}
/**
* Take the arguments at the method execution join point and output a set of arguments
* to the advice method
* @param jp the current JoinPoint
* @param jpMatch the join point match that matched this execution join point
* @param returnValue the return value from the method execution (may be null)
* @param ex the exception thrown by the method execution (may be null)
* @return the empty array if there are no arguments
*/
protected Object[] argBinding(JoinPoint jp, @Nullable JoinPointMatch jpMatch,
@Nullable Object returnValue, @Nullable Throwable ex) {
calculateArgumentBindings();
// AMC start
Object[] adviceInvocationArgs = new Object[this.parameterTypes.length];
int numBound = 0;
if (this.joinPointArgumentIndex != -1) {
adviceInvocationArgs[this.joinPointArgumentIndex] = jp;
numBound++;
}
else if (this.joinPointStaticPartArgumentIndex != -1) {
adviceInvocationArgs[this.joinPointStaticPartArgumentIndex] = jp.getStaticPart();
numBound++;
}
if (!CollectionUtils.isEmpty(this.argumentBindings)) {
// binding from pointcut match
if (jpMatch != null) {
PointcutParameter[] parameterBindings = jpMatch.getParameterBindings();
for (PointcutParameter parameter : parameterBindings) {
String name = parameter.getName();
Integer index = this.argumentBindings.get(name);
adviceInvocationArgs[index] = parameter.getBinding();
numBound++;
}
}
// binding from returning clause
if (this.returningName != null) {
Integer index = this.argumentBindings.get(this.returningName);
adviceInvocationArgs[index] = returnValue;
numBound++;
}
// binding from thrown exception
if (this.throwingName != null) {
Integer index = this.argumentBindings.get(this.throwingName);
adviceInvocationArgs[index] = ex;
numBound++;
}
}
if (numBound != this.parameterTypes.length) {
throw new IllegalStateException("Required to bind " + this.parameterTypes.length +
" arguments, but only bound " + numBound + " (JoinPointMatch " +
(jpMatch == null ? "was NOT" : "WAS") + " bound in invocation)");
}
return adviceInvocationArgs;
}
这里通过JoinPointMatch对象,获取绑定的 @LoggerManage(description=“方法描述”) 注解 ,然后根据顺序一个个给参数数组Object[] adviceInvocationArgs 赋值。就这样我们的AOP增强方法就获取到了自定义注解
注意:
这里参数有顺序要求,
[JoinPoint] [StaticPart] [匹配的切入点绑定的(比如注解)] [返回对象] [异常对象]
以上就是是如何将自定义注解注入到函数方法中的参数
AbstractAspectJAdvice是什么时候注入的呢?
断点到 AbstractAspectJAdvice,堆栈信息如下:
<clinit>:68, AbstractAspectJAdvice (org.springframework.aop.aspectj)
getAdvice:274, ReflectiveAspectJAdvisorFactory (org.springframework.aop.aspectj.annotation)
instantiateAdvice:167, InstantiationModelAwarePointcutAdvisorImpl (org.springframework.aop.aspectj.annotation)
<init>:113, InstantiationModelAwarePointcutAdvisorImpl (org.springframework.aop.aspectj.annotation)
getAdvisor:198, ReflectiveAspectJAdvisorFactory (org.springframework.aop.aspectj.annotation)
getAdvisors:126, ReflectiveAspectJAdvisorFactory (org.springframework.aop.aspectj.annotation)
buildAspectJAdvisors:110, BeanFactoryAspectJAdvisorsBuilder (org.springframework.aop.aspectj.annotation)
findCandidateAdvisors:95, AnnotationAwareAspectJAutoProxyCreator (org.springframework.aop.aspectj.annotation)
shouldSkip:101, AspectJAwareAdvisorAutoProxyCreator (org.springframework.aop.aspectj.autoproxy)
postProcessBeforeInstantiation:254, AbstractAutoProxyCreator (org.springframework.aop.framework.autoproxy)
applyBeanPostProcessorsBeforeInstantiation:1060, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
...
根据堆栈信息可以看到是通过 AbstractAutoProxyCreator.applyBeanPostProcessorsBeforeInstantiation()bean初始化前置处理,调用子类AspectJAwareAdvisorAutoProxyCreator.shouldSkip()方法来找全部匹配的Advisors再调用 BeanFactoryAspectJAdvisorsBuilder委托AspectJAdvisorFactory.getAdvisors(factory)获取全部的Advisors。
@Override
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
// TODO: Consider optimization by caching the list of the aspect names
List<Advisor> candidateAdvisors = findCandidateAdvisors();
for (Advisor advisor : candidateAdvisors) {
if (advisor instanceof AspectJPointcutAdvisor &&
((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
return true;
}
}
return super.shouldSkip(beanClass, beanName);
}
@Override
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;
}
这里会查找Spring容器里面的所有类,遍历判断有Aspect注解的类,才去生成Advisors
/**
* Look for AspectJ-annotated aspect beans in the current bean factory,
* and return to a list of Spring AOP Advisors representing them.
* <p>Creates a Spring Advisor for each AspectJ advice method.
* @return the list of {@link org.springframework.aop.Advisor} beans
* @see #isEligibleBean
*/
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);
if (beanType == null) {
continue;
}
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("Bean with name '" + beanName +
"' is a singleton, but aspect instantiation model is not singleton");
}
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;
}
@Override
public boolean isAspect(Class<?> clazz) {
return (hasAspectAnnotation(clazz) && !compiledByAjc(clazz));
}
private boolean hasAspectAnnotation(Class<?> clazz) {
return (AnnotationUtils.findAnnotation(clazz, Aspect.class) != null);
}
实际是通过AspectJAdvisorFactory的子类ReflectiveAspectJAdvisorFactory通过反射的形式获取。
@Override
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<>();
for (Method method : getAdvisorMethods(aspectClass)) {
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
if (advisor != null) {
advisors.add(advisor);
}
}
// If it's a per target aspect, emit the dummy instantiating aspect.
if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
advisors.add(0, instantiationAdvisor);
}
// Find introduction fields.
for (Field field : aspectClass.getDeclaredFields()) {
Advisor advisor = getDeclareParentsAdvisor(field);
if (advisor != null) {
advisors.add(advisor);
}
}
return advisors;
}
获取非Pointcut注解的函数
private List<Method> getAdvisorMethods(Class<?> aspectClass) {
final List<Method> methods = new ArrayList<>();
ReflectionUtils.doWithMethods(aspectClass, method -> {
// Exclude pointcuts
if (AnnotationUtils.getAnnotation(method, Pointcut.class) == null) {
methods.add(method);
}
});
methods.sort(METHOD_COMPARATOR);
return methods;
}
@Override
@Nullable
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
int declarationOrderInAspect, String aspectName) {
validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
AspectJExpressionPointcut expressionPointcut = getPointcut(
candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
if (expressionPointcut == null) {
return null;
}
return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}
最终调用ReflectiveAspectJAdvisorFactory 判断 aspectJAnnotation.getAnnotationType() 来创建实际的Advice
@Override
@Nullable
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;
}
// If we get here, we know we have an AspectJ method.
// Check that it's an AspectJ-annotated class
if (!isAspect(candidateAspectClass)) {
throw new AopConfigException("Advice must be declared inside an aspect type: " +
"Offending method '" + candidateAdviceMethod + "' in class [" +
candidateAspectClass.getName() + "]");
}
if (logger.isDebugEnabled()) {
logger.debug("Found AspectJ method: " + candidateAdviceMethod);
}
AbstractAspectJAdvice springAdvice;
switch (aspectJAnnotation.getAnnotationType()) {
case AtBefore:
springAdvice = new AspectJMethodBeforeAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtAfter:
springAdvice = new AspectJAfterAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtAfterReturning:
springAdvice = new AspectJAfterReturningAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
if (StringUtils.hasText(afterReturningAnnotation.returning())) {
springAdvice.setReturningName(afterReturningAnnotation.returning());
}
break;
case AtAfterThrowing:
springAdvice = new AspectJAfterThrowingAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
}
break;
case AtAround:
springAdvice = new AspectJAroundAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtPointcut:
if (logger.isDebugEnabled()) {
logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
}
return null;
default:
throw new UnsupportedOperationException(
"Unsupported advice type on method: " + candidateAdviceMethod);
}
// 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;
}
到这里 AbstractAspectJAdvice 就创建好了。
上面提到的AspectJAwareAdvisorAutoProxyCreator是如何注入的?
@EnableAspectJAutoProxy
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
Spriing容器启动refresh方法,会调用处理器去注册bean,从而识别@EnableAspectJAutoProxy注解的@Import(AspectJAutoProxyRegistrar.class)注解去注册AspectJAutoProxyRegistrar类。
AspectJAutoProxyRegistrar类会调用AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);从而注册AnnotationAwareAspectJAutoProxyCreator类
@Nullable
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry,
@Nullable Object source) {
return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}
AnnotationAwareAspectJAutoProxyCreator 继承AspectJAwareAdvisorAutoProxyCreator
到此AspectJAwareAdvisorAutoProxyCreator注册成功
public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator {
总结
Spirng 容器启动时 通过@EnableAspectJAutoProxy 导入注册AspectJAutoProxyRegistrar,然后注册了AnnotationAwareAspectJAutoProxyCreator类。
AnnotationAwareAspectJAutoProxyCreator 被调用bean初始化前置处理,为匹配切入表达式的方法,AOP增强处理(自动配备增强方法参数),注册增强后的对象注册到Spring容器中。从而实现AOP功能。