1.15 附加功能ApplicationContext

正如章节介绍中所讨论的,该org.springframework.beans.factory 包提供了管理和操作bean的基本功能,包括以编程方式。除了扩展其他接口以外 ,该org.springframework.context软件包还添加了 ApplicationContext扩展BeanFactory接口的接口,以更加面向应用程序框架的方式提供附加功能。许多人ApplicationContext以完全声明的方式使用它,甚至不以编程方式创建它,而是依赖于支持类,例如ContextLoader自动实例化 ApplicationContext作为Java EE Web应用程序的正常启动过程的一部分。

为了BeanFactory以更加面向框架的样式增强功能,上下文包还提供以下功能:

  • 通过MessageSource界面访问i18n风格的消息。

  • 通过ResourceLoader界面访问URL和文件等资源。

  • 事件发布,即ApplicationListener通过使用接口实现接口的bean ApplicationEventPublisher。

加载多个(分层)上下文,让每个上下文通过HierarchicalBeanFactory界面聚焦于一个特定层,例如应用程序的Web层 。

1.15.1 国际化使用MessageSource

该ApplicationContext接口扩展了一个名为的接口MessageSource,因此提供了国际化(“i18n”)功能。Spring还提供了 HierarchicalMessageSource接口,可以分层次地解析消息。这些接口共同提供了Spring影响消息解析的基础。这些接口上定义的方法包括:

  • String getMessage(String code, Object[] args, String default, Locale loc):用于从中检索消息的基本方法MessageSource。如果未找到指定区域设置的消息,则使用默认消息。传入的任何参数都使用MessageFormat标准库提供的功能成为替换值。

  • String getMessage(String code, Object[] args, Locale loc):基本上与前一个方法相同,但有一点不同:无法指定默认消息。如果找不到该消息,NoSuchMessageException则抛出a。

  • String getMessage(MessageSourceResolvable resolvable, Locale locale):前面方法中使用的所有属性也包装在一个名为的类中 MessageSourceResolvable,您可以使用此方法。

当ApplicationContext被加载时,它自动搜索MessageSource 在上下文中定义的bean。bean必须具有名称messageSource。如果找到这样的bean,则对前面方法的所有调用都被委托给消息源。如果未找到任何消息源,则ApplicationContext尝试查找包含具有相同名称的bean的父级。如果是,它将使用该bean作为MessageSource。如果 ApplicationContext找不到任何消息源,DelegatingMessageSource则实例化为空 以便能够接受对上面定义的方法的调用。

春天提供了两种MessageSource实现方式,ResourceBundleMessageSource和 StaticMessageSource。两者都是HierarchicalMessageSource为了进行嵌套消息传递而实现的。在StaticMessageSource很少使用,但提供了编程的方式向消息源添加消息。以下示例显示ResourceBundleMessageSource:

<beans><bean id="messageSource"class="org.springframework.context.support.ResourceBundleMessageSource"><property name="basenames"><list><value>format</value><value>exceptions</value><value>windows</value></list></property></bean>
</beans>

该示例假定您有三个资源包被调用format,exceptions并windows 在类路径中定义。解决消息的任何请求都以JDK标准的方式处理,通过ResourceBundle对象解析消息。出于示例的目的,假设上述两个资源包文件的内容如下:

# in format.properties
message=Alligators rock!
# in exceptions.properties
argument.required=The {0} argument is required.

下一个示例显示了执行该MessageSource功能的程序。请记住,所有ApplicationContext实现都是MessageSource 实现,因此可以强制转换为MessageSource接口。

public static void main(String[] args) {MessageSource resources = new ClassPathXmlApplicationContext("beans.xml");String message = resources.getMessage("message", null, "Default", null);System.out.println(message);
}

上述程序产生的结果如下:

Alligators rock!

总而言之,它MessageSource是在一个名为的文件中定义的,该文件beans.xml存在于类路径的根目录中。该messageSourcebean定义是指通过它的一些资源包的basenames属性。这是在列表中传递的三个文件basenames属性存在于你的classpath根目录的文件,被称为format.properties,exceptions.properties和 windows.properties分别。

下一个示例显示传递给消息查找的参数。这些参数将转换为String对象并插入到查找消息中的占位符中。

