spring源码之AOP中篇

 

前言

上篇介绍了一些AOP的基础知识,本篇来说一下spring aop的源码分析。初读AOP时,茫然地不知道从哪里开始,可能是当初对IOC的理解不够深刻。后面发现其实AOP的入口和IOC一样,也是从两个方法开始。一个是AbstractApplicationContext的refresh方法中调用obtainFreshBeanFactory去读取配置文件进行初始化操作,另一个就是getBean方法了。

概述

在读IOC的时候,我们知道IOC分为两个过程:初始化和依赖注入,那么AOP就是在这两种过程加了特殊处理。

  • 在初始化加载Bean定义时加了特殊处理
  • 在依赖注入时加了特殊处理

避免篇幅过长,本篇介绍AOP的初始化操作时的特殊处理。

初始化加载Bean定义时的特殊处理

我们在IOC中分析知道,在refresh方法中调用obtainFreshBeanFactory方法,一步步跟进去,最终会把XML的配置信息解析成一个个BeanDefinition对象并注册到DefaultListableBeanFactory上。在DefaultBeanDefinitionDocumentReader的parseBeanDefinitions方法中把对定义信息的解析分为了默认元素解析和用户元素解析。AOP的话,走的就是用户元素解析的分支。下面我们以这个为起点,进行分析。

  • root标签是默认命名空间下的,而<aop:conf>标签不是,则会走parseCustomElement方法进行解析
//DefaultBeanDefinitionDocumentReader的parseBeanDefinitions方法
//默认命名空间下的标签走默认标签解析的方法(比如<bean>),用户标签走用户标签解析的方法(比如<aop:conf>)
//这里走用户定义的解析方式

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)) {
                    parseDefaultElement(ele, delegate);
                }
                else {
                    delegate.parseCustomElement(ele);
                }
            }
        }
    }
    else {
        delegate.parseCustomElement(root);
    }
}
  • 这个方法可以分成两部分,
    • 先取获取命名空间处理器,对应到AOP就是AOPNamespaceHandler,
    • 然后是AOPNameSpaceHandler解析标签的过程
//BeanDefinitionParserDelegate类的方法
//获取命名空间处理器对标签进行解析
//这里通过AopNamespaceHander对<aop:conf>、<aop:aspect>等标签进行解析
public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
    String namespaceUri = getNamespaceURI(ele);
    NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
    if (handler == null) {
        error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
        return null;
    }
    return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}
  • 获取相应的NamespaceHandler,这里也就是获取AopNamespaceHandler。我们需要回过去看一些代码
    • 回到XmlBeanDefintionReader的registerBeanDefintions方法,这里创建了ReadContext。
    • 然后跟进去,可以看到创建了DefaultNamespaceHandlerResolver对象,重要的是我们要看到DefaultNamespaceHandlerResolver的构造函数,这里赋值了一个默认的命名空间处理器的定位地址,即DEFAULT_HANDLER_MAPPINGS_LOCATION  
//XmlBeanDefinitionReader类的方法
//解析Document成BeanDefinition,并注册到容器上
//这里我们关注的是创建命名空间解析器
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
  BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
  int countBefore = getRegistry().getBeanDefinitionCount();
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
 return getRegistry().getBeanDefinitionCount() - countBefore;
}
protected NamespaceHandlerResolver createDefaultNamespaceHandlerResolver() { 
  return new DefaultNamespaceHandlerResolver(getResourceLoader().getClassLoader());
}
public DefaultNamespaceHandlerResolver(ClassLoader classLoader) {
    this(classLoader, DEFAULT_HANDLER_MAPPINGS_LOCATION);
}
//DefaultNamespaceHandlerResolver类的属性
//通过构造函数设置资源定位地址
public
static final String DEFAULT_HANDLER_MAPPINGS_LOCATION = "META-INF/spring.handlers";
  • 上面我们回过去看了一些代码,主要是为了搞清楚资源定位路径的地址是什么。我们再回到上上步,看到调用了this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri),
    • 跟进去看到其实就是加载META-INF/spring.handlers文件内容到Map中,然后根据namespace就可以找到对应的处理类了(AopNamespaceHandler)
    • 然后调用处理器的init方法,对于AopNamespaceHandler就是注册了四个处理类
      • config-->ConfigBeanDefinitionParser
      • aspectj-autoproxy-->AspectJAutoProxyBeanDefinitionParser
      • scoped-proxy-->ScopedProxyBeanDefinitionDecorator
      • spring-configured-->SpringConfiguredBeanDefinitionParser
