【Seata源码学习 】 扫描@GlobalTransaction注解 篇一

1. SeataAutoConfiguration 自动配置类的加载

基于SpringBoot的starter机制,在应用上下文启动时,会加载SeataAutoConfiguration自动配置类

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=io.seata.spring.boot.autoconfigure.SeataAutoConfiguration

此配置类将会往应用上下文中注册四个组件

image-20231110213016125

从名字就知道,此组件负责扫描@GlobalTransaction

此类的继承关系如下图所示

截屏2023-11-10 21.32.30

2. @GlobalTransaction注解扫描

父类 AbstractAutoProxyCreator 实现了 SmartInstantiationAwareBeanPostProcessor 接口,重写了 postProcessAfterInitialization 方法

	public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {if (bean != null) {Object cacheKey = getCacheKey(bean.getClass(), beanName);if (this.earlyProxyReferences.remove(cacheKey) != bean) {return wrapIfNecessary(bean, beanName, cacheKey);}}return bean;}

io.seata.spring.annotation.GlobalTransactionScanner#wrapIfNecessary

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {// do checkersif (!doCheckers(bean, beanName)) {return bean;}try {synchronized (PROXYED_SET) {if (PROXYED_SET.contains(beanName)) {return bean;}interceptor = null;//check TCC proxyif (TCCBeanParserUtils.isTccAutoProxy(bean, beanName, applicationContext)) {// init tcc fence clean task if enable useTccFenceTCCBeanParserUtils.initTccFenceCleanTask(TCCBeanParserUtils.getRemotingDesc(beanName), applicationContext);//TCC interceptor, proxy bean of sofa:reference/dubbo:reference, and LocalTCCinterceptor = new TccActionInterceptor(TCCBeanParserUtils.getRemotingDesc(beanName));ConfigurationCache.addConfigListener(ConfigurationKeys.DISABLE_GLOBAL_TRANSACTION,(ConfigurationChangeListener)interceptor);} else {//很实用的两个工具类//查找类的原始类 而非代理类Class<?> serviceInterface = SpringProxyUtils.findTargetClass(bean);//查找类所有实现的接口Class<?>[] interfacesIfJdk = SpringProxyUtils.findInterfaces(bean);// 类上面是否有GlobalTransactional 注解  方法上面是否有标 GlobalTransactional GlobalLock注解if (!existsAnnotation(new Class[]{serviceInterface})// 接口上面是否有GlobalTransactional 注解  方法上面是否有标 GlobalTransactional GlobalLock注解&& !existsAnnotation(interfacesIfJdk)) {return bean;}//如果有 成员变量 MethodInterceptor  interceptor 赋值if (globalTransactionalInterceptor == null) {globalTransactionalInterceptor = new GlobalTransactionalInterceptor(failureHandlerHook);ConfigurationCache.addConfigListener(ConfigurationKeys.DISABLE_GLOBAL_TRANSACTION,(ConfigurationChangeListener)globalTransactionalInterceptor);}interceptor = globalTransactionalInterceptor;}LOGGER.info("Bean[{}] with name [{}] would use interceptor [{}]", bean.getClass().getName(), beanName, interceptor.getClass().getName());if (!AopUtils.isAopProxy(bean)) {//当前类没有被AOP代理过bean = super.wrapIfNecessary(bean, beanName, cacheKey);} else {//当前类被AOP代理过//AdvisedSupport对象是Spring框架中用于支持AOP的核心类之一,它封装了AOP代理的配置信息和运行时状态。// 通过获取AdvisedSupport对象,可以进一步了解和操作代理对象的AOP配置AdvisedSupport advised = SpringProxyUtils.getAdvisedSupport(bean);// AdvisedSupport :  Advisor 一对多//Spring AOP 中的 Advisor 是一种拦截器,// 它可以拦截特定的方法调用,并在方法调用前、后或异常时执行一些特定的操作//getAdvicesAndAdvisorsForBean 方法将返回我们上一步创建的GlobalTransactionalInterceptor//buildAdvisors 方法 将 MethodInterceptor 构建成一个  Advisor 用于后续创建代理类Advisor[] advisor = buildAdvisors(beanName, getAdvicesAndAdvisorsForBean(null, null, null));int pos;for (Advisor avr : advisor) {// Find the position based on the advisor's order, and add to advisors by pos//调整advisor 的位置pos = findAddSeataAdvisorPosition(advised, avr);advised.addAdvisor(pos, avr);}}//记录已经代理过的beanNamePROXYED_SET.add(beanName);//返回当前beanreturn bean;}} catch (Exception exx) {throw new RuntimeException(exx);}}

创建代理类情况一 :当前bean已经被AOP代理过

通常@GlobalTransation注解标注在业务层,而业务层的bean大多走到这已经被AOP代理过。如果你项目中使用的是MybatisPlus,那么通常会被org.springframework.transaction.interceptor.BeanFactoryTransactionAttributeSourceAdvisor创建代理类

image-20231110223907806

AdvisedSupport 添加一个Advisor( GlobalTransactionalInterceptor )后,将之前就被代理过的bean返回,你可能会好奇,添加一个 Advisor 就不管了 ? 最终谁来调用呢 ?

class org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator

继承了 AspectJAwareAdvisorAutoProxyCreator 继承了 AbstractAdvisorAutoProxyCreator 继承了 AbstractAutoProxyCreator 实现了 SmartInstantiationAwareBeanPostProcessor,

将在每个bean实例化后执行 postProcessAfterInitialization 方法,

org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessAfterInitialization

org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#wrapIfNecessary

org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBean

org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#findEligibleAdvisors

最终将找到 org.springframework.transaction.interceptor.BeanFactoryTransactionAttributeSourceAdvisor:

	protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {//查找所有的AdvisorList<Advisor> candidateAdvisors = findCandidateAdvisors();//判断当前bean是否满足Advisor的拦截要求List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);extendAdvisors(eligibleAdvisors);if (!eligibleAdvisors.isEmpty()) {eligibleAdvisors = sortAdvisors(eligibleAdvisors);}return eligibleAdvisors;}

Advisor 你可以理解为绑定了ponitcut的Advice 容器 , BeanFactoryTransactionAttributeSourceAdvisor绑定的为 TransactionAttributeSourcePointcut

方法的匹配规则

@Overridepublic boolean matches(Method method, Class<?> targetClass) {TransactionAttributeSource tas = getTransactionAttributeSource();return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);}

类的匹配规则

org.springframework.transaction.annotation.SpringTransactionAnnotationParser#isCandidateClass

@Overridepublic boolean isCandidateClass(Class<?> targetClass) {//当前类上是否有 Transactional 注解return AnnotationUtils.isCandidateClass(targetClass, Transactional.class);}

而获取方法是的代码如下

org.springframework.aop.support.AopUtils#canApply(org.springframework.aop.Pointcut, java.lang.Class<?>, boolean)

		for (Class<?> clazz : classes) {//getAllDeclaredMethods 获取当前类包括父类的所有方法Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);for (Method method : methods) {if (introductionAwareMethodMatcher != null ?introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :methodMatcher.matches(method, targetClass)) {return true;}}}

我们使用的MybatisPlus通常业务层的类会继承ServiceImpl,而ServiceImpl类中有不少方法就是标注了@Transactional注解,因此 BeanFactoryTransactionAttributeSourceAdvisor 对当前的业务层bean来说,是满足匹配规则的

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

回到

org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#wrapIfNecessary

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {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.//拿到 BeanFactoryTransactionAttributeSourceAdvisor 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;}
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,@Nullable Object[] specificInterceptors, TargetSource targetSource) {if (this.beanFactory instanceof ConfigurableListableBeanFactory) {AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);}//创建 ProxyFactory 对象,ProxyFactory proxyFactory = new ProxyFactory();proxyFactory.copyFrom(this);if (!proxyFactory.isProxyTargetClass()) {if (shouldProxyTargetClass(beanClass, beanName)) {proxyFactory.setProxyTargetClass(true);}else {evaluateProxyInterfaces(beanClass, proxyFactory);}}//创建 Advisor 链Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);proxyFactory.addAdvisors(advisors);//设置代理目标类proxyFactory.setTargetSource(targetSource);customizeProxyFactory(proxyFactory);proxyFactory.setFrozen(this.freezeProxy);if (advisorsPreFiltered()) {proxyFactory.setPreFiltered(true);}//创建目标代理类return proxyFactory.getProxy(getProxyClassLoader());}

通常情况下会使用CGLB进行创建代理类

org.springframework.aop.framework.CglibAopProxy#getProxy(java.lang.ClassLoader)

public Object getProxy(@Nullable ClassLoader classLoader) {if (logger.isTraceEnabled()) {logger.trace("Creating CGLIB proxy: " + this.advised.getTargetSource());}try {Class<?> rootClass = this.advised.getTargetClass();Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");Class<?> proxySuperClass = rootClass;if (rootClass.getName().contains(ClassUtils.CGLIB_CLASS_SEPARATOR)) {proxySuperClass = rootClass.getSuperclass();Class<?>[] additionalInterfaces = rootClass.getInterfaces();for (Class<?> additionalInterface : additionalInterfaces) {this.advised.addInterface(additionalInterface);}}// Validate the class, writing log messages as necessary.validateClassIfNecessary(proxySuperClass, classLoader);// 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);}catch (CodeGenerationException | IllegalArgumentException ex) {throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() +": Common causes of this problem include using a final class or a non-visible class",ex);}catch (Throwable ex) {// TargetSource.getTarget() failedthrow new AopConfigException("Unexpected AOP exception", ex);}}
private Callback[] getCallbacks(Class<?> rootClass) throws Exception {// Parameters used for optimization choices...boolean exposeProxy = this.advised.isExposeProxy();boolean isFrozen = this.advised.isFrozen();boolean isStatic = this.advised.getTargetSource().isStatic();// Choose an "aop" interceptor (used for AOP calls).//用于aop的回调函数Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);// Choose a "straight to target" interceptor. (used for calls that are// unadvised but can return this). May be required to expose the proxy.Callback targetInterceptor;if (exposeProxy) {targetInterceptor = (isStatic ?new StaticUnadvisedExposedInterceptor(this.advised.getTargetSource().getTarget()) :new DynamicUnadvisedExposedInterceptor(this.advised.getTargetSource()));}else {targetInterceptor = (isStatic ?new StaticUnadvisedInterceptor(this.advised.getTargetSource().getTarget()) :new DynamicUnadvisedInterceptor(this.advised.getTargetSource()));}// Choose a "direct to target" dispatcher (used for// unadvised calls to static targets that cannot return this).Callback targetDispatcher = (isStatic ?new StaticDispatcher(this.advised.getTargetSource().getTarget()) : new SerializableNoOp());//6个默认的回调函数Callback[] mainCallbacks = new Callback[] {aopInterceptor,  // for normal advicetargetInterceptor,  // invoke target without considering advice, if optimizednew SerializableNoOp(),  // no override for methods mapped to thistargetDispatcher, this.advisedDispatcher,new EqualsInterceptor(this.advised),new HashCodeInterceptor(this.advised)};Callback[] callbacks;// If the target is a static one and the advice chain is frozen,// then we can make some optimizations by sending the AOP calls// direct to the target using the fixed chain for that method.if (isStatic && isFrozen) {Method[] methods = rootClass.getMethods();Callback[] fixedCallbacks = new Callback[methods.length];this.fixedInterceptorMap = new HashMap<>(methods.length);// TODO: small memory optimization here (can skip creation for methods with no advice)for (int x = 0; x < methods.length; x++) {Method method = methods[x];//将 advisor集合转化为 MethodInterceptor 集合List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, rootClass);fixedCallbacks[x] = new FixedChainStaticTargetInterceptor(chain, this.advised.getTargetSource().getTarget(), this.advised.getTargetClass());this.fixedInterceptorMap.put(method, x);}// Now copy both the callbacks from mainCallbacks// and fixedCallbacks into the callbacks array.callbacks = new Callback[mainCallbacks.length + fixedCallbacks.length];System.arraycopy(mainCallbacks, 0, callbacks, 0, mainCallbacks.length);System.arraycopy(fixedCallbacks, 0, callbacks, mainCallbacks.length, fixedCallbacks.length);this.fixedInterceptorOffset = mainCallbacks.length;}else {callbacks = mainCallbacks;}return callbacks;}

看一下callbackFilter 设置的 callback回调规则

public int accept(Method method) {if (AopUtils.isFinalizeMethod(method)) {logger.trace("Found finalize() method - using NO_OVERRIDE");return NO_OVERRIDE; //如果是finalize方法,执行targetInterceptor回调函数,相当于什么都没做}//方法是否在Advised接口上声明。如果是,则返回DISPATCH_ADVISED,表示需要回调 advisedDispatcher 函数if (!this.advised.isOpaque() && method.getDeclaringClass().isInterface() &&method.getDeclaringClass().isAssignableFrom(Advised.class)) {if (logger.isTraceEnabled()) {logger.trace("Method is declared on Advised interface: " + method);}return DISPATCH_ADVISED;}// 检查方法是否为equals()方法或hashCode()方法,如果是,则分别返回INVOKE_EQUALS和INVOKE_HASHCODE,表示需要调用EqualsInterceptor 回调函数或 HashCodeInterceptor 回调函数if (AopUtils.isEqualsMethod(method)) {if (logger.isTraceEnabled()) {logger.trace("Found 'equals' method: " + method);}return INVOKE_EQUALS;}// We must always calculate hashCode based on the proxy.if (AopUtils.isHashCodeMethod(method)) {if (logger.isTraceEnabled()) {logger.trace("Found 'hashCode' method: " + method);}return INVOKE_HASHCODE;}//获取目标类Class<?> targetClass = this.advised.getTargetClass();// Proxy is not yet available, but that shouldn't matter.//获取方法拦截器链List<?> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);boolean haveAdvice = !chain.isEmpty();boolean exposeProxy = this.advised.isExposeProxy();boolean isStatic = this.advised.getTargetSource().isStatic();boolean isFrozen = this.advised.isFrozen();//chain  不为空 且未冻结if (haveAdvice || !isFrozen) {// If exposing the proxy, then AOP_PROXY must be used.if (exposeProxy) {if (logger.isTraceEnabled()) {logger.trace("Must expose proxy on advised method: " + method);}return AOP_PROXY; // 使用aopInterceptor 回调函数}// Check to see if we have fixed interceptor to serve this method.// Else use the AOP_PROXY.//方法是静态的、代理已被冻结,并且存在固定的拦截器来处理该方法,则返回固定拦截器的索引加上固定拦截器偏移量。这段代码用于判断是否存在固定的拦截器来处理该方法,并返回相应的处理方式。如果存在固定的拦截器,则返回固定拦截器的索引加上偏移量;否则,返回AOP_PROXY,表示需要使用AOP代理进行处理。if (isStatic && isFrozen && this.fixedInterceptorMap.containsKey(method)) {if (logger.isTraceEnabled()) {logger.trace("Method has advice and optimizations are enabled: " + method);}// We know that we are optimizing so we can use the FixedStaticChainInterceptors.int index = this.fixedInterceptorMap.get(method);return (index + this.fixedInterceptorOffset);}else {if (logger.isTraceEnabled()) {logger.trace("Unable to apply any optimizations to advised method: " + method);}return AOP_PROXY;}}else {// See if the return type of the method is outside the class hierarchy of the target type.// If so we know it never needs to have return type massage and can use a dispatcher.// If the proxy is being exposed, then must use the interceptor the correct one is already// configured. If the target is not static, then we cannot use a dispatcher because the// target needs to be explicitly released after the invocation.if (exposeProxy || !isStatic) {return INVOKE_TARGET;}Class<?> returnType = method.getReturnType();if (targetClass != null && returnType.isAssignableFrom(targetClass)) {if (logger.isTraceEnabled()) {logger.trace("Method return type is assignable from target type and " +"may therefore return 'this' - using INVOKE_TARGET: " + method);}return INVOKE_TARGET;}else {if (logger.isTraceEnabled()) {logger.trace("Method return type ensures 'this' cannot be returned - " +"using DISPATCH_TARGET: " + method);}return DISPATCH_TARGET;}}}

在回到之前那个问题,AdvisedSupport 添加一个Advisor( GlobalTransactionalInterceptor )后,将之前就被代理过的bean返回,当前bean的业务方法在执行时,就会由callbackFilter匹配上 aopInterceptor 回调函数并执行

Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);

DynamicAdvisedInterceptor 是 CglibAopProxy 的静态内部类 ,实现了 MethodInterceptor 接口

	private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable {private final AdvisedSupport advised;public DynamicAdvisedInterceptor(AdvisedSupport advised) {this.advised = advised;}@Override@Nullablepublic Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {Object oldProxy = null;boolean setProxyContext = false;Object target = null;TargetSource targetSource = this.advised.getTargetSource();try {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);// 获取方法拦截器链List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);Object retVal;// Check whether we only have one InvokerInterceptor: that is,// no real advice, but just reflective invocation of the target.if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {// 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 = methodProxy.invoke(target, argsToUse);}else {// We need to create a method invocation...//拦截器链路调用retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();}//返回值处理retVal = processReturnType(proxy, target, method, retVal);return retVal;}finally {if (target != null && !targetSource.isStatic()) {targetSource.releaseTarget(target);}if (setProxyContext) {// Restore old proxy.AopContext.setCurrentProxy(oldProxy);}}}@Overridepublic boolean equals(@Nullable Object other) {return (this == other ||(other instanceof DynamicAdvisedInterceptor &&this.advised.equals(((DynamicAdvisedInterceptor) other).advised)));}/*** CGLIB uses this to drive proxy creation.*/@Overridepublic int hashCode() {return this.advised.hashCode();}}

跟进 org.springframework.aop.framework.CglibAopProxy.CglibMethodInvocation#proceed

		@Override@Nullablepublic Object proceed() throws Throwable {try {return super.proceed();}catch (RuntimeException ex) {throw ex;}catch (Exception ex) {if (ReflectionUtils.declaresException(getMethod(), ex.getClass())) {throw ex;}else {throw new UndeclaredThrowableException(ex);}}}

父类 org.springframework.aop.framework.ReflectiveMethodInvocation#proceed

public Object proceed() throws Throwable {// We start with an index of -1 and increment early.// 如果当前拦截器链已经是最后一个了 调用目标方法if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {return invokeJoinpoint();}// currentInterceptorIndex 从 -1 开始,此时获取下表为0的方法拦截器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 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.//拦截器在此处调用  注意此处把 this 给传递过去了,每个拦截器在执行完毕后又会调用 this.proceed 进行递归调用return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);}}

创建代理类情况二 :当前bean已经未被AOP代理

回调 io.seata.spring.annotation.GlobalTransactionScanner#wrapIfNecessary

    if (!AopUtils.isAopProxy(bean)) {//如果当前类未被代理,则调用父类的wrapIfNecessary 方法bean = super.wrapIfNecessary(bean, beanName, cacheKey);} else {AdvisedSupport advised = SpringProxyUtils.getAdvisedSupport(bean);Advisor[] advisor = buildAdvisors(beanName, getAdvicesAndAdvisorsForBean(null, null, null));for (Advisor avr : advisor) {advised.addAdvisor(0, avr);}}
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {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.//调用子类 重写的 io.seata.spring.annotation.GlobalTransactionScanner#getAdvicesAndAdvisorsForBean 方法// 返回 GlobalTransactionalInterceptorObject[] 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;}

调用org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#createProxy,

创建 ProxyFactory 对象,设置目标代理类,添加advisors,最终创建代理类,对目标方法进行拦截来增强目标方法

protected Object createProxy(Class<?> beanClass, @Nullable String beanName,@Nullable Object[] specificInterceptors, TargetSource targetSource) {if (this.beanFactory instanceof ConfigurableListableBeanFactory) {AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);}ProxyFactory proxyFactory = new ProxyFactory();proxyFactory.copyFrom(this);if (!proxyFactory.isProxyTargetClass()) {if (shouldProxyTargetClass(beanClass, beanName)) {proxyFactory.setProxyTargetClass(true);}else {evaluateProxyInterfaces(beanClass, proxyFactory);}}//构建Advisor[] 用于方法拦截Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);proxyFactory.addAdvisors(advisors);//设置被代理类proxyFactory.setTargetSource(targetSource);customizeProxyFactory(proxyFactory);proxyFactory.setFrozen(this.freezeProxy);if (advisorsPreFiltered()) {proxyFactory.setPreFiltered(true);}//创建代理对象 最终底层通过 JDK动态代理或CGILIB代理创建代理对象return proxyFactory.getProxy(getProxyClassLoader());}

3.流程图

seata源码学习-导出

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/238776.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

DPDK单步跟踪(3)-如何利用visual studio 2019和visual gdb来单步调试dpdk

准备工作 因为时间的关系&#xff0c;我想到哪说到哪&#xff0c;可能没那么高的完成度。 但其实有心的人&#xff0c;看到这个标题&#xff0c;就关了本文自己能做了。 why和how to build debug version DPDK,见前两篇。这里我们准备开始。 首先&#xff0c;你有一台linux机…

算法题系列7·获得数组中多数元素

目录 题目描述 实现 提交结果 题目描述 给定一个大小为 n 的数组 nums &#xff0c;返回其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。 你可以假设数组是非空的&#xff0c;并且给定的数组总是存在多数元素。 示例 1&#xff1a; 输入&#xff1a;…

第11章 GUI Page400~402 步骤二 画直线

运行效果&#xff1a; 源代码&#xff1a; /**************************************************************** Name: wxMyPainterApp.h* Purpose: Defines Application Class* Author: yanzhenxi (3065598272qq.com)* Created: 2023-12-21* Copyright: yanzhen…

黑芝麻智能与亿咖通科技签署战略合作协议,深化协同助力智能驾驶量产落地

12月22日&#xff0c;全球智能汽车计算芯片引领者黑芝麻智能与全球出行科技企业亿咖通科技共同签署战略合作协议&#xff0c;通过深化合作&#xff0c;整合双方研发、产品和技术资源&#xff0c;联手打造领先智能驾驶系统解决方案&#xff0c;合力推进商业拓展和市场应用&#…

微前端样式隔离、sessionStorage、localStorage隔离

1、样式隔离 前端样式不隔离&#xff0c;会产生样式冲突的问题&#xff0c;这个点在qiankun也存在 子应用1修改一个样式 button {background: red&#xff01;important&#xff1b; }其它应用也会受到影响 qiankun的css隔离方案&#xff08;shadow dom&#xff09; shadow …

Hive-high Avaliabl

hive—high Avaliable ​ hive的搭建方式有三种&#xff0c;分别是 ​ 1、Local/Embedded Metastore Database (Derby) ​ 2、Remote Metastore Database ​ 3、Remote Metastore Server ​ 一般情况下&#xff0c;我们在学习的时候直接使用hive –service metastore的方式…

FreeRTOS之二值信号量(实践)

信号量相当于一个标志&#xff0c;实现对资源多少的管理。 比如停车场空位的数量。 这里使用的是二值信号量&#xff0c;其队列长度为1&#xff0c;只有空或满两种状态。 1、步骤&#xff1a; 1.1、创建信号量 1.2、释放信号量 1.3、获取信号量 注&#xff1a;若想深入还…

《深入理解计算机系统》学习笔记 - 第七课 - 机器级别的程序三

Lecture 07 Machine Level Programming III Procedures 机器级别的程序三 文章目录 Lecture 07 Machine Level Programming III Procedures 机器级别的程序三概述程序机制 栈结构栈说明栈定义推入数据弹出数据 调用控制代码示例程序控制流程%rip 传递数据ABI 标准示例 管理局部…

LangChain 29 调试Debugging 详细信息verbose

LangChain系列文章 LangChain 实现给动物取名字&#xff0c;LangChain 2模块化prompt template并用streamlit生成网站 实现给动物取名字LangChain 3使用Agent访问Wikipedia和llm-math计算狗的平均年龄LangChain 4用向量数据库Faiss存储&#xff0c;读取YouTube的视频文本搜索I…

计算机msvcp140.dll丢失的多种解决方法,哪种更值得推荐

在使用电脑进行工作&#xff0c;娱乐的时候&#xff0c;我们可能会遇到一些错误提示&#xff0c;其中之一就是“msvcp140.dll丢失”&#xff0c;这个问题可能会导致某些应用程序无法正常运行。msvcp140.dll是微软Visual C 2015运行库中的一个动态链接库文件&#xff0c;全名为M…

MyBatis的延迟加载!!!

首先&#xff1a;MyBatis的关联查询&#xff01;&#xff01;&#xff01;&#xff08;一对一、一对多、多对多&#xff09;-CSDN博客以这个项目为基础。 1.在UserMapper接口中创建一个方法&#xff1a; package com.by.mapper;import com.by.pojo.User;import java.util.Lis…

STM32的以太网外设+PHY(LAN8720)使用详解(5):MAC及DMA配置

0 工具准备 1.野火 stm32f407霸天虎开发板 2.LAN8720数据手册 3.STM32F4xx中文参考手册1 MAC及DMA配置 1.1 使能ETH时钟 stm32的ETH外设挂载在AHB1总线上&#xff0c;位于RCC_AHB1ENR的bit25-bit27&#xff1a; 相关语句如下&#xff1a; RCC_AHB1PeriphClockCmd(RCC_AHB1…

家政上门服务系统|上门服务系统让家政服务更便捷

家政上门服务系统搭建的目的是为了让用户在家政服务的过程中能够更加轻松、便捷地完成各项服务需求。我们的系统集成了多项先进功能&#xff0c;使得用户无需再花费时间和精力去寻找合适的服务员工。通过系统&#xff0c;用户只需在手机或者电脑上输入相关需求&#xff0c;系统…

突破性能瓶颈:使用Asyncio构建高并发Python应用程序

是一种处理多个任务同时执行的编程方式&#xff0c;在Python中&#xff0c;asyncio是一种用于实现异步编程的强大工具。asyncio基于协程&#xff08;coroutine&#xff09;的概念&#xff0c;能够高效地处理I/O密集型任务。本文将介绍asyncio的基本原理和使用方法。 为啥需要a…

万界星空开源MES/注塑MES/开源注塑MES/免费MES/MES源码

一、系统概述&#xff1a; 万界星空科技免费MES、开源MES、商业开源MES、市面上最好的开源MES、MES源代码、适合二开的开源MES、好看的数据大屏、功能齐全开源mes. 1.万界星空开源MES制造执行系统的Java开源版本。 开源mes系统包括系统管理&#xff0c;车间基础数据管理&…

鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之TextInput输入框组件

鸿蒙&#xff08;HarmonyOS&#xff09;项目方舟框架&#xff08;ArkUI&#xff09;之TextInput输入框组件 一、操作环境 操作系统: Windows 10 专业版 IDE:DevEco Studio 3.1 SDK:HarmonyOS 3.1 二、TextInput 接口 TextInput(value?:{placeholder?: ResourceStr, tex…

SpringSecurity深度解析与实践(2)

目录 引言1.Springboot结合SpringSecurity用户认证流程1.1 配置pom文件1.2.配置application.yml 2.自定义MD5加密3.BCryptPasswordEncoder密码编码器4.RememberMe记住我的实现5.CSRF防御5.1.什么是CSRF 引言 上篇网址 1.Springboot结合SpringSecurity用户认证流程 1.1 配置p…

过采样技术基本原理

本文介绍过采样技术基本原理。 过采样技术在ADC信号采集过程中使用还是比较多的。某些使用场景下&#xff0c;对采样速度要求并不是那么高&#xff08;或ADC采样速度过剩&#xff09;&#xff0c;但是想要获取较高的分辨率&#xff0c;就会用到这种技术&#xff0c;如针对温度…

【爬虫软件】孔夫子二手书采集

项目演示 孔网爬取图书信息 目录结构 [ |-- api-ms-win-core-synch-l1-2-0.dll, |-- api-ms-win-core-sysinfo-l1-1-0.dll, |-- api-ms-win-core-timezone-l1-1-0.dll, |-- api-ms-win-core-util-l1-1-0.dll, |-- api-ms-win-crt-conio-l1-1-0.dll, |-- api…

表格实现合并单元格

实现的效果 一、列合并 此需求的列合并比较简单, 直接使用el-table-column包括即可 <el-table-column align"center" sortable label"目标"><el-table-column prop"target1" sortable label"预设目标" /><el-table-c…