Back to Javatutorial

Spring事务(二):事务的执行流程

docs/Spring全家桶/Spring源码分析/Spring事务/Spring事务(二):事务的执行流程.md

1.0.022.3 KB
Original Source

spring ֮ʶһУͨһ demo ʾʹ spring ܣȻ @EnableTransactionManagement עĹܣĽ spring ش롣

1. 󴴽

spring ǻ aop ģʹôһϵвĽͨԵķʽĴ̡

spring ֮ʶͨ @EnableTransactionManagement ע⣬ָע spring ע InfrastructureAdvisorAutoProxyCreator AbstractAdvisorAutoProxyCreator ࣬ɴģڽ InfrastructureAdvisorAutoProxyCreator Ĵ̡

AbstractAdvisorAutoProxyCreator ķԼɣ spring aop ֮ AnnotationAwareAspectJAutoProxyCreator ϣ spring aop ֮ AnnotationAwareAspectJAutoProxyCreator £ѾϸҪ aop вĵطҪϸ˽ spring aop βС飬Ķƪ¡

ǽ AbstractAutoProxyCreator#postProcessBeforeInitialization

public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
    ...
    if (...) {
        //1\. shouldSkip:
        // - AspectJAwareAdvisorAutoProxyCreator  shouldSkip ᴦ @Aspect ע࣬
        //   е@Before/@After/@AroundעװΪAdvisorٵø(Ҳ
        //   AbstractAutoProxyCreator)shouldSkip
        // - InfrastructureAdvisorAutoProxyCreatorֱִAbstractAutoProxyCreatorshouldSkip
        if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
            this.advisedBeans.put(cacheKey, Boolean.FALSE);
            return null;
        }
    }
    if(...)  {
        ...

        // 2\. getAdvicesAndAdvisorsForBeanȡڵǰadvisor
        Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(
            beanClass, beanName, targetSource);
        Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
        ...
        return proxy;
    }
    return null;
}

ͬ㣬ѾעеIJ죬 shouldSkipûɶ˵ģصչ getAdvicesAndAdvisorsForBean(...)

1.1 BeanFactoryAdvisorRetrievalHelper#findAdvisorBeans

һ· getAdvicesAndAdvisorsForBean(...) еIJ AspectJAwareAdvisorAutoProxyCreator IJ̫𣬲иΪҪǿ££

BeanFactoryAdvisorRetrievalHelper#findAdvisorBeans

public List<Advisor> findAdvisorBeans() {
    String[] advisorNames = this.cachedAdvisorBeanNames;
    if (advisorNames == null) {
        // ҵǰbeanFactory Advisor  bean class
        // AdvisorûʵAdvisorؽӿڣҲxmlָ
        advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                this.beanFactory, Advisor.class, true, false);
        this.cachedAdvisorBeanNames = advisorNames;
    }
    ...
    List<Advisor> advisors = new ArrayList<>();
    for (String name : advisorNames) {
        ...
        // advisorbean namespringлȡ bean
        advisors.add(this.beanFactory.getBean(name, Advisor.class));
        ...
    }
    ...
    return advisors;
}

Ҫǻȡ spring е advisorʵ AnnotationAwareAspectJAutoProxyCreator ҲôȡģֻڻȡǰAnnotationAwareAspectJAutoProxyCreator shouldSkip(...) а @Aspect а @Befor/@After/@Around עķװɶӦ Advisor InfrastructureAdvisorAutoProxyCreator 򲻻ᣬһʼҲᵽˡ

spring ֮ʶһУ @EnableTransactionManagement ע⹦ʱǷעͨ @Bean ע spring BeanFactoryTransactionAttributeSourceAdvisor bean ͻ BeanFactoryAdvisorRetrievalHelper#findAdvisorBeans ȡ

1.2 AopUtils#canApply(...)

ŷһ·ߣžж advisor ܷĿ class ĵطˣ

/**
 * жadvisorܷĿclass
 */
public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
    ...
    // жǷΪ PointcutAdvisoradvisorΪBeanFactoryTransactionAttributeSourceAdvisor
    // ʵPointcutAdvisorĴִ
    else if (advisor instanceof PointcutAdvisor) {
        PointcutAdvisor pca = (PointcutAdvisor) advisor;
        //ʹ PointcutAdvisor ж
        return canApply(pca.getPointcut(), targetClass, hasIntroductions);
    }
    ...
}

/**
 * жadvisorܷĿclass
 */
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
    Assert.notNull(pc, "Pointcut must not be null");
    //1\. еǷų
    if (!pc.getClassFilter().matches(targetClass)) {
        return false;
    }
    // ȡƥMethodMatcher.TRUE ΪĬϵ MethodMatcher 
    MethodMatcher methodMatcher = pc.getMethodMatcher();
    if (methodMatcher == MethodMatcher.TRUE) {
        return true;
    }
    ...
    // classestargetClassObjectиࡢнӿ
    Set<Class<?>> classes = new LinkedHashSet<>();
    // ʡԻȡtargetClassĸಽ
    ...
    for (Class<?> clazz : classes) {
        // ȡ clazz ķǰķObjectи෽ӿڵĬϷ
        Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
        for (Method method : methods) {
            // 2\. ƥĹؼ
            if (introductionAwareMethodMatcher != null ?
                    introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
                    methodMatcher.matches(method, targetClass)) {
                return true;
            }
        }
    }
    return false;
}

һĴ AnnotationAwareAspectJAutoProxyCreator һģһǶǵͬķжϣڴĵ advisor ͬյõľƥҲͬ

Ӵķƥ߼ Pointcut У Pointcut Advisorɼ Advisor ʮֹؼ Advisor Ϊ BeanFactoryTransactionAttributeSourceAdvisorǾࡣ

1.3 BeanFactoryTransactionAttributeSourceAdvisor ƥ

һС ڵķУ֪ж targetClass ܷӦõǰ advisor ĹԴ advisor pointcut``pointcut طжϹ

  • ƥࣺpc.getClassFilter().matches(targetClass)
  • ƥ䷽pc.getMethodMatcher().matches(method, targetClass)

һС Ǵ BeanFactoryTransactionAttributeSourceAdvisor ֣һƥ

public class BeanFactoryTransactionAttributeSourceAdvisor 
        extends AbstractBeanFactoryPointcutAdvisor {

    @Nullable
    private TransactionAttributeSource transactionAttributeSource;

    /**
     *  pointcut
     */
    private final TransactionAttributeSourcePointcut pointcut = 
            new TransactionAttributeSourcePointcut() {
        @Override
        @Nullable
        protected TransactionAttributeSource getTransactionAttributeSource() {
            return transactionAttributeSource;
        }
    };

    /**
     *  transactionAttributeSource
     */
    public void setTransactionAttributeSource(TransactionAttributeSource 
            transactionAttributeSource) {
        this.transactionAttributeSource = transactionAttributeSource;
    }

    /**
     *  ClassFilter
     */
    public void setClassFilter(ClassFilter classFilter) {
        this.pointcut.setClassFilter(classFilter);
    }

    /**
     * ȡ pointcut
     */
    @Override
    public Pointcut getPointcut() {
        return this.pointcut;
    }
}

ĴؼѾעˣܽ£BeanFactoryTransactionAttributeSourceAdvisor#getPointcut õ pointcut Ϊ TransactionAttributeSourcePointcut private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {...} дġ

BeanFactoryTransactionAttributeSourceAdvisor transactionAttributeSource ʲôأ ProxyTransactionManagementConfiguration д transactionAdvisor Ĵ룺

public class ProxyTransactionManagementConfiguration 
        extends AbstractTransactionManagementConfiguration {

    // ʡ
    ...

    /**
     * ȡSpring @Transactional ע⣬ӦԹSpringṹ
     */
    @Bean
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public TransactionAttributeSource transactionAttributeSource() {
        return new AnnotationTransactionAttributeSource();
    }

    /**
     * ǿ.
     * transactionAttributeSourcetransactionAttributeSource() صĶ
     */
    @Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
            TransactionAttributeSource transactionAttributeSource,
            TransactionInterceptor transactionInterceptor) {
        BeanFactoryTransactionAttributeSourceAdvisor advisor = 
                new BeanFactoryTransactionAttributeSourceAdvisor();
        // ࣬ @Transactional 
        advisor.setTransactionAttributeSource(transactionAttributeSource);
        ...
        return advisor;
    }

}

ɴ˿֪BeanFactoryTransactionAttributeSourceAdvisor transactionAttributeSource Ϊ AnnotationTransactionAttributeSource.

ٻص BeanFactoryTransactionAttributeSourceAdvisorķ֪getPointcut() õ TransactionAttributeSourcePointcut Ȼࣺ