//DefaultNamespaceHandlerResolver类的方法
//得到合适的标签处理器,并对标签处理器进行初始化
//这里得到AopNamespaceHander,并注册了四个解析器。这里的

//getHandlerMappings方法可以跟进去看看,其实就是加载了上个步骤中分析的定制地址下的资源,得到处理器的全类名
//init方法作了一初始化操作,这里就是注册了四个解析器
public NamespaceHandler resolve(String namespaceUri) {
    Map<String, Object> handlerMappings = getHandlerMappings();
    Object handlerOrClassName = handlerMappings.get(namespaceUri);
    if (handlerOrClassName == null) {
        return null;
    }
    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");
            }
            NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
            namespaceHandler.init();
            handlerMappings.put(namespaceUri, namespaceHandler);
            return namespaceHandler;
        }
        catch (ClassNotFoundException ex) {
            throw new FatalBeanException("NamespaceHandler class [" + className + "] for namespace [" +
                    namespaceUri + "] not found", ex);
        }
        catch (LinkageError err) {
            throw new FatalBeanException("Invalid NamespaceHandler class [" + className + "] for namespace [" +
                    namespaceUri + "]: problem with handler class file or dependent class", err);
        }
    }
}
//这里是spring-aop项目的资源路径META-INF/spring.handlers下spring.hander文件的内容,正是通过这个拿到了处理类名的
http\://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler
  • 通过上面,我们已经拿到处理器,并注册了四个解析器。下面就开始分析parse对解析过程。
    • 首先拿到合适的解析器,这个分析的是<aop:config>标签,则用之前注册的ConfigBeanDefinitionParser进行解析
    • 再进行解析
//NamespaceHandlerSupport类的方法
//获取合适的解析器结标签进行解析
//这里是ConfigBeanDefinitionParser对<aop:conf>进行解析
public
BeanDefinition parse(Element element, ParserContext parserContext) { return findParserForElement(element, parserContext).parse(element, parserContext); }
//ConfigBeanDefinitionParser类的方法
//解析<aop:conf>标签,首先我们可以看到会向容器中注册一实现了
org.springframework.aop.config.internalAutoProxyCreator接口的实现类的BeanDefinition,
//然后再去循环解析下面的子节点
public BeanDefinition parse(Element element, ParserContext parserContext) {
    CompositeComponentDefinition compositeDef =
            new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
    parserContext.pushContainingComponent(compositeDef);

    configureAutoProxyCreator(parserContext, element);

    List<Element> childElts = DomUtils.getChildElements(element);
    for (Element elt: childElts) {
        String localName = parserContext.getDelegate().getLocalName(elt);
        if (POINTCUT.equals(localName)) {
            parsePointcut(elt, parserContext);
        }
        else if (ADVISOR.equals(localName)) {
            parseAdvisor(elt, parserContext);
        }
        else if (ASPECT.equals(localName)) {
            parseAspect(elt, parserContext);
        }
    }
    parserContext.popAndRegisterContainingComponent();
    return null;
}
  • 注册一个实现了InternalAutoProxyCreator接口的实现类的信息,根据优先级(其实就是在List的索引值大小),默认是AspectJAwareAdvisorAutoProxyCreator,这个类是整个AOP分析的重点,在后面分析依赖注入时重点进行分析。
