before, myAnnotation.value : son
son.hello()
before, myAnnotation.value : son
father.hello2()
父类有注解,子类无注解:
before, myAnnotation.value : father
father.hello()
before, myAnnotation.value : father
father.hello2()
son.hello()
father.hello2()
父类有注解,子类有注解
before, myAnnotation.value : father
father.hello()
before, myAnnotation.value : father
father.hello2()
before, myAnnotation.value : son
son.hello()
before, myAnnotation.value : son
father.hello2()
我们从上面总结出一套规律:
@within
:@Before
通知方法的myAnnotation
参数指的是调用方法所在的类上面的注解,就是这个方法是在哪个类上定义的
@target
:@Before
通知方法的myAnnotation
参数指的是调用方法运行时所属于的类上面的注解
我们最后总结一下,如果父类和子类上都标有注解,@within
和@target
的所得到实际注解的区别
| | @within | @target |
| — | — | — |
| 父类方法 | 父类注解 | 父类注解 |
| 子类不重写方法 | 父类注解 | 子类注解 |
| 子类重写方法 | 子类注解 | 子类注解 |
@target
看起来跟合理一点
从上面的分析可以看出,其实用@target
更符合我们想要的结果,在某个类上面加一个注解,拦截的时候就会获取这个类上面的注解,跟父类完全没有关系了
但这个时候会遇到一个问题,就是不相关的类都会生从代理类,
例子如下:
public class NormalBean {
public void hello() {
}
}
@Configuration
@EnableAspectJAutoProxy(exposeProxy = true)
public class Config {
@Bean
public Father father() {
return new Father();
}
@Bean
public Son son() {
return new Son();
}
@Bean
public 《一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》无偿开源 威信搜索公众号【编程进阶路】 NormalBean normalBean() {
return new NormalBean();
}
}
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class,
MyAspect.class);
Father father = context.getBean(“father”, Father.class);
father.hello();
father.hello2();
Son son = context.getBean(Son.class);
son.hello();
son.hello2();
NormalBean normalBean = context.getBean(NormalBean.class);
System.out.println(normalBean.getClass());
}
}
输出:
class cn.eagleli.spring.aop.demo.NormalBean E n h a n c e r B y S p r i n g C G L I B EnhancerBySpringCGLIB EnhancerBySpringCGLIBeebc2a39
可以看出NormalBean
自己什么都没做,但却被代理了
我们再把@target
换成@within
:
class cn.eagleli.spring.aop.demo.NormalBean
可以看出使用@within
时,不相关的类没有被代理
我们一起来看看为什么
在AbstractAutoProxyCreator
类中的wrapIfNecessary
方法打断点,看看什么情况:
@within
@target
我们从上面的图片就可以理解为什么@target
会生成代理类
我们再深入看一下:
@within
会走到如下:
public class ExactAnnotationTypePattern extends AnnotationTypePattern {
@Override
public FuzzyBoolean matches(AnnotatedElement annotated, ResolvedType[] parameterAnnotations) {
// …
}
}
我没深入研究,大致意思就是只要这个类或者这个类的祖先们带有这个注解,即匹配成功
@target
会走到如下:
public class ThisOrTargetAnnotationPointcut extends NameBindingPointcut {
@Override
protected FuzzyBoolean matchInternal(Shadow shadow) {
if (!couldMatch(shadow)) {
return FuzzyBoolean.NO;
}
ResolvedType toMatchAgainst = (isThis ? shadow.getThisType() : shadow.getTargetType()).resolve(shadow.getIWorld());
annotationTypePattern.resolve(shadow.getIWorld());
if (annotationTypePattern.matchesRuntimeType(toMatchAgainst).alwaysTrue()) {
return FuzzyBoolean.YES;
} else {
// a subtype may match at runtime
return FuzzyBoolean.MAYBE;
}
}
}
public class AspectJExpressionPointcut extends AbstractExpressionPointcut
implements ClassFilter, IntroductionAwareMethodMatcher, BeanFactoryAware {
@Override
public boolean matches(Method method, Class<?> targetClass, boolean hasIntroductions) {
obtainPointcutExpression();
ShadowMatch shadowMatch = getTargetShadowMatch(method, targetClass);
// Special handling for this, target, @this, @target, @annotation
// in Spring - we can optimize since we know we have exactly this class,
// and there will never be matching subclass at runtime.
if (shadowMatch.alwaysMatches()) {
return true;
}
else if (shadowMatch.neverMatches()) {
return false;
}
else {
// the maybe case
if (hasIntroductions) {
return true;
}
// A match test returned maybe - if there are any subtype sensitive variables
// involved in the test (this, target, at_this, at_target, at_annotation) then
// we say this is not a match as in Spring there will never be a different
// runtime subtype.
RuntimeTestWalker walker = getRuntimeTestWalker(shadowMatch);
return (!walker.testsSubtypeSensitiveVars() || walker.testTargetInstanceOfResidue(targetClass)); // 这里会返回true
}
}
}
我没深入研究,大致意思是匹配的话就返回YES
,否则就返回MAYBE
,匹配逻辑是和@within
一样的
因此所有不相关的类都会是一个MAYBE
的结果,这个结果会让不相关的类最后生成代理类
通知方法中注解参数的值为什么是不一样的
经过调试,最终是在这里获取的:
public final class ReflectionVar extends Var {
static final int THIS_VAR = 0;
static final int TARGET_VAR = 1;
static final int ARGS_VAR = 2;
static final int AT_THIS_VAR = 3;
static final int AT_TARGET_VAR = 4;
static final int AT_ARGS_VAR = 5;
static final int AT_WITHIN_VAR = 6;
static final int AT_WITHINCODE_VAR = 7;
static final int AT_ANNOTATION_VAR = 8;
public Object getBindingAtJoinPoint(
Object thisObject,
Object targetObject,
Object[] args,
Member subject,
Member withinCode,
Class withinType) {
switch( this.varType) {
case THIS_VAR: return thisObject;
case TARGET_VAR: return targetObject;
case ARGS_VAR:
if (this.argsIndex > (args.length - 1)) return null;
return args[argsIndex];
case AT_THIS_VAR:
if (annotationFinder != null) {
return annotationFinder.getAnnotation(getType(), thisObject);
} else return null;
case AT_TARGET_VAR:
if (annotationFinder != null) {
return annotationFinder.getAnnotation(getType(), targetObject);
} else return null;
case AT_ARGS_VAR:
if (this.argsIndex > (args.length - 1)) return null;
if (annotationFinder != null) {
return annotationFinder.getAnnotation(getType(), args[argsIndex]);
} else return null;
case AT_WITHIN_VAR:
if (annotationFinder != null) {
return annotationFinder.getAnnotationFromClass(getType(), withinType);
} else return null;
case AT_WITHINCODE_VAR:
if (annotationFinder != null) {
return annotationFinder.getAnnotationFromMember(getType(), withinCode);
} else return null;
case AT_ANNOTATION_VAR:
if (annotationFinder != null) {
return annotationFinder.getAnnotationFromMember(getType(), subject);
} else return null;
}
return null;
}
}
@within
:
case AT_WITHIN_VAR:
if (annotationFinder != null) {
return annotationFinder.getAnnotationFromClass(getType(), withinType);
} else return null;
withinType
追踪到如下:
public class PointcutExpressionImpl implements PointcutExpression {
private ShadowMatch matchesExecution(Member aMember) {
Shadow s = ReflectionShadow.makeExecutionShadow(world, aMember, this.matchContext);
ShadowMatchImpl sm = getShadowMatch(s);
sm.setSubject(aMember);
sm.setWithinCode(null);
sm.setWithinType(aMember.getDeclaringClass()); // 这里设置withinType
return sm;
}
}
public abstract class AopUtils {
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
Assert.notNull(pc, “Pointcut must not be null”);
if (!pc.getClassFilter().matches(targetClass)) {
return false;
}
MethodMatcher methodMatcher = pc.getMethodMatcher();
if (methodMatcher == MethodMatcher.TRUE) {
// No need to iterate the methods if we’re matching any method anyway…
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) { // 这里获取所有method
if (introductionAwareMethodMatcher != null ?
introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
methodMatcher.matches(method, targetClass)) {
return true;
}
}
}
return false;
}
}
@target
:
case AT_TARGET_VAR:
if (annotationFinder != null) {
return annotationFinder.getAnnotation(getType(), targetObject);
} else return null;
targetObject
追踪到如下:
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {