spring事务--事物准备阶段(初版)

2 篇文章 0 订阅
2 篇文章 0 订阅

spring事务TxNamespaceHandler原码解析,附带程序加载此类的原码流程(事物准备阶段)

Transactional类

//@Transactional 只能被应用到public方法上, 对于其它非public的方法,如果标记了@Transactional也不会报错,但方法没有事务功能.
//2、用 spring 事务管理器,由spring来负责数据库的打开,提交,回滚.默认遇到运行期异常(throw new RuntimeException("注释");)会回滚,即遇到不受检查(unchecked)的异常时回滚;而遇到需要捕获的异常(throw new Exception("注释");)不会回滚,即遇到受检查的异常(就是非运行时抛出的异常,编译器会检查到的异常叫受检查例外或说受检查异常)时,需我们指定方式来让事务回滚要想所有异常都回滚,要加上 @Transactional( rollbackFor={Exception.class,其它异常}) .如果让unchecked例外不回滚: @Transactional(notRollbackFor=RunTimeException.class)
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {
    String value() default "";

    //事物传播行为 默认为 Propagation.REQUIRED 如果有事务, 那么加入事务, 没有的话新建一个
    //其他传播行为 Propagation.NOT_SUPPORTED 容器不为这个方法开启事务
    //Propagation.REQUIRES_NEW 不管是否存在事务,都创建一个新的事务,原来的挂起,新的执行完毕,继续执行老的事务
    //Propagation.MANDATORY 必须在一个已有的事务中执行,否则抛出异常
    //Propagation.NEVER 必须在一个没有的事务中执行,否则抛出异常(与Propagation.MANDATORY相反)
    //Propagation.SUPPORTS 如果其他bean调用这个方法,在其他bean中声明事务,那就用事务.如果其他bean没有声明事务,那就不用事务.
    Propagation propagation() default Propagation.REQUIRED;

    //事务隔离级别 默认 : 数据库的默认隔离级别 MYSQL: 默认为REPEATABLE_READ级别 SQLSERVER: 默认为READ_COMMITTED
    //oracle数据库支持READ COMMITTED 和 SERIALIZABLE这两种事务隔离级别。默认系统事务隔离级别是READ_COMMITTED,也就是读已提交
    //Isolation.READ_UNCOMMITTED 读取未提交数据(会出现脏读, 不可重复读) 基本不使用
    //Isolation.READ_COMMITTED 读取已提交数据(会出现不可重复读和幻读)
  //Isolation.REPEATABLE_READ 可重复读(会出现幻读)
   //Isolation.SERIALIZABLE 串行化
   //脏读 : 一个事务读取到另一事务未提交的更新数据
   //不可重复读 : 在同一事务中, 多次读取同一数据返回的结果有所不同, 换句话说, 后续读取可以读到另一事务已提交的更新数据. 相反, "可重复读"在同一事务中多次读取数据时, 能够保证所读数据一样, 也就是后续读取不能读到另一事务已提交的更新数据
  //幻读 : 一个事务读到另一个事务已提交的insert数据
    Isolation isolation() default Isolation.DEFAULT;

    //事务超时时间 , 默认为-1 ,永不超时
    int timeout() default -1;

    //设置当前事务是否为只读事务,设置为true表示只读,false则表示可读写 默认false
    boolean readOnly() default false;

    //设置需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,则进行事务回滚。例如:
    //指定单一异常类@Transactional(rollbackFor=RuntimeException.class)
   //指定多个异常类@Transactional(rollbackFor={RuntimeException.class,Exception.class})
    Class<? extends Throwable>[] rollbackFor() default {};

//设置需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,则进行事务回滚。例如:
//指定单一异常类名称:@Transactional(rollbackForClassName="RuntimeException")
//指定多个异常类名称:@Transactional(rollbackForClassName={"RuntimeException","Exception"})
    String[] rollbackForClassName() default {};

//设置不需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,不进行事务回滚。例如:
//指定单一异常类:@Transactional(noRollbackFor=RuntimeException.class)
//指定多个异常类:@Transactional(noRollbackFor={RuntimeException.class, Exception.class})
    Class<? extends Throwable>[] noRollbackFor() default {};

//设置不需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,不进行事务回滚.例如:
//指定单一异常类名称:@Transactional(noRollbackForClassName="RuntimeException")
//指定多个异常类名称:@Transactional(noRollbackForClassName={"RuntimeException","Exception"})
    String[] noRollbackForClassName() default {};
}

一 .

1.AbstractApplicationContext类obtainFreshBeanFactory()

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
    this.refreshBeanFactory(); // --> 2
    ConfigurableListableBeanFactory beanFactory = this.getBeanFactory();
    if (this.logger.isDebugEnabled()) {
        this.logger.debug("Bean factory for " + this.getDisplayName() + ": " + beanFactory);
    }

    return beanFactory;
}

2.AbstractRefreshableApplicationContext类refreshBeanFactory()

protected final void refreshBeanFactory() throws BeansException {
        if (this.hasBeanFactory()) {
            this.destroyBeans();
            this.closeBeanFactory();
        }

        try {
            DefaultListableBeanFactory beanFactory = this.createBeanFactory();
            beanFactory.setSerializationId(this.getId());
            this.customizeBeanFactory(beanFactory);
            this.loadBeanDefinitions(beanFactory); // --> 3
            Object var2 = this.beanFactoryMonitor;
            synchronized(this.beanFactoryMonitor) {
                this.beanFactory = beanFactory;
            }
        } catch (IOException var5) {
            throw new ApplicationContextException("I/O error parsing bean definition source for " + this.getDisplayName(), var5);
        }
    }

3.AbstractXmlApplicationContext类loadBeanDefinitions()

protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
        beanDefinitionReader.setEnvironment(this.getEnvironment());
        beanDefinitionReader.setResourceLoader(this);
        beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
        this.initBeanDefinitionReader(beanDefinitionReader);
        this.loadBeanDefinitions(beanDefinitionReader); // --> 4
    }

4.AbstractXmlApplicationContext类loadBeanDefinitions()

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
    Resource[] configResources = this.getConfigResources();
    if (configResources != null) {
        reader.loadBeanDefinitions(configResources); // --> 5
    }

    String[] configLocations = this.getConfigLocations();
    if (configLocations != null) {
        reader.loadBeanDefinitions(configLocations);
    }

}

5.AbstractBeanDefinitionReader类loadBeanDefinitions()

//(1)
public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
    Assert.notNull(locations, "Location array must not be null");
    int counter = 0;
    String[] var3 = locations;
    int var4 = locations.length;

    for(int var5 = 0; var5 < var4; ++var5) {
        String location = var3[var5];
        counter += this.loadBeanDefinitions(location);// --> 
    }

    return counter;
}
//(2)
public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {
    return this.loadBeanDefinitions(location, (Set)null); // -->
}
//(3)
public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {
    ResourceLoader resourceLoader = this.getResourceLoader();
    if (resourceLoader == null) {
        throw new BeanDefinitionStoreException("Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
    } else {
        int loadCount;
        if (!(resourceLoader instanceof ResourcePatternResolver)) {
            Resource resource = resourceLoader.getResource(location);
            loadCount = this.loadBeanDefinitions((Resource)resource);
            if (actualResources != null) {
                actualResources.add(resource);
            }

            if (this.logger.isDebugEnabled()) {
                this.logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
            }

            return loadCount;
        } else {
            try {
                Resource[] resources = ((ResourcePatternResolver)resourceLoader).getResources(location);
                loadCount = this.loadBeanDefinitions(resources);
                if (actualResources != null) {
                    Resource[] var6 = resources;
                    int var7 = resources.length;

                    for(int var8 = 0; var8 < var7; ++var8) {
                        Resource resource = var6[var8];
                        actualResources.add(resource);
                    }
                }

                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");
                }

                return loadCount;
            } catch (IOException var10) {
                throw new BeanDefinitionStoreException("Could not resolve bean definition resource pattern [" + location + "]", var10);
            }
        }
    }
}
//(4)
public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
    Assert.notNull(locations, "Location array must not be null");
    int counter = 0;
    String[] var3 = locations;
    int var4 = locations.length;

    for(int var5 = 0; var5 < var4; ++var5) {
        String location = var3[var5];
        counter += this.loadBeanDefinitions(location);
    }

    return counter;
}

6.XmlBeanDefinitionReader类loadBeanDefinitions()

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
    Assert.notNull(encodedResource, "EncodedResource must not be null");
    if (this.logger.isInfoEnabled()) {
        this.logger.info("Loading XML bean definitions from " + encodedResource.getResource());
    }

    Set<EncodedResource> currentResources = (Set)this.resourcesCurrentlyBeingLoaded.get();
    if (currentResources == null) {
        currentResources = new HashSet(4);
        this.resourcesCurrentlyBeingLoaded.set(currentResources);
    }

    if (!((Set)currentResources).add(encodedResource)) {
        throw new BeanDefinitionStoreException("Detected cyclic loading of " + encodedResource + " - check your import definitions!");
    } else {
        int var5;
        try {
            InputStream inputStream = encodedResource.getResource().getInputStream();

            try {
                InputSource inputSource = new InputSource(inputStream);
                if (encodedResource.getEncoding() != null) {
                    inputSource.setEncoding(encodedResource.getEncoding());
                }

                var5 = this.doLoadBeanDefinitions(inputSource, encodedResource.getResource()); // -->
            } finally {
                inputStream.close();
            }
        } catch (IOException var15) {
            throw new BeanDefinitionStoreException("IOException parsing XML document from " + encodedResource.getResource(), var15);
        } finally {
            ((Set)currentResources).remove(encodedResource);
            if (((Set)currentResources).isEmpty()) {
                this.resourcesCurrentlyBeingLoaded.remove();
            }

        }

        return var5;
    }
}

7.XmlBeanDefinitionReader类doLoadBeanDefinitions()

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException {
    try {
        Document doc = this.doLoadDocument(inputSource, resource); // -->
        return this.registerBeanDefinitions(doc, resource);
    } catch (BeanDefinitionStoreException var4) {
        throw var4;
    } catch (SAXParseException var5) {
        throw new XmlBeanDefinitionStoreException(resource.getDescription(), "Line " + var5.getLineNumber() + " in XML document from " + resource + " is invalid", var5);
    } catch (SAXException var6) {
        throw new XmlBeanDefinitionStoreException(resource.getDescription(), "XML document from " + resource + " is invalid", var6);
    } catch (ParserConfigurationException var7) {
        throw new BeanDefinitionStoreException(resource.getDescription(), "Parser configuration exception parsing XML from " + resource, var7);
    } catch (IOException var8) {
        throw new BeanDefinitionStoreException(resource.getDescription(), "IOException parsing XML document from " + resource, var8);
    } catch (Throwable var9) {
        throw new BeanDefinitionStoreException(resource.getDescription(), "Unexpected exception parsing XML document from " + resource, var9);
    }
}

8.XmlBeanDefinitionReader类registerBeanDefinitions()

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
    BeanDefinitionDocumentReader documentReader = this.createBeanDefinitionDocumentReader();
    documentReader.setEnvironment(this.getEnvironment());
    int countBefore = this.getRegistry().getBeanDefinitionCount();
    documentReader.registerBeanDefinitions(doc, this.createReaderContext(resource));//-->
    return this.getRegistry().getBeanDefinitionCount() - countBefore;
}