<beans><!-- this MessageSource is being used in a web application --><bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource"><property name="basename" value="exceptions"/></bean><!-- lets inject the above MessageSource into this POJO --><bean id="example" class="com.something.Example"><property name="messages" ref="messageSource"/></bean>
</beans>
public class Example {private MessageSource messages;public void setMessages(MessageSource messages) {this.messages = messages;}public void execute() {String message = this.messages.getMessage("argument.required",new Object [] {"userDao"}, "Required", null);System.out.println(message);}
}

调用execute()方法得到的结果如下:

The userDao argument is required.

关于国际化(“i18n”),Spring的各种MessageSource 实现遵循与标准JDK相同的区域设置解析和回退规则 ResourceBundle。总之,和继续该示例messageSource先前定义的,如果你想解析British(消息en-GB)语言环境中,您将创建文件名为format_en_GB.properties,exceptions_en_GB.properties和 windows_en_GB.properties分别。

通常,区域设置解析由应用程序的周围环境管理。在以下示例中,手动指定解析(英国)消息的区域设置:

# in exceptions_en_GB.properties
argument.required=Ebagum lad, the {0} argument is required, I say, required.
public static void main(final String[] args) {MessageSource resources = new ClassPathXmlApplicationContext("beans.xml");String message = resources.getMessage("argument.required",new Object [] {"userDao"}, "Required", Locale.UK);System.out.println(message);
}

运行上述程序产生的结果如下:

Ebagum lad, the 'userDao' argument is required, I say, required.

您还可以使用该MessageSourceAware接口获取对MessageSource已定义的任何引用的引用 。在创建和配置bean时,将使用应用程序上下文注入ApplicationContext实现MessageSourceAware接口的任何bean MessageSource。

作为替代ResourceBundleMessageSource,Spring提供了一个 ReloadableResourceBundleMessageSource类。此变体支持相同的包文件格式,但比基于标准JDK的ResourceBundleMessageSource实现更灵活 。特别是,它允许从任何Spring资源位置(不仅从类路径)读取文件,并支持bundle属性文件的热重新加载(同时在其间有效地缓存它们)。有关ReloadableResourceBundleMessageSource 详细信息,请参阅javadoc。

1.15.2 标准和自定义事件

ApplicationContext通过ApplicationEvent 类和ApplicationListener接口提供事件处理。如果将实现ApplicationListener接口的bean 部署到上下文中,则每次 ApplicationEvent将其发布到该ApplicationContextbean时,都会通知该bean。从本质上讲,这是标准的Observer设计模式。

从Spring 4.2开始,事件基础结构得到了显着改进,并提供了基于注释的模型以及发布任意事件(即不一定从中扩展的对象ApplicationEvent)的能力。当发布这样的对象时,我们将它包装在一个事件中。

下表描述了Spring提供的标准事件:

表7.内置事件

事件 说明
ContextRefreshedEvent ApplicationContext初始化或刷新时发布(例如,通过refresh()在ConfigurableApplicationContext接口上使用该方法)。这里,“初始化”意味着加载所有bean,检测并激活后处理器bean,预先实例化单例,并且ApplicationContext对象已准备好使用。只要上下文尚未关闭,只要所选择的ApplicationContext实际支持这种“热”刷新,就可以多次触发刷新。例如,XmlWebApplicationContext支持热刷新,但GenericApplicationContext不支持 。
ContextStartedEvent ApplicationContext通过start()在ConfigurableApplicationContext接口上使用方法 启动时发布。这里,“已启动”意味着所有Lifecycle bean都会收到明确的启动信号。通常,此信号用于在显式停止后重新启动Bean,但它也可用于启动尚未为自动启动配置的组件(例如,在初始化时尚未启动的组件)。
ContextStoppedEvent ApplicationContext通过stop()在ConfigurableApplicationContext接口上使用方法 停止时发布。这里,“停止”意味着所有Lifecycle bean都会收到明确的停止信号。可以通过start()呼叫重新启动已停止的上下文
ContextClosedEvent ApplicationContext通过close()在ConfigurableApplicationContext接口上使用方法 关闭时发布。这里,“关闭”意味着所有单例bean都被销毁。封闭的环境达到其寿命终结。它无法刷新或重新启动。
RequestHandledEvent 一个特定于Web的事件,告诉所有bean已经为HTTP请求提供服务。请求完成后发布此事件。此事件仅适用于使用Spring的Web应用程序DispatcherServlet。

