SpringAOP从入门到源码分析大全(三)ProxyFactory源码分析

时间:2024-04-23 07:01:55

文章目录

  • 系列文档索引
  • 五、ProxyFactory源码分析
    • 1、案例
    • 2、认识TargetSource
      • (1)何时用到TargetSource
      • (2)@Lazy的原理
      • (3)应用TargetSource
    • 3、ProxyFactory选择cglib或jdk动态代理原理
    • 4、jdk代理获取代理方法的逻辑
      • (1)getInterceptorsAndDynamicInterceptionAdvice获取拦截器链
      • (2)包装AfterReturningAdvice、MethodBeforeAdvice为MethodInterceptor
      • (3)总结
    • 5、cglib代理获取代理方法的逻辑
      • (1)getCallbacks获取callback方法
      • (2)总结
    • 6、执行器链执行逻辑

系列文档索引

SpringAOP从入门到源码分析大全(一)熟悉动态代理
SpringAOP从入门到源码分析大全(二)熟悉ProxyFactory
SpringAOP从入门到源码分析大全(三)ProxyFactory源码分析
SpringAOP从入门到源码分析大全(四)SpringAOP的源码分析
SpringAOP从入门到源码分析大全(五)手写一个编程式AOP

五、ProxyFactory源码分析

1、案例

UserService userService = new UserService();
// spring 将cglib和jdk动态代理合二为一了,如果有接口,就会走jdk代理,如果只有类,就会走cglib代理
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(userService);
// 可以设置多个Advice,会形成代理链
proxyFactory.addAdvice(new MyBeforeAdvice());
proxyFactory.addAdvice(new MyAroundAdvice());
proxyFactory.addAdvice(new MyAfterAdvice());

proxyFactory.addAdvisor(new PointcutAdvisor() {
    @Override
    public Pointcut getPointcut() {
        return new Pointcut() {
            @Override
            public ClassFilter getClassFilter() {
                return new ClassFilter() {
                    @Override
                    public boolean matches(Class<?> clazz) {
                        // 类匹配器
                        return false;
                    }
                };
            }

            @Override
            public MethodMatcher getMethodMatcher() {
                // 方法匹配器
                return new MethodMatcher() {
                    @Override
                    public boolean matches(Method method, Class<?> targetClass) {
                        return false;
                    }

                    @Override
                    public boolean isRuntime() {
                        return false; // 如果为true时,下面的参数matches就会生效
                    }

                    @Override
                    public boolean matches(Method method, Class<?> targetClass, Object... args) {
                        return false;
                    }
                };
            }
        };
    }

    @Override
    public Advice getAdvice() {
        return new MyAfterAdvice();
    }

    // 没用
    @Override
    public boolean isPerInstance() {
        return true;
    }
});

UserService proxy = (UserService) proxyFactory.getProxy();

proxy.test();

2、认识TargetSource

(1)何时用到TargetSource

我们在调用proxyFactory.setTarget方法时,是将原始对象封装为了SingletonTargetSource。
在这里插入图片描述
SingletonTargetSource实现了TargetSource接口,相当于非常简单的一个TargetSource。

// 动态目标源可以支持池化、热插拔等。
public interface TargetSource extends TargetClassAware {

	// 返回TargetSource返回的目标类型。
	@Override
	@Nullable
	Class<?> getTargetClass();

	// true表示目标不可变,意味着会缓存Target
	boolean isStatic();

	// 返回目标实例。在AOP框架调用AOP方法调用的“目标”之前立即调用。
	@Nullable
	Object getTarget() throws Exception;

	// 释放从getTarget()方法获得的给定目标对象(如果有的话)。
	void releaseTarget(Object target) throws Exception;

}

其实,AOP代理的对象,每次调用代理对象的方法时,获取的原始对象就是从TargetSource 的getTarget方法中获取的,这就意味着具备了很强的灵活性。

(2)@Lazy的原理

@Autowired
private UserService userService;

在属性注入时,使用@Lazy注解,并不会初始化Bean,而是将代理对象赋值给了属性。

我们看一下@Lazy属性赋值的源码:

