前面咱已经知道,最终 bean 的初始化会被 BeanPostProcessor
的 postProcessAfterInitialization
处理,进入到 AnnotationAwareAspectJAutoProxyCreator
的 postProcessAfterInitialization
方法中,它又要调用 wrapIfNecessary
方法来尝试创建代理,咱深入方法内部来研究。
1. wrapIfNecessary
复制 protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// 判断决定是否是不会被增强的 bean
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// Create proxy if we have advice.
// 如果上面的判断都没有成立,则决定是否需要进行代理对象的创建
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 创建代理对象的动作
// 注意此处它创建了一个SingletonTargetSource,将bean包装起来了
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;
}
这里前面的筛选过滤懂还是蛮简单的,咱就不关注了,重点是关注一下中间的获取增强器,以及下面的创建代理对象,两个动作。
1.1 getAdvicesAndAdvisorsForBean
这个方法很明显是根据当前正在初始化的 bean ,去匹配获取能切入的增强器,它的源码看上去不复杂:
复制 protected Object[] getAdvicesAndAdvisorsForBean(
Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
if (advisors.isEmpty()) {
return DO_NOT_PROXY;
}
return advisors.toArray();
}
毫无疑问,核心逻辑是 findEligibleAdvisors
方法咯,继续往里走:
复制 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;
}
这个方法就很复杂了,尽管只有几行,但都是封装好的方法,咱一个一个的展开来看。
1.1.1 findCandidateAdvisors
又回到 AnnotationAwareAspectJAutoProxyCreator
了:
复制 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;
}
可以发现,这个方法只是把 SpringFramework 原生的 AOP 增强器,以及 AspectJ 形式封装的增强器都拿出来,仅此而已。
1.1.2 findAdvisorsThatCanApply
所有的增强器获取到之后,下面要去匹配可以切入到当前 bean 的增强器了,咱进入到 findAdvisorsThatCanApply
方法中:
复制 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
执行了,咱继续往里看:
复制 public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
if (candidateAdvisors.isEmpty()) {
return candidateAdvisors;
}
List<Advisor> eligibleAdvisors = new ArrayList<>();
// 先匹配引介增强器
for (Advisor candidate : candidateAdvisors) {
if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
eligibleAdvisors.add(candidate);
}
}
boolean hasIntroductions = !eligibleAdvisors.isEmpty();
// 再匹配普通方法增强器
for (Advisor candidate : candidateAdvisors) {
if (candidate instanceof IntroductionAdvisor) {
// already processed
continue;
}
if (canApply(candidate, clazz, hasIntroductions)) {
eligibleAdvisors.add(candidate);
}
}
return eligibleAdvisors;
}
可以发现,整体逻辑分为两个部分,前面是针对引介通知的增强器作筛选,后面是普通的方法通知封装的增强器。
上面的引介增强器的匹配咱就不多研究了,本来平时就用得少,咱主要还是来看对于方法的增强器,它是如何去做匹配的。进入到下面的 canApply
方法中:
复制 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) {
// 方法切入点的增强器匹配逻辑
PointcutAdvisor pca = (PointcutAdvisor) advisor;
return canApply(pca.getPointcut(), targetClass, hasIntroductions);
}
else {
// It doesn't have a pointcut so we assume it applies.
// SpringFramework也不知道咋搞了,于是就直接让它可以匹配
return true;
}
}
从这个逻辑中就可以看出,底层针对不同种的增强器,分别会有不同的判断逻辑。对于方法增强器的判断,它又调用了下面的重载方法:
复制 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) {
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) {
// 逐个判断每个方法是否能被当前切入点表达式切入,切入则立即返回true
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;
}
整体思路还是很清晰的吧,我们要理解的核心部分,是下面的这个双重循环,以此就能判断出来切入点表达式是否能对当前 bean 进行增强了。
Debug 下来,最终发现可以给 OrderService
匹配到的增强器一共有 2 个:( FinanceService
就不看了,因为咱一开始学习的时候,就是拿它举的例子,所有的通知方法都切入它了)
1.1.3 extendAdvisors
这个方法看上去蛮不起眼的,不过小伙伴们有自己 Debug 的话,过了这个方法会发现 eligibleAdvisors
集合中多了一个增强器:
诶?它自己还有偷偷添加增强器啊,那咱看看它干了些啥:
1.1.3.1 extendAdvisors方法的小动作
复制 protected void extendAdvisors(List<Advisor> candidateAdvisors) {
AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(candidateAdvisors);
}
// AspectJProxyUtils
public static boolean makeAdvisorChainAspectJCapableIfNecessary(List<Advisor> advisors) {
// Don't add advisors to an empty list; may indicate that proxying is just not required
if (!advisors.isEmpty()) {
boolean foundAspectJAdvice = false;
for (Advisor advisor : advisors) {
// Be careful not to get the Advice without a guard, as this might eagerly
// instantiate a non-singleton AspectJ aspect...
if (isAspectJAdvice(advisor)) {
foundAspectJAdvice = true;
break;
}
}
// 发现有AspectJ包装的增强器,则添加一个ExposeInvocationInterceptor
if (foundAspectJAdvice && !advisors.contains(ExposeInvocationInterceptor.ADVISOR)) {
advisors.add(0, ExposeInvocationInterceptor.ADVISOR);
return true;
}
}
return false;
}
逻辑不算复杂,它这个方法的关键是,判断当前可用的增强器中有没有 AspectJ 类型的,如果有的话,那就在整个增强器的列表的最前面,添加一个 ExposeInvocationInterceptor.ADVISOR
。
1.1.3.2 ADVISOR是个啥?
那这个 ADVISOR
又是个啥子?咱继续往里走:
复制 public static final ExposeInvocationInterceptor INSTANCE = new ExposeInvocationInterceptor();
public static final Advisor ADVISOR = new DefaultPointcutAdvisor(INSTANCE) {
@Override
public String toString() {
return ExposeInvocationInterceptor.class.getName() +".ADVISOR";
}
};
哦?合着它是个对所有 bean 都生效的增强器呗?传入的这个 INSTANCE
很明显是单例的设计,那到头来核心还是这个 ExposeInvocationInterceptor
本身。
1.1.3.3 ExposeInvocationInterceptor又是个啥?
那新的问题就来了:ExposeInvocationInterceptor
这玩意的作用是什么呢?
翻开源码的核心 invoke 方法,发现它在向当前线程的 ThreadLocal
中放入了当前正在执行的代理对象的方法执行包装:
复制 private static final ThreadLocal<MethodInvocation> invocation =
new NamedThreadLocal<>("Current AOP method invocation");
public Object invoke(MethodInvocation mi) throws Throwable {
MethodInvocation oldInvocation = invocation.get();
invocation.set(mi);
try {
return mi.proceed();
}
finally {
invocation.set(oldInvocation);
}
}
每次都在增强器链的第一个执行,并且放入 ThreadLocal
变量中,那这意图就很明显了:它可以让后面的增强器都拿到当前正在执行的 MethodInvocation
。至于哪里会用到 MethodInvocation
,咱目前还没有遇到,后面如果遇到了咱再留意。
或许会有小伙伴产生一个小小的疑惑:那你放就放呗, MethodInvocation oldInvocation = invocation.get();
这个操作是啥意思?原本就没有,你 get
个什么劲呢???
哎?真的没有吗?如果是一个 AOP 代理对象,调用了另外一个 AOP 代理对象的话,这个过程是在一个线程中执行的呀,那第二个代理对象的方法被调用时,是不是也会经过 ExposeInvocationInterceptor
呢?那是不是从 ThreadLocal
中就可以取出 MethodInvocation
了呢?所以小伙伴们一定要多想一层呀,多实践多思考才会更进步 ~
1.2 createProxy
上面结束之后,所有的增强器也就都准备好了,接下来就是创建代理对象的部分了,咱进入 createProxy
中:
复制 protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) {
// 记录被代理bean的原始类型
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
// 代理工厂的初始化
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
// 根据AOP的设计,决定是否强制使用Cglib
if (!proxyFactory.isProxyTargetClass()) {
if (shouldProxyTargetClass(beanClass, beanName)) {
// Cglib动态代理直接记录被代理bean的所属类即可
proxyFactory.setProxyTargetClass(true);
}
else {
// 解析被代理bean所属类的所有实现的接口
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
// 1.2.1 构造整合所有增强器
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
// 1.2.2 创建代理对象
return proxyFactory.getProxy(getProxyClassLoader());
}
到了这里,咱就可以发现,这里面的逻辑已经基本上处理的差不多了,核心的动作就两个:收集整理要织入到目标对象的通知增强器 ,以及创建代理对象 。前面的那些小细节小伙伴们可以自行研究,相对都是蛮简单的,小册带小伙伴们关注的是这两部分的核心逻辑。
1.2.1 buildAdvisors
源码不算长,里面有一段日志的部分,小册在这里删掉了,咱只关心核心逻辑:
复制 protected Advisor[] buildAdvisors(@Nullable String beanName, @Nullable Object[] specificInterceptors) {
// Handle prototypes correctly...
// 这个地方是适配Spring原生AOP的MethodInterceptor,感兴趣的小伙伴可自行研究
Advisor[] commonInterceptors = resolveInterceptorNames();
List<Object> allInterceptors = new ArrayList<>();
if (specificInterceptors != null) {
allInterceptors.addAll(Arrays.asList(specificInterceptors));
// 组合原生的方法拦截器,共同作为AOP的通知织入
if (commonInterceptors.length > 0) {
if (this.applyCommonInterceptorsFirst) {
allInterceptors.addAll(0, Arrays.asList(commonInterceptors));
}
else {
allInterceptors.addAll(Arrays.asList(commonInterceptors));
}
}
}
// logger ......
Advisor[] advisors = new Advisor[allInterceptors.size()];
for (int i = 0; i < allInterceptors.size(); i++) {
// 此处有一个原生AOP的适配动作
advisors[i] = this.advisorAdapterRegistry.wrap(allInterceptors.get(i));
}
return advisors;
}
上面整合 SpringFramework 原生 AOP 的内容咱小册就不提及了,毕竟是很久之前用的东西了,咱现在都是 AspectJ 的。在最下面,它有一个 advisorAdapterRegistry.wrap
的方法调用,它是干嘛的呢?咱可以去瞅一眼:
复制 public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
// Advisor增强器可以直接返回
if (adviceObject instanceof Advisor) {
return (Advisor) adviceObject;
}
// 不支持非Advice的类型
if (!(adviceObject instanceof Advice)) {
throw new UnknownAdviceTypeException(adviceObject);
}
Advice advice = (Advice) adviceObject;
// MethodInterceptor的支持
if (advice instanceof MethodInterceptor) {
// So well-known it doesn't even need an adapter.
return new DefaultPointcutAdvisor(advice);
}
// AdvisorAdapter的支持
for (AdvisorAdapter adapter : this.adapters) {
// Check that it is supported.
if (adapter.supportsAdvice(advice)) {
return new DefaultPointcutAdvisor(advice);
}
}
throw new UnknownAdviceTypeException(advice);
}
注意这个方法的参数和返回值:它可以是任意类型的入参,但返回的一定是 Advisor
,这也就呼应了 wrap
方法的含义:将可以支持转换 / 包装为 **Advisor**
类型的对象适配成 **Advisor**
。至于它可以适配的类型,内置的只有 MethodInterceptor
和几种原生的 Advice
(前面 Spring 原生 AOP 中提到的),不过它提供了一个 AdvisorAdapter
的接口,供我们扩展使用,以此来支持自定义的 Advice
类型。不过我们几乎都没有这么做的,所以这部分小伙伴们知道一下就可以了,没必要深究。
1.2.2 proxyFactory.getProxy
下面就是真正创建代理对象的逻辑了,这个方法又分为两个部分:
复制 public Object getProxy(@Nullable ClassLoader classLoader) {
return createAopProxy().getProxy(classLoader);
}
咱一一来看。
1.2.2.1 createAopProxy
复制 protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
return getAopProxyFactory().createAopProxy(this);
}
private void activate() {
this.active = true;
for (AdvisedSupportListener listener : this.listeners) {
listener.activated(this);
}
}
上面有一个监听器的通知动作,由于这个动作涉及到的监听器 AdvisedSupportListener
只在 ProxyCreatorSupport
这个类中使用,咱们开发也基本不会碰这些东西,所以这个咱可以跳过了,关键的还是下面 getAopProxyFactory().createAopProxy(this);
的执行。
getAopProxyFactory
方法返回的是当前 ProxyCreatorSupport
的成员 aopProxyFactory
,借助 Debug 可以发现它的类型是 DefaultAopProxyFactory
。
进入到它的 createAopProxy
方法中,终于发现了咱熟悉的 jdk 、Cglib 动态代理的字眼了:
复制 public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
// 如果要代理的本身就是接口,或者已经是被jdk动态代理了的代理对象
// 则使用jdk动态代理
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
// 否则使用Cglib动态代理
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
至此,咱就知道,使用 jdk 动态代理,还是 Cglib 动态代理,底层的选择是在这里决定的。
1.2.2.2 AopProxy#getProxy
创建完 AopProxy
后,下面就是创建代理对象的动作了,咱以 JdkDynamicAopProxy
为例进去看一下:
复制 public Object getProxy(@Nullable ClassLoader classLoader) {
// logger ......
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
// jdk动态代理的API
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
看,最底下,咱最最熟悉的 Proxy.newProxyInstance
方法出现了!!!所以由此咱就可以体会到,代理对象的底层创建还是依赖 jdk 动态代理,或者 Cglib 动态代理的核心 API 呀!
至于 Cglib 动态代理的创建,咱就不特别深入了,咱注意一下中间的核心部分即可:
复制 // ......
// 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));
Callback[] callbacks = getCallbacks(rootClass);
Class<?>[] types = new Class<?>[callbacks.length];
for (int x = 0; x < types.length; x++) {
types[x] = callbacks[x].getClass();
}
// fixedInterceptorMap only populated at this point, after getCallbacks call above
enhancer.setCallbackFilter(new ProxyCallbackFilter(
this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
enhancer.setCallbackTypes(types);
// Generate the proxy class and create a proxy instance.
return createProxyClassAndInstance(enhancer, callbacks);
// ......
可以看到,这也是对 Cglib 中的 Enhancer
进行操作,核心的思路是不变的,只是框架比咱考虑的更多罢了。
OK ,到此为止,代理对象也就成功创建了,整个 AOP 通知织入的流程也就结束了。