当前位置: 代码迷 >> 综合 >> Spring(十八)Spring AOP createProxy 创建JDK代理 过程
  详细解决方案

Spring(十八)Spring AOP createProxy 创建JDK代理 过程

热度:37   发布时间:2024-02-08 03:20:29.0

上篇文章主要有以下几个主题:

  1. 围绕SpringBoot AOP加载原理。
  2. Spring AOP 是嵌入在Spring 容器启动哪个阶段。
  3. 不进行增强的原理,其中包含寻找增强器(Advisor)逻辑。

本文将围绕 创建代理过程 进行更近一步研究。

postProcessAfterInitialization

还是从Spring 容器处理器固定方法开始,AbstractAutoProxyCreator定义的 postProcessAfterInitialization ,当每个bean初始化完,都会执行这个方法:

	@Overridepublic Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {if (bean != null) {// 获取缓存的keyObject cacheKey = getCacheKey(bean.getClass(), beanName);if (this.earlyProxyReferences.remove(cacheKey) != bean) {return wrapIfNecessary(bean, beanName, cacheKey);}}return bean;}

上面方法,简单获取完用于缓存的key后,就进入到 wrapIfNecessary 方法进行具体包装:

	protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {// 如果已经是 targetSourceBean了,即为增强器,那么就不进行代理,直接返回if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {return bean;}// 不在advisedBeans 中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;}// 获取所有过滤器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;}

上面方法除了普通检查外,需要对两行代码具体分析。

获取所有过滤器Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);

		// 创建代理过程Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));

getAdvicesAndAdvisorsForBean

看这个方法具体内容:

	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();List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);// 是否设置在头结点设置 ExposeInvocationInterceptor 类型切点拦截器advisorextendAdvisors(eligibleAdvisors);if (!eligibleAdvisors.isEmpty()) {eligibleAdvisors = sortAdvisors(eligibleAdvisors);}return eligibleAdvisors;}

对于bean的增强,肯定有两个方面:

  1. 获取所有的增强器这在 findCandidateAdvisors 体现。
  2. 利用第一步中找到的增强器,找到该bean适用的增强器,在 findAdvisorThatCanApply

findCandidateAdvisors

	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;}

这个方法在上一篇文章中有详细介绍,总结如下:

  1. 加载xml中配置接口,或者继承 Advisor 类的 配置接口。
  2. 使用 BeanFactoryAspectJAdvisorsBuilder 去搜寻使用 @Aspectj 注解类,并构建的 Advisor

findAdvisorsThatCanApply