abstract class TransactionAttributeSourcePointcut 
        extends StaticMethodMatcherPointcut implements Serializable {

    protected TransactionAttributeSourcePointcut() {
        // ڹ췽 ClassFilter
        setClassFilter(new TransactionAttributeSourceClassFilter());
    }

    /**
     * pointcut  matches 
     */
    @Override
    public boolean matches(Method method, Class<?> targetClass) {
        // õĽΪAnnotationTransactionAttributeSource
        TransactionAttributeSource tas = getTransactionAttributeSource();
        return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
    }

    /**
     *  BeanFactoryTransactionAttributeSourceAdvisor ָ
     */
    @Nullable
    protected abstract TransactionAttributeSource getTransactionAttributeSource();

    /**
     * ڲ࣬ʵ ClassFilter
     */
    private class TransactionAttributeSourceClassFilter implements ClassFilter {

        /**
         * ClassFilter  matches
         */
        @Override
        public boolean matches(Class<?> clazz) {
            // ǷΪTransactionalProxyPlatformTransactionManagerPersistenceExceptionTranslatorʵ
            if (TransactionalProxy.class.isAssignableFrom(clazz) ||
                    PlatformTransactionManager.class.isAssignableFrom(clazz) ||
                    PersistenceExceptionTranslator.class.isAssignableFrom(clazz)) {
                return false;
            }
            //ж TransactionAttributeSource ȡǷΪ
            // õĽΪAnnotationTransactionAttributeSource
            TransactionAttributeSource tas = getTransactionAttributeSource();
            return (tas == null || tas.isCandidateClass(clazz));
        }
    }

}

ķǵõһҪĹ

  • ƥࣺpc.getClassFilter().matches(targetClass)``ClassFilter Ϊ TransactionAttributeSourceClassFilter

ƥĹҵˣƥ䷽Ĺأǽ TransactionAttributeSourcePointcut#getMethodMatcher() StaticMethodMatcherPointcut

public abstract class StaticMethodMatcherPointcut 
        extends StaticMethodMatcher implements Pointcut {
    // ʡһЩ
    ...

    @Override
    public final MethodMatcher getMethodMatcher() {
        return this;
    }
}

صľȻ thisǸɶҪţϸ TransactionAttributeSourcePointcut̳ StaticMethodMatcherPointcut

abstract class TransactionAttributeSourcePointcut 
        extends StaticMethodMatcherPointcut implements Serializable {
    // ʡһЩ
    ...
}

ԣpc.getMethodMatcher() õľ TransactionAttributeSourcePointcut mathes(...) TransactionAttributeSourcePointcut#matches.

ڱСڵܽ·Ľ

  • ƥࣺpc.getClassFilter().matches(targetClass)``ClassFilter Ϊ TransactionAttributeSourceClassFilter
  • ƥ䷽pc.getMethodMatcher().matches(method, targetClass)``methodMatcher Ϊ TransactionAttributeSourcePointcut
  • У TransactionAttributeSourcePointcut#getTransactionAttributeSourceصĽΪ AnnotationTransactionAttributeSource.

1.4 ƥ

1.2 ֣֪ǰ advisor ܷӦĿ classҪͬʱƥ

  • ƥࣺpc.getClassFilter().matches(targetClass)``ClassFilter Ϊ TransactionAttributeSourceClassFilter
  • ƥ䷽pc.getMethodMatcher().matches(method, targetClass)``methodMatcher Ϊ TransactionAttributeSourcePointcut

  • TransactionAttributeSourceClassFilter#matchesжϵǰǷΪǷΪ TransactionalProxy``PlatformTransactionManager``PersistenceExceptionTranslator ʵ࣬Ȼ AnnotationTransactionAttributeSource#isCandidateClass жϣ
  • TransactionAttributeSourcePointcut#matches AnnotationTransactionAttributeSource#getTransactionAttributeڼ̳йϵʵʵõ AbstractFallbackTransactionAttributeSource#getTransactionAttributeжϡ

Ǿ¾ƥ̡

AnnotationTransactionAttributeSource#isCandidateClass

ֱ⣬ isCandidateClass

AnnotationTransactionAttributeSource#isCandidateClass

@Override
public boolean isCandidateClass(Class<?> targetClass) {
    // ҵеannotationParsersѭƥ
    for (TransactionAnnotationParser parser : this.annotationParsers) {
        if (parser.isCandidateClass(targetClass)) {
            return true;
        }
    }
    return false;
}

Կѭ TransactionAnnotationParser isCandidateClass this.annotationParsers ɶأͨԣ£

this.annotationParsers ֻ SpringTransactionAnnotationParserǽ isCandidateClass

public class SpringTransactionAnnotationParser 
        implements TransactionAnnotationParser, Serializable {

    /**
     * жǷ @Transactional ע
     */
    @Override
    public boolean isCandidateClass(Class<?> targetClass) {
        return AnnotationUtils.isCandidateClass(targetClass, Transactional.class);
    }
}

յõ AnnotationUtils.isCandidateClassжָǷ @Transactional ע⡣