// org.springframework.context.annotation.ContextAnnotationAutowireCandidateResolver#buildLazyResolutionProxy
protected Object buildLazyResolutionProxy(final DependencyDescriptor descriptor, final @Nullable String beanName) {
	BeanFactory beanFactory = getBeanFactory();
	Assert.state(beanFactory instanceof DefaultListableBeanFactory,
			"BeanFactory needs to be a DefaultListableBeanFactory");
	final DefaultListableBeanFactory dlbf = (DefaultListableBeanFactory) beanFactory;

	TargetSource ts = new TargetSource() {
		@Override
		public Class<?> getTargetClass() {
			return descriptor.getDependencyType();
		}
		@Override
		public boolean isStatic() {
			return false;
		}
		@Override
		public Object getTarget() {
			Set<String> autowiredBeanNames = (beanName != null ? new LinkedHashSet<>(1) : null);
			Object target = dlbf.doResolveDependency(descriptor, beanName, autowiredBeanNames, null);
			if (target == null) {
				Class<?> type = getTargetClass();
				if (Map.class == type) {
					return Collections.emptyMap();
				}
				else if (List.class == type) {
					return Collections.emptyList();
				}
				else if (Set.class == type || Collection.class == type) {
					return Collections.emptySet();
				}
				throw new NoSuchBeanDefinitionException(descriptor.getResolvableType(),
						"Optional dependency not present for lazy injection point");
			}
			if (autowiredBeanNames != null) {
				for (String autowiredBeanName : autowiredBeanNames) {
					if (dlbf.containsBean(autowiredBeanName)) {
						dlbf.registerDependentBean(autowiredBeanName, beanName);
					}
				}
			}
			return target;
		}
		@Override
		public void releaseTarget(Object target) {
		}
	};

	ProxyFactory pf = new ProxyFactory();
	pf.setTargetSource(ts);
	Class<?> dependencyType = descriptor.getDependencyType();
	if (dependencyType.isInterface()) {
		pf.addInterface(dependencyType);
	}
	return pf.getProxy(dlbf.getBeanClassLoader());
}

上面的源码可以看出,就是将属性赋值了一个代理对象,而TargetSource 的getTarget方法,就是从容器中获取目标对象的Bean进行返回。很巧妙的实现了懒加载。

(3)应用TargetSource

实际上我们日常开发中,很少会用到TargetSource。

我们也可以使用TargetSource实现懒加载、池化(每次获取Target都是从池子里获取)、热插拔(每次获取Target都是重新获取)。

3、ProxyFactory选择cglib或jdk动态代理原理

ProxyFactory在生成代理对象之前需要决定到底是使用JDK动态代理还是CGLIB技术:

// org.springframework.aop.framework.DefaultAopProxyFactory#createAopProxy
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
	// 是GraalVM 就直接用jdk代理
	// Optimize == true或者isProxyTargetClass == true 或者配置了接口,就走jdk
	if (!NativeDetector.inNativeImage() &&
			(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代理类了 或 lambda表达式 就用jdk
		if (targetClass.isInterface() || Proxy.isProxyClass(targetClass) || ClassUtils.isLambdaClass(targetClass)) {
			return new JdkDynamicAopProxy(config);
		}
		return new ObjenesisCglibAopProxy(config);
	}
	else {
		return new JdkDynamicAopProxy(config);
	}
}

然后获取代理类的方法,就是jdk和cglib代理的逻辑。

4、jdk代理获取代理方法的逻辑