//AopConfigUtils类的方法
//注册一个优先级最高的InternalAutoProxyCreator接口的实现类,默认是AspectJAwareAdvisorAutoProxyCreator
private
static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, Object source) { Assert.notNull(registry, "BeanDefinitionRegistry must not be null"); if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) { BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME); if (!cls.getName().equals(apcDefinition.getBeanClassName())) { int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName()); int requiredPriority = findPriorityForClass(cls); if (currentPriority < requiredPriority) { apcDefinition.setBeanClassName(cls.getName()); } } return null; } RootBeanDefinition beanDefinition = new RootBeanDefinition(cls); beanDefinition.setSource(source); beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE); beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition); return beanDefinition; }
//这里我们可以看到,优先级其实很简单,就是在List中的索引值大小,AnnotationAwareAspectJAutoProxyCreator的优先级就最高,我们在JAVA CONFIG配置中就是使用的它。
//当然,我们自己也可以自己实现InternalAutoProxyCreator接口并添加到列表中
static
{ APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class); APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class); APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class); }
  • InternalAutoProxyCreator注册完成后,接下来的的第一个子节点的解析就是<aop:aspect>节点
    • 解析<aop:declare-parents>,注册DeclareParentsAdvisor类的BeanDefinition
    • 解析<aop:before>,注册AspectJPointcutAdvisor类的BeanDefinition
    • 解析<aop:pointcut>,注册AspectJExpressionPointcut类的BeanDefinition
    •  