9.DefaultBeanDefinitionDocumentReader类registerBeanDefinitions();

public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
    this.readerContext = readerContext;
    this.logger.debug("Loading bean definitions");
    Element root = doc.getDocumentElement();
    this.doRegisterBeanDefinitions(root); // -->
}

10.DefaultBeanDefinitionDocumentReader类doRegisterBeanDefinitions()

protected void doRegisterBeanDefinitions(Element root) {
    BeanDefinitionParserDelegate parent = this.delegate;
    this.delegate = this.createDelegate(this.getReaderContext(), root, parent);
    if (this.delegate.isDefaultNamespace(root)) {
        String profileSpec = root.getAttribute("profile");
        if (StringUtils.hasText(profileSpec)) {
            String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, ",; ");
            if (!this.getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
                return;
            }
        }
    }

    this.preProcessXml(root);
    this.parseBeanDefinitions(root, this.delegate); // -->
    this.postProcessXml(root);
    this.delegate = parent;
}

11.DefaultBeanDefinitionDocumentReader类parseBeanDefinitions()

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
    if (delegate.isDefaultNamespace(root)) {
        NodeList nl = root.getChildNodes();

        for(int i = 0; i < nl.getLength(); ++i) {
            Node node = nl.item(i);
            if (node instanceof Element) {
                Element ele = (Element)node;
                if (delegate.isDefaultNamespace(ele)) {
                    this.parseDefaultElement(ele, delegate);
                } else {
                    delegate.parseCustomElement(ele); // -->
                }
            }
        }
    } else {
        delegate.parseCustomElement(root);
    }

}

12.BeanDefinitionParserDelegate类parseCustomElement()

public BeanDefinition parseCustomElement(Element ele) {
    return this.parseCustomElement(ele, (BeanDefinition)null);
}

public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
    String namespaceUri = this.getNamespaceURI(ele);
    NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri); // --> 此处使用NamespaceHandler的resolve方法,来执行各个实现NamespaceHandler的init方法 -->见13,resolve方法
    if (handler == null) {
        this.error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
        return null;
    } else {
        return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd)); // --> 如果handler不为空,则执行NamespaceHandler的hanler方法 --> 见14
    }
}

13.DefaultNamespaceHandlerResolver类resolve()

public NamespaceHandler resolve(String namespaceUri) {
    //处理类的映射集合
    Map<String, Object> handlerMappings = this.getHandlerMappings();
    //获取传入的名称空间地址namespaceUri的
    Object handlerOrClassName = handlerMappings.get(namespaceUri);
    //如果为null 则返回null
    if (handlerOrClassName == null) {
        return null;
    //如果是NamespaceHandler的实现类,则返回这个类
    } else if (handlerOrClassName instanceof NamespaceHandler) {
        return (NamespaceHandler)handlerOrClassName;
    } else {
        String className = (String)handlerOrClassName;

        try {
            //根据名称转化为实体类
            Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);
            if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {
                throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri + "] does not implement the [" + NamespaceHandler.class.getName() + "] interface");
            } else {
                //实例化类
                NamespaceHandler namespaceHandler = (NamespaceHandler)BeanUtils.instantiateClass(handlerClass);
                //实现init方法
                namespaceHandler.init();
                handlerMappings.put(namespaceUri, namespaceHandler);
                return namespaceHandler;
            }
        } catch (ClassNotFoundException var7) {
            throw new FatalBeanException("NamespaceHandler class [" + className + "] for namespace [" + namespaceUri + "] not found", var7);
        } catch (LinkageError var8) {
            throw new FatalBeanException("Invalid NamespaceHandler class [" + className + "] for namespace [" + namespaceUri + "]: problem with handler class file or dependent class", var8);
        }
    }
}

14.NamespaceHandlerSupport类的parse方法

//(1)
public BeanDefinition parse(Element element, ParserContext parserContext) {
    return this.findParserForElement(element, parserContext)//-->此方法内容如下,返回的是BeanDefinitionParser接口,故下面的parse方法即是BeanDefinitionParser的实现类的parse方法
        .parse(element, parserContext);
}
//(2)
private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {
    String localName = parserContext.getDelegate().getLocalName(element);
    BeanDefinitionParser parser = (BeanDefinitionParser)this.parsers.get(localName);
    if (parser == null) {
        parserContext.getReaderContext().fatal("Cannot locate BeanDefinitionParser for element [" + localName + "]", element);
    }

    return parser;
}

由上面对代码的跟踪可知道,spring解析xml是通过DefaultNamespaceHandlerResolver为入口,执行 resolve()方法,从而调用TxNamespaceHandler,ContextNamespaceHandler,AopNamespaceHandler,jdbcNamespaceHandler等类的init()方法,

同时又对BeanDefinitionParser接口的实现类的parse方法进行调用

下面进行TxNamespaceHandler,即事务调用过程的原码解析

1).TxNamespaceHandler类中init()方法

public void init() {
        this.registerBeanDefinitionParser("advice", new TxAdviceBeanDefinitionParser());//--标签方式
        this.registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());//-->注解方式  此处我们只看注解方式
        this.registerBeanDefinitionParser("jta-transaction-manager", new JtaTransactionManagerBeanDefinitionParser());//-->分布式事务
    }

2).AnnotationDrivenBeanDefinitionParser类的parse方法

