【Seata源码学习 】 扫描@GlobalTransaction注解 篇一
1. SeataAutoConfiguration 自动配置类的加载
基于SpringBoot的starter机制,在应用上下文启动时,会加载SeataAutoConfiguration自动配置类
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=io.seata.spring.boot.autoconfigure.SeataAutoConfiguration
此配置类将会往应用上下文中注册四个组件
从名字就知道,此组件负责扫描@GlobalTransaction
此类的继承关系如下图所示
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创建代理类
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源码学习 】 扫描@GlobalTransaction注解 篇一
1. SeataAutoConfiguration 自动配置类的加载 基于SpringBoot的starter机制,在应用上下文启动时,会加载SeataAutoConfiguration自动配置类 # Auto Configure org.springframework.boot.autoconfigure.EnableAutoConfigurationio.seata.spring.boot.aut…...

DBA-MySql面试问题及答案-上
文章目录 1.什么是数据库?2.如何查看某个操作的语法?3.MySql的存储引擎有哪些?4.常用的2种存储引擎?6.可以针对表设置引擎吗?如何设置?6.选择合适的存储引擎?7.选择合适的数据类型8.char & varchar9.Mysql字符集10.如何选择…...

网络爬虫之Ajax动态数据采集
动态数据采集 规则 有时候我们在用 requests 抓取页面的时候,得到的结果可能和在浏览器中看到的不一样,在浏览器中可以看到正常显示的页面教据,但是使用 requests 得到的结果并没有,这是因为requests 获取的都是原始的 HTML 文档…...

c语言的初始学习(练习)
##初学c语言---MOOC浙江大学翁恺先生学习c语言 那么我们先看看这个题目吧,这是初始语法的应用。 记住,我们的程序是按步骤执行的,并不是在不同的两行同时进行。 程序设计:1.了解题目的需要,几个变量需要用到&#x…...