您还可以创建和发布自己的自定义事件。以下示例显示了一个扩展Spring的ApplicationEvent基类的简单类:

public class BlackListEvent extends ApplicationEvent {private final String address;private final String content;public BlackListEvent(Object source, String address, String content) {super(source);this.address = address;this.content = content;}// accessor and other methods...
}

要发布自定义ApplicationEvent,请在publishEvent()方法上调用该方法 ApplicationEventPublisher。通常,这是通过创建一个实现ApplicationEventPublisherAware并将其注册为Spring bean 的类来完成的 。以下示例显示了这样一个类:

public class EmailService implements ApplicationEventPublisherAware {private List<String> blackList;private ApplicationEventPublisher publisher;public void setBlackList(List<String> blackList) {this.blackList = blackList;}public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {this.publisher = publisher;}public void sendEmail(String address, String content) {if (blackList.contains(address)) {publisher.publishEvent(new BlackListEvent(this, address, content));return;}// send email...}
}

在配置时,Spring容器检测到EmailService实现 ApplicationEventPublisherAware并自动调用 setApplicationEventPublisher()。实际上,传入的参数是Spring容器本身。您正通过其ApplicationEventPublisher界面与应用程序上下文进行 交互。

要接收自定义ApplicationEvent,您可以创建一个实现 ApplicationListener并将其注册为Spring bean的类。以下示例显示了这样一个类:

public class BlackListNotifier implements ApplicationListener<BlackListEvent> {private String notificationAddress;public void setNotificationAddress(String notificationAddress) {this.notificationAddress = notificationAddress;}public void onApplicationEvent(BlackListEvent event) {// notify appropriate parties via notificationAddress...}
}

请注意,ApplicationListener通常使用自定义事件的类型进行参数化(BlackListEvent在前面的示例中)。这意味着该onApplicationEvent()方法可以保持类型安全,避免任何向下转换的需要。您可以根据需要注册任意数量的事件侦听器,但请注意,默认情况下,事件侦听器会同步接收事件。这意味着该publishEvent()方法将阻塞,直到所有侦听器都已完成对事件的处理。这种同步和单线程方法的一个优点是,当侦听器接收到事件时,如果事务上下文可用,它将在发布者的事务上下文内运行。如果需要另一个事件发布策略,请参阅Spring的ApplicationEventMulticaster界面的javadoc 。

以下示例显示了用于注册和配置上述每个类的bean定义:

<bean id="emailService" class="example.EmailService"><property name="blackList"><list><value>known.spammer@example.org</value><value>known.hacker@example.org</value><value>john.doe@example.org</value></list></property>
</bean><bean id="blackListNotifier" class="example.BlackListNotifier"><property name="notificationAddress" value="blacklist@example.org"/>
</bean>

总而言之,当调用bean 的sendEmail()方法时emailService,如果有任何应列入黑名单的电子邮件消息,BlackListEvent则会发布类型的自定义事件 。该blackListNotifierbean被注册为 ApplicationListener与接收BlackListEvent,此时它可以通知有关各方。

Spring的事件机制是为在同一应用程序上下文中的Spring bean之间的简单通信而设计的。但是,对于更复杂的企业集成需求,单独维护的 Spring Integration项目为构建基于众所周知的Spring编程模型的轻量级,面向模式,事件驱动的体系结构提供了完整的支持 。

基于注释的事件监听器
从Spring 4.2开始,您可以使用EventListener注释在托管bean的任何公共方法上注册事件侦听器。该BlackListNotifier可改写如下:

public class BlackListNotifier {private String notificationAddress;public void setNotificationAddress(String notificationAddress) {this.notificationAddress = notificationAddress;}@EventListenerpublic void processBlackListEvent(BlackListEvent event) {// notify appropriate parties via notificationAddress...}
}

方法签名再次声明它侦听的事件类型,但这次使用灵活的名称并且没有实现特定的侦听器接口。只要实际事件类型在其实现层次结构中解析通用参数,也可以通过泛型缩小事件类型。

如果您的方法应该监听多个事件,或者您想要根据任何参数进行定义,那么也可以在注释本身上指定事件类型。以下示例显示了如何执行此操作:

@EventListener({ContextStartedEvent.class, ContextRefreshedEvent.class})
public void handleContextStart() {...
}

还可以通过使用condition定义SpEL表达式的注释的属性来添加额外的运行时过滤,该属性应该匹配以实际调用特定事件的方法。

以下示例显示了仅当content事件的属性等于时,如何重写我们的通知程序才能被调用my-event:

@EventListener(condition = "#blEvent.content == 'my-event'")
public void processBlackListEvent(BlackListEvent blEvent) {// notify appropriate parties via notificationAddress...
}

每个SpEL表达式都针对专用上下文进行评估。下表列出了可用于上下文的项目,以便您可以将它们用于条件事件处理:

表8.事件SpEL可用元数据

名称 地点 描述
Event root object 实际的ApplicationEvent #root.event
Arguments array root object 用于调用目标的参数(作为数组)。
Argument name evaluation #root.args[0] context 任何方法参数的名称。如果由于某种原因,名称不可用(例如,因为没有调试信息),参数名称也可以在#a<#arg> where #arg参数索引(从0开始)下找到。

请注意#root.event,即使您的方法签名实际引用已发布的任意对象,也可以访问基础事件。

如果您需要作为处理其他事件的结果发布事件,则可以更改方法签名以返回应发布的事件,如以下示例所示:

@EventListener
public ListUpdateEvent handleBlackListEvent(BlackListEvent event) {// notify appropriate parties via notificationAddress and// then publish a ListUpdateEvent...
}

asynchronous listeners 异步侦听器不支持这个

这个新方法ListUpdateEvent为BlackListEvent上述方法处理的每个方法发布一个新的方法。如果您需要发布多个事件,则可以返回一个Collection事件。

异步监听器
如果希望特定侦听器异步处理事件,则可以重用 常规@Async支持。以下示例显示了如何执行此操作:

@EventListener
@Async
public void processBlackListEvent(BlackListEvent event) {// BlackListEvent is processed in a separate thread
}

使用异步事件时请注意以下限制:

如果事件侦听器抛出一个Exception,则它不会传播给调用者。有关AsyncUncaughtExceptionHandler详细信息,请参阅。

此类事件监听器无法发送回复。如果您需要作为处理结果发送另一个事件,请注入ApplicationEventPublisher以手动发送事件。

Ordering Listeners

如果需要在另一个侦听器之前调用一个侦听器,则可以将@Order 注释添加到方法声明中,如以下示例所示:

@EventListener
@Order(42)
public void processBlackListEvent(BlackListEvent event) {// notify appropriate parties via notificationAddress...
}

Generic Events

您还可以使用泛型来进一步定义事件的结构。考虑使用 EntityCreatedEventwhere T是创建的实际实体的类型。例如,您可以创建以下侦听器定义只接收EntityCreatedEvent了 Person:

@EventListener
public void onPersonCreated(EntityCreatedEvent<Person> event) {...
}

由于类型擦除,这仅在被触发的事件解析事件侦听器过滤的泛型参数(即类似的东西class PersonCreatedEvent extends EntityCreatedEvent { …​ })时才有效 。

在某些情况下,如果所有事件都遵循相同的结构(这可能是前面示例中的事件的情况),则这可能变得相当繁琐。在这种情况下,您可以实现ResolvableTypeProvider指导框架超出运行时环境提供的范围。以下事件显示了如何执行此操作:

public class EntityCreatedEvent<T> extends ApplicationEvent implements ResolvableTypeProvider {public EntityCreatedEvent(T entity) {super(entity);}@Overridepublic ResolvableType getResolvableType() {return ResolvableType.forClassWithGenerics(getClass(), ResolvableType.forInstance(getSource()));}
}

这不仅适用于ApplicationEvent您作为事件发送的任何任意对象。

1.15.3 方便地访问低级资源

为了最佳地使用和理解应用程序上下文,您应该熟悉Spring的Resource抽象,如 参考资料中所述。

应用程序上下文是a ResourceLoader,可用于加载Resource对象。A Resource本质上是JDK java.net.URL类的功能更丰富的版本。实际上,在适当Resource的情况下包装一个实例的实现java.net.URL。A Resource可以透明的方式从几乎任何位置获取低级资源,包括从类路径,文件系统位置,任何可用标准URL描述的位置,以及一些其他变体。如果资源位置字符串是没有任何特殊前缀的简单路径,那么这些资源来自特定且适合于实际应用程序上下文类型。

您可以配置部署到应用程序上下文中的bean来实现特殊的回调接口,ResourceLoaderAware在初始化时自动回调,应用程序上下文本身作为传入 ResourceLoader。您还可以公开Resource要用于访问静态资源的类型属性。它们像任何其他属性一样被注入其中。您可以将这些Resource属性指定为简单String路径,并依赖特殊的JavaBean PropertyEditor(由上下文自动注册),以便Resource在部署Bean时将这些文本字符串转换为实际对象。

提供给ApplicationContext构造函数的位置路径实际上是资源字符串,并且以简单的形式根据特定的上下文实现进行适当处理。例如,ClassPathXmlApplicationContext将简单的位置路径视为类路径位置。您还可以使用具有特殊前缀的位置路径(资源字符串)来强制从类路径或URL加载定义,而不管实际的上下文类型如何。

1.15.4 方便的Web应用程序的ApplicationContext实例化

您可以ApplicationContext使用例如a以声明方式创建实例 ContextLoader。当然,您也可以ApplicationContext使用其中一个ApplicationContext实现以编程方式创建实例。

您可以ApplicationContext使用ContextLoaderListener,注册一个,如下例所示:

<context-param><param-name>contextConfigLocation</param-name><param-value>/WEB-INF/daoContext.xml /WEB-INF/applicationContext.xml</param-value>
</context-param><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

监听器检查contextConfigLocation参数。如果参数不存在,则侦听器将/WEB-INF/applicationContext.xml默认使用。当参数确实存在时,侦听器String使用预定义的分隔符(逗号,分号和空格)分隔,并将值用作搜索应用程序上下文的位置。还支持Ant样式的路径模式。示例是/WEB-INF/*Context.xml(对于名称Context.xml 以WEB-INF目录结尾并位于目录/WEB-INF/**/*Context.xml中的所有文件)和(对于任何子目录中的所有此类文件WEB-INF)。

1.15.5 将Spring部署ApplicationContext为Java EE RAR文件

可以将Spring部署ApplicationContext为RAR文件,将上下文及其所有必需的bean类和库JAR封装在Java EE RAR部署单元中。这相当于ApplicationContext能够访问Java EE服务器设施的独立引导(仅在Java EE环境中托管)。RAR部署是部署无头WAR文件的一种更自然的替代方案 - 实际上是一个没有任何HTTP入口点的WAR文件,仅用于ApplicationContext在Java EE环境中引导Spring 。

RAR部署非常适用于不需要HTTP入口点但仅包含消息端点和预定作业的应用程序上下文。在这样的上下文中的Bean可以使用应用程序服务器资源,例如JTA事务管理器和JNDI绑定的JDBC DataSource实例和JMS ConnectionFactory实例,并且还可以通过Spring的标准事务管理以及JNDI和JMX支持工具向平台的JMX服务器注册。应用程序组件还可以WorkManager通过Spring的TaskExecutor抽象与应用程序服务器的JCA交互。

有关SpringContextResourceAdapter RAR部署中涉及的配置详细信息,请参阅该类的javadoc 。

对于将Spring ApplicationContext简单部署为Java EE RAR文件:

将所有应用程序类打包到一个RAR文件(这是一个具有不同文件扩展名的标准JAR文件)。。将所有必需的库JAR添加到RAR存档的根目录中。。添加 META-INF/ra.xml部署描述符(如javadoc中SpringContextResourceAdapter所示)和相应的Spring XML bean定义文件(通常为“META-INF / applicationContext.xml”)。

将生成的RAR文件放入应用程序服务器的部署目录中。

这种RAR部署单元通常是独立的。它们不会将组件暴露给外部世界,甚至不会暴露给同一应用程序的其他模块。与基于RAR的交互ApplicationContext通常通过与其他模块共享的JMS目标进行。ApplicationContext例如,基于RAR的还可以调度一些作业或对文件系统(或类似物)中的新文件作出反应。如果它需要允许来自外部的同步访问,它可以(例如)导出RMI端点,这可以由同一台机器上的其他应用程序模块使用。

2.15 Spring Framework 5.x 之ApplicationContext附加功能相关推荐