public BeanDefinition parse(Element element, ParserContext parserContext) {
    //1、解析标签的mode属性
    String mode = element.getAttribute("mode");
    if ("aspectj".equals(mode)) {
        //mode为 aspectj 则此处为aspectj模式
        this.registerTransactionAspect(element, parserContext);
    } else {
       //mode为 proxy 则此处为proxy模式(默认是proxy模式)
        AnnotationDrivenBeanDefinitionParser.AopAutoProxyConfigurer.configureAutoProxyCreator(element, parserContext);
    }

    return null;
}
//关于两种模式的选择 
//若只要目标对象实现甚至一个接口, 则使用proxy模式
//如果目标对象没有实现接口,则使用aspectj模式
//简单的说,如果把@Transactional放到接口上,就使用aspectj,放在实现类上就使用proxy

3).静态内部类AopAutoProxyConfigurer中的方法configureAutoProxyCreator()

private static class AopAutoProxyConfigurer {
    private AopAutoProxyConfigurer() {
    }

    public static void configureAutoProxyCreator(Element element, ParserContext parserContext) {
        //注册InfrastructureAdvisorAutoProxyCreator --> 3.1)
        AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element); 
        String txAdvisorBeanName = "org.springframework.transaction.config.internalTransactionAdvisor";
        if (!parserContext.getRegistry().containsBeanDefinition(txAdvisorBeanName)) {
            Object eleSource = parserContext.extractSource(element);
            //注册bean:AnnotationTransactionAttributeSource
            RootBeanDefinition sourceDef = new RootBeanDefinition("org.springframework.transaction.annotation.AnnotationTransactionAttributeSource");
            sourceDef.setSource(eleSource);
            sourceDef.setRole(2);
            String sourceName = parserContext.getReaderContext().registerWithGeneratedName(sourceDef);
            //注册bean:TransactionInterceptor
            RootBeanDefinition interceptorDef = new RootBeanDefinition(TransactionInterceptor.class);
            interceptorDef.setSource(eleSource);
            interceptorDef.setRole(2);
            AnnotationDrivenBeanDefinitionParser.registerTransactionManager(element, interceptorDef);
            interceptorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));
            String interceptorName = parserContext.getReaderContext().registerWithGeneratedName(interceptorDef);
            //注册bean:TransactionAttributeSourceAdvisor
            RootBeanDefinition advisorDef = new RootBeanDefinition(BeanFactoryTransactionAttributeSourceAdvisor.class);
            advisorDef.setSource(eleSource);
            advisorDef.setRole(2);
            // 将 TransactionAttributeSource 的 bean 注入 advisorDef 的 transactionAttributeSource 属性中
            advisorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));
            // 将 TransactionInterceptor 的 bean 注入 advisorDef 的 adviceBeanName 属性中
            advisorDef.getPropertyValues().add("adviceBeanName", interceptorName);
            if (element.hasAttribute("order")) {
                advisorDef.getPropertyValues().add("order", element.getAttribute("order"));
            }

            parserContext.getRegistry().registerBeanDefinition(txAdvisorBeanName, advisorDef);
            //注册Component:CompositeComponentDefinition
            CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), eleSource);
            compositeDef.addNestedComponent(new BeanComponentDefinition(sourceDef, sourceName));
            compositeDef.addNestedComponent(new BeanComponentDefinition(interceptorDef, interceptorName));
            compositeDef.addNestedComponent(new BeanComponentDefinition(advisorDef, txAdvisorBeanName));
            parserContext.registerComponent(compositeDef);
        }

    }
}

3.1)AopNamespaceUtils.registerAutoProxyCreatorIfNecessary

public static void registerAutoProxyCreatorIfNecessary(ParserContext parserContext, Element sourceElement) {
        //1.注册或升级creator  定义beanname 详见 3.11
        BeanDefinition beanDefinition = AopConfigUtils.registerAutoProxyCreatorIfNecessary(parserContext.getRegistry(), parserContext.extractSource(sourceElement));
        //2.对于proxy-tartarget-class 和expose-proxy属性的处理 
        //设置InfrastructureAdvisorAutoProxyCreator这个bean对应的属性,proxyTargetClass,exposeProxy 见3.12
        useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
        //3.注册组件并通知,便于监听器进一步处理
        registerComponentIfNecessary(beanDefinition, parserContext);
    }


// 3.11 跟踪代码走到AopConfigUtils的registerOrEscalateApcAsRequired方法
//其中cls = InfrastructureAdvisorAutoProxyCreator.class
private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, Object source) {
        Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
  //如果已经存在了自动代理创建器且与现在的不一致那么需要判断优先级
  if(registry.containsBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator")) {
            BeanDefinition apcDefinition = registry.getBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator");
      		//创建器不一致
            if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
                //已经存在的优先级
                int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());//这个方法就是查看这个类在一个arrayList里面的位置
                //当前优先级
                int requiredPriority = findPriorityForClass(cls);
                //值越大优先级越小 
                if (currentPriority < requiredPriority) {
                    apcDefinition.setBeanClassName(cls.getName());
                }
            }

            return null;
        } else {
      //如果不存在,则创建一个
            RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
            beanDefinition.setSource(source);
            beanDefinition.getPropertyValues().add("order", -2147483648);
            beanDefinition.setRole(2);
            registry.registerBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator", beanDefinition);
            return beanDefinition;
        }
    }

//3.12 设置InfrastructureAdvisorAutoProxyCreator这个bean对应的属性,proxyTargetClass,exposeProxy
private static void useClassProxyingIfNecessary(BeanDefinitionRegistry registry, Element sourceElement) {
        if (sourceElement != null) {
            boolean proxyTargetClass = Boolean.valueOf(sourceElement.getAttribute("proxy-target-class"));
            if (proxyTargetClass) {
                AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
            }

            boolean exposeProxy = Boolean.valueOf(sourceElement.getAttribute("expose-proxy"));
            if (exposeProxy) {
                AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
            }
        }

    }