研究论文 2022-Oncoimmunology:AI+癌RNA-seq数据 识别细胞景观
Wang, Xin, et al. "Deep learning using bulk RNA-seq data expands cell landscape identification in tumor microenvironment." Oncoimmunology 11.1 (2022): 2043662. https://www.tandfonline.com/doi/full/10.1080/2162402X.2022.2043662 被引次数࿱…...
ChatGPT4与ArcGIS Pro3助力AI 地理空间分析和可视化及助力科研论文写作
在地学领域,ArcGIS几乎成为了每位科研工作者作图、数据分析的必备工具,而ArcGIS Pro3除了良好地继承了ArcMap强大的数据管理、制图、空间分析等能力,还具有二三维融合、大数据、矢量切片制作及发布、任务工作流、时空立方体等特色功能&#x…...
okhttp系列-一些上限值
1.正在执行的任务数量最大值是64 异步请求放入readyAsyncCalls后,遍历readyAsyncCalls取出任务去执行的时候,如果发现runningAsyncCalls的数量大于等于64,就不从readyAsyncCalls取出任务执行。 public final class Dispatcher {private int …...

C++面向对象(OOP)编程-STL详解(vector)
本文主要介绍STL六大组件,并主要介绍一些容器的使用。 目录 1 泛型编程 2 CSTL 3 STL 六大组件 4 容器 4.1 顺序性容器 4.1.1 顺序性容器的使用场景 4.2 关联式容器 4.2.1 关联式容器的使用场景 4.3 容器适配器 4.3.1 容器适配器的使用场景 5 具体容器的…...

postman几种常见的请求方式
1、get请求直接拼URL形式 对于http接口,有get和post两种请求方式,当接口说明中未明确post中入参必须是json串时,均可用url方式请求 参数既可以写到URL中,也可写到参数列表中,都一样,请求时候都是拼URL 2&am…...

openai最新探索:超级对齐是否可行?
前言 今天来介绍一篇openai最新的paper:弱到强的对齐。 openai专门成立了一个团队来做大模型的超级对齐即superhuman model,之前chatgpt取得成功依赖RLHF即依赖人类反馈,但是作者期望的superhuman model将会是一个能够处理各种复杂问题的强…...

本地websocket服务端结合cpolar内网穿透实现公网访问
文章目录 1. Java 服务端demo环境2. 在pom文件引入第三包封装的netty框架maven坐标3. 创建服务端,以接口模式调用,方便外部调用4. 启动服务,出现以下信息表示启动成功,暴露端口默认99995. 创建隧道映射内网端口6. 查看状态->在线隧道,复制所创建隧道的公网地址加端口号7. 以…...

关于“Python”的核心知识点整理大全37
目录 13.6.2 响应外星人和飞船碰撞 game_stats.py settings.py alien_invasion.py game_functions.py ship.py 注意 13.6.3 有外星人到达屏幕底端 game_functions.py 13.6.4 游戏结束 game_stats.py game_functions.py 13.7 确定应运行游戏的哪些部分 alien_inva…...

Vivado中的FFT IP核使用(含代码)
本文介绍了Vidado中FFT IP核的使用,具体内容为:调用IP核>>配置界面介绍>>IP核端口介绍>>MATLAB生成测试数据>>测试verilogHDL>>TestBench仿真>>结果验证>>FFT运算。 1、调用IP核 该IP核对应手册pg109_xfft.pd…...

创新驱动,边缘计算领袖:亚马逊云科技海外服务器服务再进化
2022年亚马逊云科技re:Invent盛会于近日在拉斯维加斯成功召开,吸引了众多业界精英和创新者。亚马逊云科技边缘服务副总裁Jan Hofmeyr在演讲中分享了关于亚马逊云科技海外服务器边缘计算的最新发展和创新成果,引发与会者热烈关注。 re:Invent的核心主题是…...

什么是“人机协同”机器学习?
“人机协同”(HITL)是人工智能的一个分支,它同时利用人类智能和机器智能来创建机器学习模型。在传统的“人机协同”方法中,人们会参与一个良性循环,在其中训练、调整和测试特定算法。通常,它的工作方式如下…...

数学建模笔记-拟合算法
内容:拟合算法 一.概念: 拟合的结果就是找到一个确定的曲线 二.最小二乘法: 1. 2.最小二乘法的二表示的是平方的那个2 3.求解最小二乘法: 三.评价拟合的好坏 1.总体评分和SST: 2.误差平方和SSE: 3.回…...
非线性约束的优化问题_序列二次规划算法代码
1. 理论部分 2. 序列二次规划算法代码及解析 3.完整代码 1.理论部分 a.约束优化问题的极值条件 库恩塔克条件(Kuhn-Tucker conditions,KT条件)是确定某点为极值点的必要条件。如果所讨论的规划是凸规划,那么库恩-塔克条件也是充分条件。 ÿ…...

【数据结构之顺序表】
数据结构学习笔记---002 数据结构之顺序表1、介绍线性表1.1、什么是线性表? 2、什么是顺序表?2.1、概念及结构2.2、顺序表的分类 3、顺序表接口的实现3.1、顺序表动态存储结构的Seqlist.h3.1.1、定义顺序表的动态存储结构3.1.2、声明顺序表各个接口的函数 3.2、顺序表动态存储…...
junit-mock-dubbo
dubbo单元测试分两种情况 Autowired注解是启动上下文环境,使用上下文对象进行测试,适合调试代码 InjectMocks注解是启动上下文环境,使用mock对象替换上下文对象,适合单元测试 BaseTest *** Created by Luohh on 2023/2/10*/ S…...
json解析之fastjson和jackson使用对比
前言 最近项目中需要做埋点分析,首先就需要对埋点日志进行解析处理,刚好这时候体验对比了下fastjson和jackson两者使用的区别,以下分别是针对同一个json串处理,最终的效果都是将json数据解析出来,并统一展示。 一、fa…...
零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?
一、核心优势:专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发,是一款收费低廉但功能全面的Windows NAS工具,主打“无学习成本部署” 。与其他NAS软件相比,其优势在于: 无需硬件改造:将任意W…...

【单片机期末】单片机系统设计
主要内容:系统状态机,系统时基,系统需求分析,系统构建,系统状态流图 一、题目要求 二、绘制系统状态流图 题目:根据上述描述绘制系统状态流图,注明状态转移条件及方向。 三、利用定时器产生时…...

DBAPI如何优雅的获取单条数据
API如何优雅的获取单条数据 案例一 对于查询类API,查询的是单条数据,比如根据主键ID查询用户信息,sql如下: select id, name, age from user where id #{id}API默认返回的数据格式是多条的,如下: {&qu…...

华硕a豆14 Air香氛版,美学与科技的馨香融合
在快节奏的现代生活中,我们渴望一个能激发创想、愉悦感官的工作与生活伙伴,它不仅是冰冷的科技工具,更能触动我们内心深处的细腻情感。正是在这样的期许下,华硕a豆14 Air香氛版翩然而至,它以一种前所未有的方式&#x…...
Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析
Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析 一、第一轮提问(基础概念问题) 1. 请解释Spring框架的核心容器是什么?它在Spring中起到什么作用? Spring框架的核心容器是IoC容器&#…...
Spring Security 认证流程——补充
一、认证流程概述 Spring Security 的认证流程基于 过滤器链(Filter Chain),核心组件包括 UsernamePasswordAuthenticationFilter、AuthenticationManager、UserDetailsService 等。整个流程可分为以下步骤: 用户提交登录请求拦…...

DeepSeek源码深度解析 × 华为仓颉语言编程精粹——从MoE架构到全场景开发生态
前言 在人工智能技术飞速发展的今天,深度学习与大模型技术已成为推动行业变革的核心驱动力,而高效、灵活的开发工具与编程语言则为技术创新提供了重要支撑。本书以两大前沿技术领域为核心,系统性地呈现了两部深度技术著作的精华:…...
React从基础入门到高级实战:React 实战项目 - 项目五:微前端与模块化架构
React 实战项目:微前端与模块化架构 欢迎来到 React 开发教程专栏 的第 30 篇!在前 29 篇文章中,我们从 React 的基础概念逐步深入到高级技巧,涵盖了组件设计、状态管理、路由配置、性能优化和企业级应用等核心内容。这一次&…...
[USACO23FEB] Bakery S
题目描述 Bessie 开了一家面包店! 在她的面包店里,Bessie 有一个烤箱,可以在 t C t_C tC 的时间内生产一块饼干或在 t M t_M tM 单位时间内生产一块松糕。 ( 1 ≤ t C , t M ≤ 10 9 ) (1 \le t_C,t_M \le 10^9) (1≤tC,tM≤109)。由于空间…...

DeepSeek越强,Kimi越慌?
被DeepSeek吊打的Kimi,还有多少人在用? 去年,月之暗面创始人杨植麟别提有多风光了。90后清华学霸,国产大模型六小虎之一,手握十几亿美金的融资。旗下的AI助手Kimi烧钱如流水,单月光是投流就花费2个亿。 疯…...