ǾˣTransactionAttributeSourceClassFilter#matches ųһЩ (TransactionalProxy/PlatformTransactionManager/PersistenceExceptionTranslator ) ջƥ @Transactional עࡣ

AnnotationTransactionAttributeSource#getTransactionAttribute

ķƥɹ󣬲ܱʾɹƥ䣬ƥ TransactionAttributeSourcePointcut#matchesͬʱŻƥɹTransactionAttributeSourcePointcut#matches AnnotationTransactionAttributeSource#getTransactionAttribute ƥģǸȥ

public abstract class AbstractFallbackTransactionAttributeSource 
        implements TransactionAttributeSource {

    /**
     * ȡ @Transactional ע
     */
    public TransactionAttribute getTransactionAttribute(Method method, 
            @Nullable Class<?> targetClass) {
        if (method.getDeclaringClass() == Object.class) {
            return null;
        }

        // ʡԴӻлȡ
        ...
        else {
            // ȡ Transaction ԣ @Transactional ע
            TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
            // ʡԷ뻺
            ...
            return txAttr;
        }
    }
}

AnnotationTransactionAttributeSource getTransactionAttribute Ǽ̳ AbstractFallbackTransactionAttributeSource ģǽķ AbstractFallbackTransactionAttributeSource#getTransactionAttributeȡϵ @Transactional עԣǸ computeTransactionAttribute(...)

AbstractFallbackTransactionAttributeSource

protected TransactionAttribute computeTransactionAttribute(Method method, 
        @Nullable Class<?> targetClass) {
    // ĬϱҪ public ֧
    if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
        return null;
    }
    // 1\. ȡȷеķ紫classIFooʵʵĵclassDefaultFoo
    //    ôӦý IFoo#method תΪ DefaultFoo#method
    Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);
    // 2\. ӷϻȡ @Transactional 
    TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
    if (txAttr != null) {
        return txAttr;
    }
    // 3\. ϻȡ @Transaction 
    txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());
    if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
        return txAttr;
    }
    if (specificMethod != method) {
        // 4\. ȷеķҲҴķϵ
        txAttr = findTransactionAttribute(method);
        if (txAttr != null) {
            return txAttr;
        }
        // 5\. ϶ûҵȷеϵ
        txAttr = findTransactionAttribute(method.getDeclaringClass());
        if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
            return txAttr;
        }
    }
    // 6\. ûлȡշnull
    return null;
}

Ϸ̣ܽȡ @Transactional £

  1. ķתΪȷеķ紫 class IFooʵʵĵ class DefaultFooͻὫ IFoo#method תΪ DefaultFoo#method
  2. ȷеķϻȡ @Transactional
  3. ûлȡʹȷеĴϻȡ @Transaction
  4. ûлȡʹķϻȡ @Transaction
  5. ûлȡʹϻȡ @Transaction
  6. ϶ûлȡͷ null

spring δӷϻȡ @Transactional أȥ

AnnotationTransactionAttributeSource

    // ӷϻȡ @Transactional 
    protected TransactionAttribute findTransactionAttribute(Method method) {
        return determineTransactionAttribute(method);
    }

    // ϻȡ @Transactional 
    protected TransactionAttribute findTransactionAttribute(Class<?> clazz) {
        return determineTransactionAttribute(clazz);
    }

    // յõķ
    protected TransactionAttribute determineTransactionAttribute(AnnotatedElement element) {
        for (TransactionAnnotationParser parser : this.annotationParsers) {
            //  @Transactional ע
            TransactionAttribute attr = parser.parseTransactionAnnotation(element);
            if (attr != null) {
                return attr;
            }
        }
        return null;
    }

Ƕǵ AnnotationTransactionAttributeSource#determineTransactionAttribute ȡģ AnnotationTransactionAttributeSource#determineTransactionAttribute TransactionAnnotationParser#parseTransactionAnnotation this.annotationParsers ǰѾˣֻһࣺSpringTransactionAnnotationParserǸȥ