//设置InfrastructureAdvisorAutoProxyCreator的proxyTargetClass属性
public static void forceAutoProxyCreatorToUseClassProxying(BeanDefinitionRegistry registry) {
        if (registry.containsBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator")) {
            BeanDefinition definition = registry.getBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator");
            definition.getPropertyValues().add("proxyTargetClass", Boolean.TRUE);
        }

    }
//设置InfrastructureAdvisorAutoProxyCreator的exposeProxy属性
static void forceAutoProxyCreatorToExposeProxy(BeanDefinitionRegistry registry) {
        if (registry.containsBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator")) {
            BeanDefinition definition = registry.getBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator");
            definition.getPropertyValues().add("exposeProxy", Boolean.TRUE);
        }

    }

综上所述 : 这个方法就是把

InfrastructureAdvisorAutoProxyCreator ,

AnnotationTransactionAttributeSource,

TransactionInterceptor (主要的拦截功能在这里实现)

BeanFactoryTransactionAttributeSourceAdvisor(此类的继承图如下,创建bean的代理类的时候该Advisor会被用上)
在这里插入图片描述

二.下面我们看一下InfrastructureAdvisorAutoProxyCreator

InfrastructureAdvisorAutoProxyCreator 的关系图如下
在这里插入图片描述

注意 : InfrastructureAdvisorAutoProxyCreator 实现了BeanPostProcessor接口,而在Spring之ClassPathXmlApplicationContext这篇讲解ClassPathXmlApplicationContext中我们说到关键方法refresh()时,里面registerBeanPostProcessors方法会将BeanPostProcessor的实现类注册到spring中,则在spring创建bean的时候,会调用InfrastructureAdvisorAutoProxyCreator 的父类AbstractAutoProxyCreator中的postProcessAfterInitialization()方法

public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (bean != null) {
            //创建一个cachekey,一般为类名拼接
            Object cacheKey = this.getCacheKey(bean.getClass(), beanName);
            // 是否已经是代理过的类(earlyProxyReferences是一个set)
            if (!this.earlyProxyReferences.contains(cacheKey)) {
                // 对 bean 进行封装
                return this.wrapIfNecessary(bean, beanName, cacheKey);
            }
        }

        return bean;
}

// wrapIfNecessary 方法 主要对bean进行分装
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
        // 如果已经处理过,则返回bean
        if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
            return bean;
         //不应该被代理的bean 
        } else if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
            return bean;
        //给定的 bean 类是否是一个基础类,不是的话,进行代理
        } else if (!this.isInfrastructureClass(bean.getClass()) && !this.shouldSkip(bean.getClass(), beanName)) {
            // 1.获取当前类的Advisors,在下面 1) 详细讲解
            Object[] specificInterceptors = this.getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, (TargetSource)null);
            // 2.如果不为空,则需要创建当前类的代理类
            if (specificInterceptors != DO_NOT_PROXY) {
                this.advisedBeans.put(cacheKey, Boolean.TRUE);
                // 3.创建代理类,在3.1中详细分析
                Object proxy = this.createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
                this.proxyTypes.put(cacheKey, proxy.getClass());
                return proxy;
            } else {//否则放到不必被代理的bean中
                this.advisedBeans.put(cacheKey, Boolean.FALSE);
                return bean;
            }
        } else {//如果是一个基础类 ,如 Advice、Pointcut AopInfrastructureBeans 等基础类型的类,或者配置了指定 bean 不需要自动代理(即上方的不应该被代理的bean)
            this.advisedBeans.put(cacheKey, Boolean.FALSE);
            return bean;
        }
 }

// 1) getAdvicesAndAdvisorsForBean()获取当前类的Advisors , 由其抽象子类AbstractAdvisorAutoProxyCreator去实现
public abstract class AbstractAdvisorAutoProxyCreator extends AbstractAutoProxyCreator {
	protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String 													beanName, TargetSource targetSource) {
        List<Advisor> advisors = this.findEligibleAdvisors(beanClass, beanName);//调用此方法,如下  (1)
        return advisors.isEmpty() ? DO_NOT_PROXY : advisors.toArray();
    }
    
    //(1) findEligibleAdvisors 获取当前类的Advisors
    protected List<Advisor> findEligibleAdvisors(Class<?> beanClass,String beanName){
        //获取所有的Advisors 详见 (1.1),我们之前放入的
        List<Advisor> candidateAdvisors = this.findCandidateAdvisors();
        //找到适合本类的Advisors 详见 (1.2)
        List<Advisor> eligibleAdvisors =       				          this.findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
        this.extendAdvisors(eligibleAdvisors);
        if (!eligibleAdvisors.isEmpty()) {
            eligibleAdvisors = this.sortAdvisors(eligibleAdvisors);
        }

        return eligibleAdvisors;
    }
    //(1.1)findCandidateAdvisors()
    protected List<Advisor> findCandidateAdvisors() {
        return this.advisorRetrievalHelper.findAdvisorBeans(); // 见(1.1-1)
    }
    //(1.2)找到适合本类的Advisors,findAdvisorsThatCanApply()方法
    protected List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
        //设置通用代理类名
        ProxyCreationContext.setCurrentProxiedBeanName(beanName);

        List var4;
        try {//见(1.2-1)
            var4 = AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
        } finally {
            ProxyCreationContext.setCurrentProxiedBeanName((String)null);
        }

        return var4;
    }
}
//(1.1-1)  转到BeanFactoryAdvisorRetrievalHelper类的findAdvisorBeans方法
public List<Advisor> findAdvisorBeans() {
        //
        String[] advisorNames = null;
        synchronized(this) {
            //Advisor 类型的 类名的数组
            advisorNames = this.cachedAdvisorBeanNames;
            if (advisorNames == null) {//如果为null
                // 获取 BeanFactory 中 Advisor 类型的 类名数组(此处会找到上面注册到spring中的BeanFactoryTransactionAttributeSourceAdvisor,取出来)
                advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors
                    (this.beanFactory, Advisor.class, true, false);
                this.cachedAdvisorBeanNames = advisorNames;
            }
        }
		//如果长度为0,则返回一个空List
        if (advisorNames.length == 0) {
            return new LinkedList();
        } else {
            List<Advisor> advisors = new LinkedList();
            String[] var3 = advisorNames;
            int var4 = advisorNames.length;

            for(int var5 = 0; var5 < var4; ++var5) {
                String name = var3[var5];
                if (this.isEligibleBean(name)) {
                    if (this.beanFactory.isCurrentlyInCreation(name)) {
                        if (logger.isDebugEnabled()) {
                            logger.debug("Skipping currently created advisor '" + name + "'");
                        }
                    } else {
                        try {
                            // 实例化 Advisor 类型的 bean,并且放入 advisors 中
                            advisors.add(this.beanFactory.getBean(name, Advisor.class));
                        } catch (BeanCreationException var10) {
                            Throwable rootCause = var10.getMostSpecificCause();
                            if (rootCause instanceof BeanCurrentlyInCreationException) {
                                BeanCreationException bce = (BeanCreationException)rootCause;
                                if (this.beanFactory.isCurrentlyInCreation(bce.getBeanName())) {
                                    if (logger.isDebugEnabled()) {
                                        logger.debug("Skipping advisor '" + name + "' with dependency on currently created bean: " + var10.getMessage());
                                    }
                                    continue;
                                }
                            }

                            throw var10;
                        }
                    }
                }
            }

            return advisors;
        }
    }