JdkDynamicAopProxy实现了InvocationHandler方法,JdkDynamicAopProxy调用其getProxy方法,执行目标方法就会执行JdkDynamicAopProxy的invoke方法:

	@Override
	@Nullable
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		Object oldProxy = null;
		boolean setProxyContext = false;
		// 拿到被代理对象
		TargetSource targetSource = this.advised.targetSource;
		Object target = null;

		try {
			// 如果接口中没有定义equals()方法,那么直接调用,不走代理
			if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
				// The target does not implement the equals(Object) method itself.
				return equals(args[0]);
			}
			else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
				// The target does not implement the hashCode() method itself.
				return hashCode();
			}
			else if (method.getDeclaringClass() == DecoratingProxy.class) {
				// There is only getDecoratedClass() declared -> dispatch to proxy config.
				// 得到代理对象的类型,而不是所实现的接口
				return AopProxyUtils.ultimateTargetClass(this.advised);
			}
			else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
					method.getDeclaringClass().isAssignableFrom(Advised.class)) {
				// Service invocations on ProxyConfig with the proxy config...
				// 也是直接调用Advised接口中的方法,不走代理逻辑
				// 其实就是利用代理对象获取ProxyFactory中的信息
				return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
			}

			Object retVal;
			// 如果ProxyFactory的exposeProxy为true,则将代理对象设置到currentProxy这个ThreadLocal中去
			// 如果使用@EnableAspectJAutoProxy注解,需要手动将该参数设置为true,默认为false
			if (this.advised.exposeProxy) {
				// Make invocation available if necessary.
				oldProxy = AopContext.setCurrentProxy(proxy);
				setProxyContext = true;
			}

			// Get as late as possible to minimize the time we "own" the target,
			// in case it comes from a pool.
			// 被代理对象和代理类
			target = targetSource.getTarget();
			Class<?> targetClass = (target != null ? target.getClass() : null);

			// Get the interception chain for this method.
			// 代理对象在执行某个方法时,根据方法筛选出匹配的Advisor,并适配成Interceptor 代理链
			List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

			// Check whether we have any advice. If we don't, we can fall back on direct
			// reflective invocation of the target, and avoid creating a MethodInvocation.
			if (chain.isEmpty()) {
				// We can skip creating a MethodInvocation: just invoke the target directly
				// Note that the final invoker must be an InvokerInterceptor so we know it does
				// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
				// 如果没有Advice,则直接调用对应方法
				Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
				retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
			}
			else {
				// We need to create a method invocation...
				MethodInvocation invocation =
						new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
				// Proceed to the joinpoint through the interceptor chain.
				retVal = invocation.proceed(); // 执行下一步
			}

			// Massage return value if necessary.
			Class<?> returnType = method.getReturnType();
			if (retVal != null && retVal == target &&
					returnType != Object.class && returnType.isInstance(proxy) &&
					!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
				// Special case: it returned "this" and the return type of the method
				// is type-compatible. Note that we can't help if the target sets
				// a reference to itself in another returned object.
				retVal = proxy;
			}
			else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
				throw new AopInvocationException(
						"Null return value from advice does not match primitive return type for: " + method);
			}
			return retVal;
		}
		finally {
			if (target != null && !targetSource.isStatic()) {
				// Must have come from TargetSource.
				targetSource.releaseTarget(target);
			}
			if (setProxyContext) {
				// Restore old proxy.
				AopContext.setCurrentProxy(oldProxy);
			}
		}
	}

(1)getInterceptorsAndDynamicInterceptionAdvice获取拦截器链

// org.springframework.aop.framework.AdvisedSupport#getInterceptorsAndDynamicInterceptionAdvice
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
	// 代理对象在执行某个方法时,会根据当前ProxyFactory中所设置的Advisor根据当前method再次进行过滤
	MethodCacheKey cacheKey = new MethodCacheKey(method);
	// 注意这个List,表示的就是Advice,有缓存。
	List<Object> cached = this.methodCache.get(cacheKey);
	if (cached == null) {
		cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
				this, method, targetClass);
		this.methodCache.put(cacheKey, cached);
	}
	return cached;
}
// org.springframework.aop.framework.DefaultAdvisorChainFactory#getInterceptorsAndDynamicInterceptionAdvice
@Override
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
		Advised config, Method method, @Nullable Class<?> targetClass) {

	// This is somewhat tricky... We have to process introductions first,
	// but we need to preserve order in the ultimate list.
	AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
	// 从ProxyFactory中拿到所设置的Advice,(添加时被封装成了DefaultPointcutAdvisor)
	// 添加的时候会控制顺序
	Advisor[] advisors = config.getAdvisors();
	List<Object> interceptorList = new ArrayList<>(advisors.length);
	Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
	Boolean hasIntroductions = null;

	for (Advisor advisor : advisors) {
		if (advisor instanceof PointcutAdvisor) {
			// Add it conditionally.
			PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
			// 先匹配类
			if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
				MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
				boolean match;
				// 再匹配方法
				if (mm instanceof IntroductionAwareMethodMatcher) {
					if (hasIntroductions == null) {
						hasIntroductions = hasMatchingIntroductions(advisors, actualClass