SpringTransactionAnnotationParser

    /**
     * ȡ Transactional ע⣬򷵻 null
     */
    public TransactionAttribute parseTransactionAnnotation(AnnotatedElement element) {
        // ȡ Transactional ע⣬򷵻 null
        AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(
                element, Transactional.class, false, false);
        if (attributes != null) {
            return parseTransactionAnnotation(attributes);
        }
        else {
            return null;
        }
    }

    /**
     *  Transactional עľ
     */
    protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {
        RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
        // Ĵʽ
        Propagation propagation = attributes.getEnum("propagation");
        rbta.setPropagationBehavior(propagation.value());
        // ĸ뼶
        Isolation isolation = attributes.getEnum("isolation");
        rbta.setIsolationLevel(isolation.value());
        // ijʱʱ
        rbta.setTimeout(attributes.getNumber("timeout").intValue());
        // ǷΪֻ
        rbta.setReadOnly(attributes.getBoolean("readOnly"));
        rbta.setQualifier(attributes.getString("value"));
        // ع쳣
        List<RollbackRuleAttribute> rollbackRules = new ArrayList<>();
        for (Class<?> rbRule : attributes.getClassArray("rollbackFor")) {
            rollbackRules.add(new RollbackRuleAttribute(rbRule));
        }
        for (String rbRule : attributes.getStringArray("rollbackForClassName")) {
            rollbackRules.add(new RollbackRuleAttribute(rbRule));
        }
        // ع쳣
        for (Class<?> rbRule : attributes.getClassArray("noRollbackFor")) {
            rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
        }
        for (String rbRule : attributes.getStringArray("noRollbackForClassName")) {
            rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
        }
        rbta.setRollbackRules(rollbackRules);

        return rbta;
    }

ԿTransactional עĸԽ RuleBasedTransactionAttribute.

ˣǾˣTransactionAttributeSourcePointcut#matches ж򷽷û Transactional ע⡣

1.5 Ĵ

Ĵ AbstractAutoProxyCreator#postProcessAfterInitialization ɵģͬ aop һģһͲٷˣ˽Сɲ鿴 spring aop ֮ AnnotationAwareAspectJAutoProxyCreator £

2. ִ

ִз棬 aop ִ̲һͨ Advisor ҵӦ Adviceͨ Advice ҵӦ methodInterceptorִе MethodInterceptor#invoke MethodInterceptor Ϊ TransactionInterceptor ProxyTransactionManagementConfiguration ͨ @Bean עġ

aop ̣Dzط spring aop ֮ jdk ̬ spring aop ֮ cglib ϸȤСвģֱ TransactionInterceptor#invoke ִ̡

Ĵ TransactionInterceptor#invoke У

TransactionInterceptor#invoke

public Object invoke(MethodInvocation invocation) throws Throwable {
    Class<?> targetClass = (invocation.getThis() != null 
        ? AopUtils.getTargetClass(invocation.getThis()) : null);
    // ¿
    return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
}

Ĵ߼ TransactionAspectSupport#invokeWithinTransaction У

TransactionAspectSupport#invokeWithinTransaction

protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
        final InvocationCallback invocation) throws Throwable {
    TransactionAttributeSource tas = getTransactionAttributeSource();
    // ȡ@Transactional
    final TransactionAttribute txAttr = (tas != null 
        ? tas.getTransactionAttribute(method, targetClass) : null);
    // ȡIOCлȡ
    final TransactionManager tm = determineTransactionManager(txAttr);

    // ʡ ReactiveTransactionManager Ĵ
    ...

    PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
    // ȡȫ޶ʽΪ".."
    final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);

    // Ĵ߼ҲǽҪĵط
    if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
        // 1\. 
        TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);
        Object retVal;
        try {
            // 2\. ִоҵ
            retVal = invocation.proceedWithInvocation();
        }
        catch (Throwable ex) {
            // 3\. 쳣ع
            completeTransactionAfterThrowing(txInfo, ex);
            throw ex;
        }
        finally {
            // Ϣ
            cleanupTransactionInfo(txInfo);
        }
        if (vavrPresent && VavrDelegate.isVavrTry(retVal)) {
            TransactionStatus status = txInfo.getTransactionStatus();
            if (status != null && txAttr != null) {
                retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
            }
        }
        // 4\. ύ񣬴лжǷ֧
        commitTransactionAfterReturning(txInfo);
        return retVal;
    }
    else {
        // ʡ
        ...
    }
}

Ϸȫˣ£

  1. ִҵ
  2. 쳣ع

ľǽһƪ·ֻҪĴд˽⼴ɡ

3. ܽ

ҪдĴִ̣ʵЩͬ aop һ£ط aop ͬIJ֣

  • ڴĴ棬жϵǰܷʹ BeanFactoryTransactionAttributeSourceAdvisorص TransactionAttributeSourceClassFilter#matches TransactionAttributeSourcePointcut#matches жϵĺڣ

  • ڷִϵģԷ TransactionInterceptor#invoke ִ̣ЩĿύ쳣ع̸ƽʹõIJ𲻴󣬲ľϸDzûз

صĴִִ̣еľϸƪٷ


ԭӣhttps://my.oschina.net/funcy/blog/4773457 ߸ˮƽд֮ӭָԭףҵתϵ߻Ȩҵתע