  1. spring 5.x(1)-----Spring Framework 5.x中的新功能

    Spring Framework 5.x中有什么新功能 5.1版中的新功能 一般核心修订 基础设施: 在类路径和模块路径上对JDK 11的无警告支持. 支持Graal原生图像约束(反射,参数名称). ...

  2. Spring Framework 4.2 中的新功能和增强功能

    至今为止,Spring Framework 的最新版本为 4.2.1.RELEASE. 那么 Spring Framework 4.2 中的又有哪些新功能和增强功能呢? 核心容器改进 如 @bean ...

  3. Spring Framework 官方文档学习(四)之Validation、Data Binding、Type Conversion

    本篇太乱,请移步: Spring Framework 官方文档学习(四)之Validation.Data Binding.Type Conversion(一) 写了删删了写,反复几次,对自己的描述很不 ...

  4. Spring Framework 开发参考手册中文(在线HTML)

    '原文:http://blog.csdn.net/zfrong/article/details/3971722 Spring Framework 开发参考手册中文(在线HTML) Spring Fra ...

  5. 万字博客带你了解Spring Framework 的全貌

    1.写在前面 我之前出过一个系列介绍的是spring的源码的系列,但是由于当时个人的水平有限,有些地方介绍的也是模棱两可的,打算重启这块内容,上次只是介绍其中的一部分,例如国际化,事件等等这块的源码都 ...