上一步中,完成了所有增强器的解析,但是并不是所有都适用于当前bean,所以需要进一步过滤:

	protected List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {// 设置当前正在装配的beanNameProxyCreationContext.setCurrentProxiedBeanName(beanName);try {// 筛选出合适的Advisorreturn AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);}finally {ProxyCreationContext.setCurrentProxiedBeanName(null);}}

findAdvisorsThatCanApply:

	public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {if (candidateAdvisors.isEmpty()) {return candidateAdvisors;}List<Advisor> eligibleAdvisors = new ArrayList<>();// 处理 IntroductionAdvisor 类型增强器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 processedcontinue;}// 对于普通bean处理if (canApply(candidate, clazz, hasIntroductions)) {eligibleAdvisors.add(candidate);}}return eligibleAdvisors;}

如何才能确定,这个bean的这些方法需要增强呢?看canApply方法:

	public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {if (advisor instanceof IntroductionAdvisor) {// IntroductionAdvisor 类型advisorreturn ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);}else if (advisor instanceof PointcutAdvisor) {// 切点增强器advisorPointcutAdvisor pca = (PointcutAdvisor) advisor;return canApply(pca.getPointcut(), targetClass, hasIntroductions);}else {默认返回truereturn true;}}

即使用每个注解上面配置的 PointCut 注解进行匹配,匹配完后即 加入到 eligibleAdvisors 中。

createProxy

搜寻完,过滤完,即开始进入创建代理过程,入口方法为 createProxy

	protected Object createProxy(Class<?> beanClass, @Nullable String beanName,@Nullable Object[] specificInterceptors, TargetSource targetSource) {// 设置该bean的 originalTargetClass 属性if (this.beanFactory instanceof ConfigurableListableBeanFactory) {AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);}// 定义代理工厂类ProxyFactory proxyFactory = new ProxyFactory();proxyFactory.copyFrom(this);// 设置代理规则,使用jdk还是cglibif (!proxyFactory.isProxyTargetClass()) {if (shouldProxyTargetClass(beanClass, beanName)) {proxyFactory.setProxyTargetClass(true);}else {evaluateProxyInterfaces(beanClass, proxyFactory);}}// 将上一步获取的过滤后的specificInterceptors ,转化为advisorAdvisor[] advisors = buildAdvisors(beanName, specificInterceptors);// 增加 advisor增强器proxyFactory.addAdvisors(advisors);// 设置targetSourceproxyFactory.setTargetSource(targetSource);customizeProxyFactory(proxyFactory);// 设置freezen属性,默认为false,即代理配置后,不允许修改代理值。proxyFactory.setFrozen(this.freezeProxy);if (advisorsPreFiltered()) {proxyFactory.setPreFiltered(true);}// 生成并获取操作。return proxyFactory.getProxy(getProxyClassLoader());}

上面即是创建代理过程,Spring将其委托给ProxyFactory处理,这里主要是对ProxyFactory进行初始化工作。

	public Object getProxy(@Nullable ClassLoader classLoader) {return createAopProxy().getProxy(classLoader);}

中间有一部创建Aop代理工厂过程:

	protected final synchronized AopProxy createAopProxy() {if (!this.active) {activate();}return getAopProxyFactory().createAopProxy(this);}

DefaultAopProxyFactorycreateAopProxy 方法:

	@Overridepublic 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.");}if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {return new JdkDynamicAopProxy(config);}return new ObjenesisCglibAopProxy(config);}else {return new JdkDynamicAopProxy(config);}}

上面方法主要是判断使用何种代理:
是否 设置优化optimize,或者设置proxyTargetClass或者代理类没有接口,将影响Spring使用代理方式。

  1. 如果目标对象,实现了接口,默认情况采用jdk动态代理。
  2. 如果目标对象实现接口,可以强制使用CGLIB实现AOP。
  3. 如果没有实现接口,那么必须采用CGLIB库,Spring会自动在JDK动态代理和CGLIB之间切换。

JDK和CGLIB字节码区别:

  • JDK动态代理只能对实现接口的类生成代理,而不针对类。
  • CGLIB是针对类,实现方式为对类生成一个子类,覆盖其中方法,因为是集成,所以无法集成final方法或者类。

具体JDK和CGLIB例子可以看博主文章:

  1. jdk: https://blog.csdn.net/anLA_/article/details/77074557
  2. cglib:https://blog.csdn.net/anLA_/article/details/77074955

JdkDynamicAopProxy

对于JDK代理,有以下几个点:

  1. 继承 InvocationHandler
  2. 将代理对象传入,通过构造方法,或者普通方法。
  3. 重写invoke方法
  4. getProxy方法,获取代理后的对象
    既然创建的是代理,并且后文还会执行代理类的getProxy,所以直接看具体方法:
	@Overridepublic Object getProxy(@Nullable ClassLoader classLoader) {if (logger.isTraceEnabled()) {logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());}// 获取所有代理接口Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);// 配置equals和hashCode接口findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);// 生成代理return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);}

completeProxiedInterfaces 中,主要是添加 SpringProxyAdvisedDecoratingProxy三种类型接口以及当前bean自身实现的接口bean。

代理生成完毕,接下来看 invoke方法中内容:

	@Override@Nullablepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 用于保留旧对象Object oldProxy = null;boolean setProxyContext = false;// 获取targetSourceTargetSource targetSource = this.advised.targetSource;Object target = null;try {if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {// equals方法,直接执行// 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.// hashcode方法,直接执行return hashCode();}else if (method.getDeclaringClass() == DecoratingProxy.class) {// There is only getDecoratedClass() declared -> dispatch to proxy config.// 如果是 执行 DecoratingProxy 的几个方法,那么直接执行 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 的方法return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);}Object retVal;// 用于处理,目标对象自我调用命中切面,需要使用此属性来暴露。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.// 获取当前方法的执行链List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);// Check whether we have any advice. If we don't, we can fallback 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.Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);}else {// 由前面的执行链路,创建一个MethodInvocation执行。MethodInvocation invocation =new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);// 具体执行方法retVal = invocation.proceed();}// 如果有返回值,则获取类型并返回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) {// 设置为原始的代理执行对象AopContext.setCurrentProxy(oldProxy);}}}

除了最开始几个if对方法类型及参数判断,主要逻辑还是在过滤器链逻辑组装处。

AOP过滤器链

对上面部分代码选出来分析:

			List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);if (chain.isEmpty()) {Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);}else {MethodInvocation invocation =new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);retVal = invocation.proceed();}

JdkDynamicAopProxyadvised 为构造方法创建时传入,就是上面构造的 ProxyFactory 对象。
获取过滤器链操作:

	public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {MethodCacheKey cacheKey = new MethodCacheKey(method);List<Object> cached = this.methodCache.get(cacheKey);if (cached == null) {cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(this, method, targetClass);this.methodCache.put(cacheKey, cached);}return cached;}

advisorChainFactory 中获取过滤器链,主要过程就是讲该方法去和过滤器链匹配,如果能够匹配,则将对应增强器返回。

MethodInvocation

当找到过滤器链后,会构造一个 ReflectiveMethodInvocation 开始执行链路。

	public Object proceed() throws Throwable {//	如果执行按了,那么直接执行对应方法if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {return invokeJoinpoint();}// 通过索引,获取下一个链Object interceptorOrInterceptionAdvice =this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {// Evaluate dynamic method matcher here: static part will already have// been evaluated and found to match.// 执行 InterceptorAndDynamicMethodMatcher 操作。InterceptorAndDynamicMethodMatcher dm =(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {return dm.interceptor.invoke(this);}else {// Dynamic matching failed.// Skip this interceptor and invoke the next in the chain.return proceed();}}else {// It's an interceptor, so we just invoke it: The pointcut will have// been evaluated statically before this object was constructed.// 执行对应方法return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);}}

整个执行链路可以总结为:

  1. 每当命中要拦截方法,则会获取所有advisor的执行器链。
  2. 最后进入 retVal = invocation.proceed(); 执行所有链路。
  3. 通过自带 currentInterceptorIndex 变量标识顺序,而不需要重新进入JdkDynamicAopProxy拦截
  4. 执行完后,如果有返回值,则返回对应值。

觉得博主写的有用,不妨关注博主公众号: 六点A君。
哈哈哈,一起研究Spring:
在这里插入图片描述

  相关解决方案