//(1.2-1)AopUtils中的findAdvisorsThatCanApply方法 此处传递的Advisor即为BeanFactoryTransactionAttributeSourceAdvisor
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
    	//为空则直接返回
        if (candidateAdvisors.isEmpty()) {
            return candidateAdvisors;
        } else {
            List<Advisor> eligibleAdvisors = new LinkedList();
            Iterator var3 = candidateAdvisors.iterator();

            while(var3.hasNext()) {
                Advisor candidate = (Advisor)var3.next();
                //判断candidate属于IntroductionAdvisor子类 同时 advisor能否匹配一个指定的类型,则添加此advisor
                if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
                    eligibleAdvisors.add(candidate);
                }
            }
            boolean hasIntroductions = !eligibleAdvisors.isEmpty();
            Iterator var7 = candidateAdvisors.iterator();

            while(var7.hasNext()) {
                Advisor candidate = (Advisor)var7.next();
                //没有添加过candidate,判断是否支持引入匹配,即对于普通bean的处理,此处进入canApply里面进行处理,传递的Advisor为BeanFactoryTransactionAttributeSourceAdvisor -->(1.2-1.1)
                if (!(candidate instanceof IntroductionAdvisor) && canApply(candidate, clazz, hasIntroductions)) {
                    eligibleAdvisors.add(candidate);
                }
            }

            return eligibleAdvisors;
        }
}

//(1.2-1.1) canApply() advisor为BeanFactoryTransactionAttributeSourceAdvisor
public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
    //从上面的BeanFactoryTransactionAttributeSourceAdvisor继承图知道此类间接实现PointcutAdvisor,则走下面第二个else if()
        if (advisor instanceof IntroductionAdvisor) {
            return ((IntroductionAdvisor)advisor).getClassFilter().matches(targetClass);
        } else if (advisor instanceof PointcutAdvisor) {
            PointcutAdvisor pca = (PointcutAdvisor)advisor;
            //此处调用BeanFactoryTransactionAttributeSourceAdvisor的getPointcut()方法返回值做参数,继续调用canApply,其中getPointcut()返回值是TransactionAttributeSourcePointcut
            //则此处为canApply(TransactionAttributeSourcePointcut,targetClass,hasIntroductions)
            return canApply(pca.getPointcut(), targetClass, hasIntroductions);
        } else {
            return true;
        }
 }
//继续跟踪canApply() pc = TransactionAttributeSourcePointcut类
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
        Assert.notNull(pc, "Pointcut must not be null");
        if (!pc.getClassFilter().matches(targetClass)) {
            return false;
        } else {
            //pc.getMethodMatcher() 返回的还是自身(this)
            MethodMatcher methodMatcher = pc.getMethodMatcher();
            IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
            if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
                introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher)methodMatcher;
            }
			// 获取对应类的所有接口连同类自身
            Set<Class<?>> classes = new LinkedHashSet(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
            classes.add(targetClass);
            Iterator var6 = classes.iterator();

            while(var6.hasNext()) {
                Class<?> clazz = (Class)var6.next();
                //获取类中所有方法
                Method[] methods = clazz.getMethods();
                Method[] var9 = methods;
                int var10 = methods.length;

                for(int var11 = 0; var11 < var10; ++var11) {
                    Method method = var9[var11];
                    //开始匹配操作 此处有一处methodMatcher.matches()方法,此处即调用的是TransactionAttributeSourcePointcut类的matches方法
                    if (introductionAwareMethodMatcher != null && introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) || methodMatcher.matches(method, targetClass)) {
                        return true;
                    }
                }
            }

            return false;
        }
}

TransactionAttributeSourcePointcut类的matches方法

public boolean matches(Method method, Class<?> targetClass) {
        TransactionAttributeSource tas = this.getTransactionAttributeSource();
    	//下面的tas.getTransactionAttribute调用的是AbstractFallbackTransactionAttributeSource类的getTransactionAttribute()
        return tas == null || tas.getTransactionAttribute(method,targetClass)!= null;
    }