  6. Spring Framework 5.0.0.M4中文文档第3章

    文章目录 Part II. 核心技术 3. IoC容器 3.2 容器概述 3.2.1 配置元数据 3.2.2 实例化容器 3.2.3 使用容器 3.3 Bean概述 3.3.1 命名bean 3.3. ...

  7. 【Spring】Spring Framework Reference Documentation中文版18

    Part VI. The Web This part of the reference documentation covers Spring Framework's support for the ...

  8. Spring Framework 6 将采用 Java 17,是时候将你的应用升级了

    关于从先前的长期支持版本(Java 11 和 Java 8)迁移代码,你需要知道的是什么? 整理 | 王晓曼 出品 | CSDN(ID:CSDNnews) Spring Framework 6 将采用 ...

  9. Spring Framework Reference Documentation手册官网下载地址

    之前在国内资源网站遇见很多Spring Framework Reference Documentation 开发手册下载的,居然都要资源点之类的,而且几乎都是英语(截止到2016/06/15,较新版本 ...

最新文章

  1. dedecms部分文章出现读取附加信息出错的解决办法
  2. 前端try catch是如何捕获异常的_一文告诉你如何优雅处理前端异常?
  3. Airbnb改进部署管道安全性,规范部署顺序
  4. Python代码加密,将python文件编译成so文件
  5. KDD 2020 开源论文 | 稀疏优化的块分解算法
  6. HG255D 刷机备忘
  7. 百度人脸识别Java版
  8. 天津奥的斯服务器显示PKS WT,天津奥的斯电梯故障代码大全
  9. 阿里云服务器怎么预防CC攻击?
  10. python关于模块说法错误的是_python常用模块错题
  11. Bzoj4598: [Sdoi2016]模式字符串 点分治 哈希
  12. 优达(Udacity)-机器学习基础-数据集与问题(安然数据集)
  13. 笨方法学Python—ex42:对象、类及从属关系
  14. 2020西瓜直播弹幕协议版弹幕提取思路与实现py
  15. Mac解决 zsh: command not found: ll
  16. 360校园招聘2015届技术类笔试题(一)
  17. 用C#识别图像中的文字_MODI OCR
  18. Hive学习—数据操作
  19. 2021,移动办公再次风起
  20. 怎么判断私网地址_如何判断一个IP地址是私有地址

热门文章

  1. OSChina 周六乱弹 ——请让我的灵魂最后一次燃烧
  2. c语言 单词首字母大写
  3. 马蜂窝陈罡:用户、内容、商业化3C矩阵,是新一代旅游市场密码
  4. 6,Matlab轨迹生成
  5. 单行函数和多表查询 例题代码可复制
  6. lisp实现框选裁切_《剪切成虚线》v3.1版(支持框选)
  7. 数据库高可用架构 - pxc
  8. elementUI表格动态渲染错乱
  9. Quartus 13.0和Modelsim SE 10.1a 联合仿真
  10. 向SQL Server 中导入长文本