//ConfigBeanDefinitionParser类的方法
//解析<aop:aspect>标签
private
void parseAspect(Element aspectElement, ParserContext parserContext) { String aspectId = aspectElement.getAttribute(ID); String aspectName = aspectElement.getAttribute(REF); try { this.parseState.push(new AspectEntry(aspectId, aspectName)); List<BeanDefinition> beanDefinitions = new ArrayList<BeanDefinition>(); List<BeanReference> beanReferences = new ArrayList<BeanReference>(); List<Element> declareParents = DomUtils.getChildElementsByTagName(aspectElement, DECLARE_PARENTS); for (int i = METHOD_INDEX; i < declareParents.size(); i++) { Element declareParentsElement = declareParents.get(i); beanDefinitions.add(parseDeclareParents(declareParentsElement, parserContext)); } // We have to parse "advice" and all the advice kinds in one loop, to get the // ordering semantics right. NodeList nodeList = aspectElement.getChildNodes(); boolean adviceFoundAlready = false; for (int i = 0; i < nodeList.getLength(); i++) { Node node = nodeList.item(i); if (isAdviceNode(node, parserContext)) { if (!adviceFoundAlready) { adviceFoundAlready = true; if (!StringUtils.hasText(aspectName)) { parserContext.getReaderContext().error( "<aspect> tag needs aspect bean reference via 'ref' attribute when declaring advices.", aspectElement, this.parseState.snapshot()); return; } beanReferences.add(new RuntimeBeanReference(aspectName)); } AbstractBeanDefinition advisorDefinition = parseAdvice( aspectName, i, aspectElement, (Element) node, parserContext, beanDefinitions, beanReferences); beanDefinitions.add(advisorDefinition); } } AspectComponentDefinition aspectComponentDefinition = createAspectComponentDefinition( aspectElement, aspectId, beanDefinitions, beanReferences, parserContext); parserContext.pushContainingComponent(aspectComponentDefinition); List<Element> pointcuts = DomUtils.getChildElementsByTagName(aspectElement, POINTCUT); for (Element pointcutElement : pointcuts) { parsePointcut(pointcutElement, parserContext); } parserContext.popAndRegisterContainingComponent(); } finally { this.parseState.pop(); } }
  • 解析<aop:declare-parents>标签,创建DeclareParentsAdvisor类的BeanDefinition,并注册到DefaultLisableBeanFactory
//ConfigBeanDefinitionParser类的方法
//创建DeclareParentsAdvisor类的BeanDefinition,并注册到DefaultLisableBeanFactory中,这里我们看到了一种新的Advisor,而常用的五种类型都是
AspectJPointcutAdvisor,具体使用可以参照官方文档
private AbstractBeanDefinition parseDeclareParents(Element declareParentsElement, ParserContext parserContext) {
    BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(DeclareParentsAdvisor.class);
    builder.addConstructorArgValue(declareParentsElement.getAttribute(IMPLEMENT_INTERFACE));
    builder.addConstructorArgValue(declareParentsElement.getAttribute(TYPE_PATTERN));

    String defaultImpl = declareParentsElement.getAttribute(DEFAULT_IMPL);
    String delegateRef = declareParentsElement.getAttribute(DELEGATE_REF);

    if (StringUtils.hasText(defaultImpl) && !StringUtils.hasText(delegateRef)) {
        builder.addConstructorArgValue(defaultImpl);
    }
    else if (StringUtils.hasText(delegateRef) && !StringUtils.hasText(defaultImpl)) {
        builder.addConstructorArgReference(delegateRef);
    }
    else {
        parserContext.getReaderContext().error(
                "Exactly one of the " + DEFAULT_IMPL + " or " + DELEGATE_REF + " attributes must be specified",
                declareParentsElement, this.parseState.snapshot());
    }

    AbstractBeanDefinition definition = builder.getBeanDefinition();
    definition.setSource(parserContext.extractSource(declareParentsElement));
    parserContext.getReaderContext().registerWithGeneratedName(definition);
    return definition;
}
  • 解析<aop:before>等五个标签,这里主要分为三个步骤
    • 根据通知类型不同,创建不同Advice类的RootBeanDefinition
    • 将上面的RootBeanDefinition再封装到AspectJPointcutAdvisor类的RootBeanDefinition
    • 把上面的RootBeanDefinition注册到DefaultListableBeanFactory
//ConfigBeanDefinitionParser类的方法
//判断是否是一种类型的通知
private
boolean isAdviceNode(Node aNode, ParserContext parserContext) { if (!(aNode instanceof Element)) { return false; } else { String name = parserContext.getDelegate().getLocalName(aNode); return (BEFORE.equals(name) || AFTER.equals(name) || AFTER_RETURNING_ELEMENT.equals(name) || AFTER_THROWING_ELEMENT.equals(name) || AROUND.equals(name)); } }
//ConfigBeanDefinitionParser类的方法
//解析五种通知类型,创建相应通知的BeanDefinition,并注册到DefaultLisableBeanFactory中
private AbstractBeanDefinition parseAdvice(
        String aspectName, int order, Element aspectElement, Element adviceElement, ParserContext parserContext,
        List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) {

    try {
        this.parseState.push(new AdviceEntry(parserContext.getDelegate().getLocalName(adviceElement)));

        // create the method factory bean
        RootBeanDefinition methodDefinition = new RootBeanDefinition(MethodLocatingFactoryBean.class);
        methodDefinition.getPropertyValues().add("targetBeanName", aspectName);
        methodDefinition.getPropertyValues().add("methodName", adviceElement.getAttribute("method"));
        methodDefinition.setSynthetic(true);

        // create instance factory definition
        RootBeanDefinition aspectFactoryDef =
                new RootBeanDefinition(SimpleBeanFactoryAwareAspectInstanceFactory.class);
        aspectFactoryDef.getPropertyValues().add("aspectBeanName", aspectName);
        aspectFactoryDef.setSynthetic(true);

        // register the pointcut
        AbstractBeanDefinition adviceDef = createAdviceDefinition(
                adviceElement, parserContext, aspectName, order, methodDefinition, aspectFactoryDef,
                beanDefinitions, beanReferences);

        // configure the advisor
        RootBeanDefinition advisorDefinition = new RootBeanDefinition(AspectJPointcutAdvisor.class);
        advisorDefinition.setSource(parserContext.extractSource(adviceElement));
        advisorDefinition.getConstructorArgumentValues().addGenericArgumentValue(adviceDef);
        if (aspectElement.hasAttribute(ORDER_PROPERTY)) {
            advisorDefinition.getPropertyValues().add(
                    ORDER_PROPERTY, aspectElement.getAttribute(ORDER_PROPERTY));
        }

        // register the final advisor
        parserContext.getReaderContext().registerWithGeneratedName(advisorDefinition);

        return advisorDefinition;
    }
    finally {
        this.parseState.pop();
    }
private AbstractBeanDefinition createAdviceDefinition(
        Element adviceElement, ParserContext parserContext, String aspectName, int order,
        RootBeanDefinition methodDef, RootBeanDefinition aspectFactoryDef,
        List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) {

    RootBeanDefinition adviceDefinition = new RootBeanDefinition(getAdviceClass(adviceElement, parserContext));
    adviceDefinition.setSource(parserContext.extractSource(adviceElement));

    adviceDefinition.getPropertyValues().add(ASPECT_NAME_PROPERTY, aspectName);
    adviceDefinition.getPropertyValues().add(DECLARATION_ORDER_PROPERTY, order);

    if (adviceElement.hasAttribute(RETURNING)) {
        adviceDefinition.getPropertyValues().add(
                RETURNING_PROPERTY, adviceElement.getAttribute(RETURNING));
    }
    if (adviceElement.hasAttribute(THROWING)) {
        adviceDefinition.getPropertyValues().add(
                THROWING_PROPERTY, adviceElement.getAttribute(THROWING));
    }
    if (adviceElement.hasAttribute(ARG_NAMES)) {
        adviceDefinition.getPropertyValues().add(
                ARG_NAMES_PROPERTY, adviceElement.getAttribute(ARG_NAMES));
    }

    ConstructorArgumentValues cav = adviceDefinition.getConstructorArgumentValues();
    cav.addIndexedArgumentValue(METHOD_INDEX, methodDef);

    Object pointcut = parsePointcutProperty(adviceElement, parserContext);
    if (pointcut instanceof BeanDefinition) {
        cav.addIndexedArgumentValue(POINTCUT_INDEX, pointcut);
        beanDefinitions.add((BeanDefinition) pointcut);
    }
    else if (pointcut instanceof String) {
        RuntimeBeanReference pointcutRef = new RuntimeBeanReference((String) pointcut);
        cav.addIndexedArgumentValue(POINTCUT_INDEX, pointcutRef);
        beanReferences.add(pointcutRef);
    }

    cav.addIndexedArgumentValue(ASPECT_INSTANCE_FACTORY_INDEX, aspectFactoryDef);

    return adviceDefinition;
}
private Class<?> getAdviceClass(Element adviceElement, ParserContext parserContext) {
    String elementName = parserContext.getDelegate().getLocalName(adviceElement);
    if (BEFORE.equals(elementName)) {
        return AspectJMethodBeforeAdvice.class;
    }
    else if (AFTER.equals(elementName)) {
        return AspectJAfterAdvice.class;
    }
    else if (AFTER_RETURNING_ELEMENT.equals(elementName)) {
        return AspectJAfterReturningAdvice.class;
    }
    else if (AFTER_THROWING_ELEMENT.equals(elementName)) {
        return AspectJAfterThrowingAdvice.class;
    }
    else if (AROUND.equals(elementName)) {
        return AspectJAroundAdvice.class;
    }
    else {
        throw new IllegalArgumentException("Unknown advice kind [" + elementName + "].");
    }
}
  • 解析切点,这里分为两步
    • 创建一个AspectJExpressionPointcut类的RootBeanDefinition类的方法
    • 注册RootBeanDefinition到DefaultListableBeanFactory上
//ConfigBeanDefinitionParser类的方法
//
private
AbstractBeanDefinition parsePointcut(Element pointcutElement, ParserContext parserContext) { String id = pointcutElement.getAttribute(ID); String expression = pointcutElement.getAttribute(EXPRESSION); AbstractBeanDefinition pointcutDefinition = null; try { this.parseState.push(new PointcutEntry(id)); pointcutDefinition = createPointcutDefinition(expression); pointcutDefinition.setSource(parserContext.extractSource(pointcutElement)); String pointcutBeanName = id; if (StringUtils.hasText(pointcutBeanName)) { parserContext.getRegistry().registerBeanDefinition(pointcutBeanName, pointcutDefinition); } else { pointcutBeanName = parserContext.getReaderContext().registerWithGeneratedName(pointcutDefinition); } parserContext.registerComponent( new PointcutComponentDefinition(pointcutBeanName, pointcutDefinition, expression)); } finally { this.parseState.pop(); } return pointcutDefinition; }
//ConfigBeanDefinitionParser类的方法
//创建AspectJExpressionPointcut类的RootBeanDefinition
protected
AbstractBeanDefinition createPointcutDefinition(String expression) { RootBeanDefinition beanDefinition = new RootBeanDefinition(AspectJExpressionPointcut.class); beanDefinition.setScope(BeanDefinition.SCOPE_PROTOTYPE); beanDefinition.setSynthetic(true); beanDefinition.getPropertyValues().add(EXPRESSION, expression); return beanDefinition; }  

总结

  到这里我们已经结束初始化的分析了,在下一篇再看依赖注册时的特殊处理,有两个地方可以注意下

  • 注册了一个AspectComponentDefinition的复杂组件定义
  • 最后在注册AspectJExpressionPointcut的定义时,我们发现是原型的,并不是单例的

参考链接

  • https://wenku.baidu.com/view/6ce3121da300a6c30c229f89.html(核心关注点与横切关注点)
  • https://www.cnblogs.com/syf/archive/2012/05/09/2491780.html(OOP与AOP)
  • https://blog.csdn.net/garfielder007/article/details/78057107(连接点用地概念)
  • https://docs.spring.io/spring/docs/4.3.18.RELEASE/spring-framework-reference(spring官方文档)
  • http://www.cnblogs.com/xrq730/p/6753160.html((源码分析的参考文章)
  • https://blog.csdn.net/elim168/article/details/78166296(@DeclareParents使用)

 

转载于:https://www.cnblogs.com/lucas2/p/9309539.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
基于LSTM的财务因子预测选股模型LSTM (Long Short-Term Memory) 是一种特殊的循环神经网络(RNN)架构,用于处理具有长期依赖关系的序列数据。传统的RNN在处理长序列时往往会遇到梯度消失或梯度爆炸的问题,导致无法有效地捕捉长期依赖。LSTM通过引入门控机制(Gating Mechanism)和记忆单元(Memory Cell)来克服这些问题。 以下是LSTM的基本结构和主要组件: 记忆单元(Memory Cell):记忆单元是LSTM的核心,用于存储长期信息。它像一个传送带一样,在整个链上运行,只有一些小的线性交互。信息很容易地在其上保持不变。 输入门(Input Gate):输入门决定了哪些新的信息会被加入到记忆单元中。它由当前时刻的输入和上一时刻的隐藏状态共同决定。 遗忘门(Forget Gate):遗忘门决定了哪些信息会从记忆单元中被丢弃或遗忘。它也由当前时刻的输入和上一时刻的隐藏状态共同决定。 输出门(Output Gate):输出门决定了哪些信息会从记忆单元中输出到当前时刻的隐藏状态中。同样地,它也由当前时刻的输入和上一时刻的隐藏状态共同决定。 LSTM的计算过程可以大致描述为: 通过遗忘门决定从记忆单元中丢弃哪些信息。 通过输入门决定哪些新的信息会被加入到记忆单元中。 更新记忆单元的状态。 通过输出门决定哪些信息会从记忆单元中输出到当前时刻的隐藏状态中。 由于LSTM能够有效地处理长期依赖关系,它在许多序列建模任务中都取得了很好的效果,如语音识别、文本生成、机器翻译、时序预测等。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值