AbstractFallbackTransactionAttributeSource类

public TransactionAttribute getTransactionAttribute(Method method, Class<?> targetClass) {
    //查询缓存中是否存在
    //根据方法,类生成唯一id
    Object cacheKey = this.getCacheKey(method, targetClass);
    //根据id判断是否有值
    Object cached = this.attributeCache.get(cacheKey);
    if (cached != null) {//存在 判读是不是空事务,是,则返回null
        return cached == NULL_TRANSACTION_ATTRIBUTE ? null : (TransactionAttribute)cached;//返回对应是属性
    } else {//不存在
        TransactionAttribute txAtt = this.computeTransactionAttribute(method, targetClass);//获取方法上的事物配置属性 -- >1.12
        if (txAtt == null) {
            //放到缓存中
            this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE);
        } else {
            if (this.logger.isDebugEnabled()) {
                Class<?> classToLog = targetClass != null ? targetClass : method.getDeclaringClass();
                this.logger.debug("Adding transactional method '" + classToLog.getSimpleName() + "." + method.getName() + "' with attribute: " + txAtt);
            }

            this.attributeCache.put(cacheKey, txAtt);
        }

        return txAtt;
    }
}

//computeTransactionAttribute()方法
private TransactionAttribute computeTransactionAttribute(Method method, Class<?> targetClass) {
    //如果该方法不是public方法,则直接返回空
    if (this.allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
        return null;
    } else {
        Class<?> userClass = ClassUtils.getUserClass(targetClass);
        //如果是接口,则找到实现类的方法
        Method specificMethod = ClassUtils.getMostSpecificMethod(method, userClass);
        specificMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
        //1.解析方法上的@Transactional属性,从这里可以看出,方法上的@Transactional要优先于类上的
        TransactionAttribute txAtt = this.findTransactionAttribute(specificMethod);
        if (txAtt != null) {
            return txAtt;
        } else {
            //2.解析目标类上的@Transactional属性
            txAtt = this.findTransactionAttribute(specificMethod.getDeclaringClass());
            if (txAtt != null) {
                return txAtt;
            } else if (specificMethod != method) {
                txAtt = this.findTransactionAttribute(method);
                return txAtt != null ? txAtt : this.findTransactionAttribute(method.getDeclaringClass());
            } else {
                return null;
            }
        }
    }
}

//findTransactionAttribute()方法
protected TransactionAttribute findTransactionAttribute(Class<?> clazz) {
        return this.determineTransactionAttribute(clazz);
}
//determineTransactionAttribute()方法
protected TransactionAttribute determineTransactionAttribute(AnnotatedElement ae) {
        Iterator var2 = this.annotationParsers.iterator();

        TransactionAttribute attr;
        do {
            if (!var2.hasNext()) {
                return null;
            }

            TransactionAnnotationParser annotationParser = (TransactionAnnotationParser)var2.next();
            //此处是调用的SpringTransactionAnnotationParser的parseTransactionAnnotation方法
            attr = annotationParser.parseTransactionAnnotation(ae);
        } while(attr == null);

        return attr;
  }
//SpringTransactionAnnotationParser的parseTransactionAnnotation()方法
public TransactionAttribute parseTransactionAnnotation(AnnotatedElement ae) {
        AnnotationAttributes ann = AnnotatedElementUtils.getAnnotationAttributes(ae, Transactional.class.getName());//此处即获取Transactional类,即@Transactional
        return ann != null ? this.parseTransactionAnnotation(ann) : null;//this.parseTransactionAnnotation(ann)即为查询@Transactional内部参数的值
    }
//parseTransactionAnnotation方法,对应的名称都可以在Transactional中找到,此处不做说明
protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {
        RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
        Propagation propagation = (Propagation)attributes.getEnum("propagation");
        rbta.setPropagationBehavior(propagation.value());
        Isolation isolation = (Isolation)attributes.getEnum("isolation");
        rbta.setIsolationLevel(isolation.value());
        rbta.setTimeout(attributes.getNumber("timeout").intValue());
        rbta.setReadOnly(attributes.getBoolean("readOnly"));
        rbta.setQualifier(attributes.getString("value"));
        ArrayList<RollbackRuleAttribute> rollBackRules = new ArrayList();
        Class<?>[] rbf = attributes.getClassArray("rollbackFor");
        Class[] var7 = rbf;
        int var8 = rbf.length;

        int var9;
        for(var9 = 0; var9 < var8; ++var9) {
            Class<?> rbRule = var7[var9];
            RollbackRuleAttribute rule = new RollbackRuleAttribute(rbRule);
            rollBackRules.add(rule);
        }

        String[] rbfc = attributes.getStringArray("rollbackForClassName");
        String[] var16 = rbfc;
        var9 = rbfc.length;

        int var19;
        for(var19 = 0; var19 < var9; ++var19) {
            String rbRule = var16[var19];
            RollbackRuleAttribute rule = new RollbackRuleAttribute(rbRule);
            rollBackRules.add(rule);
        }

        Class<?>[] nrbf = attributes.getClassArray("noRollbackFor");
        Class[] var18 = nrbf;
        var19 = nrbf.length;

        int var23;
        for(var23 = 0; var23 < var19; ++var23) {
            Class<?> rbRule = var18[var23];
            NoRollbackRuleAttribute rule = new NoRollbackRuleAttribute(rbRule);
            rollBackRules.add(rule);
        }

        String[] nrbfc = attributes.getStringArray("noRollbackForClassName");
        String[] var22 = nrbfc;
        var23 = nrbfc.length;

        for(int var25 = 0; var25 < var23; ++var25) {
            String rbRule = var22[var25];
            NoRollbackRuleAttribute rule = new NoRollbackRuleAttribute(rbRule);
            rollBackRules.add(rule);
        }

        rbta.getRollbackRules().addAll(rollBackRules);
        return rbta;
    }

事务准备阶段,注册流程

  1. spring解析xml是通过DefaultNamespaceHandlerResolver为入口,执行 resolve()方法,从而调用TxNamespaceHandler,ContextNamespaceHandler,AopNamespaceHandler,jdbcNamespaceHandler等类的init()方法,

    同时又对BeanDefinitionParser接口的实现类的parse方法进行调用

AbstractApplicationContext类
BeanDefinitionParserDelegate类
没有注册handler
NamespaceHandler所有实例类的
已经注册handler
refresh方法
obtainFreshBeanFactory方法
parseCustomElement方法
DefaultNamespaceHandlerResolver类resolve方法
init方法
BeanDefinitionParser接口的实现类的parse方法
  1. 解析<tx:annotation-driven transaction-manager=“transactionManager”/>,通过TxNamespaceHandler的init方法,创建BeanDefinitionParser接口的实现类AnnotationDrivenBeanDefinitionParser的parse方法,spring默认是proxy模式,则走静态内部类AopAutoProxyConfigurer中的方法configureAutoProxyCreator(),在此方法中主要完成了InfrastructureAdvisorAutoProxyCreator 注册,

    AnnotationTransactionAttributeSource注册,

    TransactionInterceptor 注册(主要的拦截功能在这里实现)

    BeanFactoryTransactionAttributeSourceAdvisor注册(创建bean的代理类的时候该Advisor会被用上)

init方法
parse方法,proxy模式下
TxNamespaceHandler类
AnnotationDrivenBeanDefinitionParser类
AopAutoProxyConfigurer静态内部类
configureAutoProxyCreator方法
InfrastructureAdvisorAutoProxyCreator注册
AnnotationTransactionAttributeSource注册
TransactionInterceptor 注册
BeanFactoryTransactionAttributeSourceAdvisor注册

spaceHandlerResolver类resolve方法]
D–NamespaceHandler所有实例类的–>E[init方法]
C–已经注册handler–>F[BeanDefinitionParser接口的实现类的parse方法]


> 2. 解析<tx:annotation-driven transaction-manager="transactionManager"/>,通过TxNamespaceHandler的init方法,创建BeanDefinitionParser接口的实现类AnnotationDrivenBeanDefinitionParser的parse方法,spring默认是proxy模式,则走静态内部类AopAutoProxyConfigurer中的方法configureAutoProxyCreator(),在此方法中主要完成了InfrastructureAdvisorAutoProxyCreator 注册, 
>
>    AnnotationTransactionAttributeSource注册,
>
>    TransactionInterceptor 注册(**主要的拦截功能在这里实现**)
>
>    BeanFactoryTransactionAttributeSourceAdvisor注册(**创建bean的代理类的时候该Advisor会被用上**)

```mermaid
graph TB
  A[TxNamespaceHandler类]--init方法-->B[AnnotationDrivenBeanDefinitionParser类]
  B--parse方法,proxy模式下-->C[AopAutoProxyConfigurer静态内部类]
  C-->D[configureAutoProxyCreator方法]
  D-->E[InfrastructureAdvisorAutoProxyCreator注册]
  D-->F[AnnotationTransactionAttributeSource注册]
  D-->H[TransactionInterceptor 注册]
  D-->I[BeanFactoryTransactionAttributeSourceAdvisor注册]
  1. refresh()时,里面registerBeanPostProcessors方法会将BeanPostProcessor的实现类注册到spring中,则在spring创建bean的时候,会调用InfrastructureAdvisorAutoProxyCreator 的父类AbstractAutoProxyCreator中的postProcessAfterInitialization()方法,从而走到findEligibleAdvisors方法中取出之前注册到spring中BeanFactoryTransactionAttributeSourceAdvisor,后因为此类实现PointcutAdvisor接口,走canApply()传递的为BeanFactoryTransactionAttributeSourceAdvisor,后走到AbstractFallbackTransactionAttributeSource类getTransactionAttribute方法中根据getCacheKey获取类方法的唯一id,computeTransactionAttribute根据获取方法上的事物,即@Transactional
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
springcloud-netflix是一个基于Spring Cloud的微服务框架。它提供了一系列工具和组件来简化开发和管理分布式系统的任务。其中包括Eureka、Feign和Zuul等组件。 在搭建springcloud-netflix项目时,需要创建父工程和子工程。父工程是springcloud-netflix-parent,子工程可以是springcloud-netflix-eureka、springcloud-netflix-service-pay等。每个子工程都需要在pom.xml文件中导入相应的依赖。 对于springcloud-netflix-eureka,需要导入spring-cloud-starter-netflix-eureka-server和spring-cloud-starter-netflix-eureka-client等依赖。此外,还需要配置相关的类。 对于springcloud-netflix-service-pay,需要导入spring-cloud-starter-netflix-eureka-client、spring-boot-starter-web和spring-cloud-starter-openfeign等依赖。同样,也需要配置相关的类。 对于Zuul,它是一个API Gateway服务器,提供了动态路由、监控、弹性和安全等边缘服务的框架。在搭建Zuul时,需要导入spring-cloud-starter-netflix-eureka-client、spring-boot-starter-web和spring-cloud-starter-netflix-zuul等依赖。同时,需要配置开启Zuul。 总之,springcloud-netflix是一个基于Spring Cloud的微服务框架,包括了Eureka、Feign和Zuul等组件,可以帮助简化开发和管理分布式系统的任务。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [SpringCloudNetflix](https://blog.csdn.net/Exist_W/article/details/131867868)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值