`
yinchunjian
  • 浏览: 283155 次
  • 性别: Icon_minigender_1
  • 来自: 苏州
社区版块
存档分类
最新评论

Asptctj是什么

    博客分类:
  • java
阅读更多

What is AspectJ <script></script>

网上出现了很多讲解AspectJ的资料,但大多是从讲解AspectJ语法开始,本文从另一个角度讲解AspectJ,作者着重介绍了AspectJ的设计思路和运行原理。

1. 序
Aspect Oriented Programming (AOP)是近来一个比较热门的话题。

AspectJ是AOP的Java语言的实现,获得了Java程序员的广泛关注。

关于AspectJ和AOP的具体资料,请从下列链接中查找:

http://www.eclipse.org/aspectj/
http://www.parc.com/research/csl/projects/aspectj/
http://aosd.net/

网上出现了很多讲解AspectJ的资料,但大多是从讲解AspectJ语法开始,然后讲解如何应用AspectJ,如何分离软件开发过程的不同方面(Aspect)--Log,Session,Authentication and Authorization,Transaction,等等。

初次接触AspectJ的读者看到这些资料(或者语法手册),会感到AspectJ有些神秘。他们想知道,AspectJ是如何做到这些的?AspectJ是怎样工作的?AspectJ需要特殊的运行环境吗?

本文从另一个角度讲解AspectJ,本文从讲解AspectJ的设计思路、运行原理入手,回答上述问题。

本文讲解的主要内容,按照概念的重要程度,排列如下:

  1. AspectJ是一个代码生成工具(Code Generator)。
  2. AspectJ语法就是用来定义代码生成规则的语法。您如果使用过Java Compiler Compiler (JavaCC),您会发现,两者的代码生成规则的理念惊人相似。
  3. AspectJ有自己的语法编译工具,编译的结果是Java Class文件,运行的时候,classpath需要包含AspectJ的一个jar文件(Runtime lib)。
  4. AspectJ和xDoclet的比较。AspectJ和EJB Descriptor的比较。

本文的原则是,只细讲其他资料没有讲到的东西,其他资料讲过的东西,不讲或略讲。以节省网络资源,更为了节省大家,宝贵的时间。J

2.Aspect Oriented Programming (AOP)
本节简单介绍AOP的概念,解释我们为什么需要AOP。

AOP是Object Oriented Programming(OOP)的补充。

OOP能够很好地解决对象的数据和封装的问题,却不能很好的解决Aspect("方面")分离的问题。下面举例具体说明。

比如,我们有一个Bank(银行)类。Bank有两个方法,deposit(存钱)和withdraw(取钱)。

类和方法的定义如下:

 

														
Code 2.1 Bank.java
class Bank{
public float deposit(AccountInfo account, float money){
  // 增加account账户的钱数,返回账户里当前的钱数
}

public float withdraw(AccountInfo account, float money){
  // 减少account账户的钱数,返回取出的钱数
}
};

												

这两个方法涉及到用户的账户资金等重要信息,必须要非常小心,所以编写完上面的商业逻辑之后,项目负责人又提出了新的要求--给Bank类的每个重要方法加上安全认证特性。

于是,我们不得不分别在上面的两个方法中加入安全认证的代码。

类和方法的定义如下:(新增加的代码用不同的背景标出)

 

														
Code 2.2 Bank.java
class Bank{
public float deposit(AccountInfo account, float money){
  // 验证account是否为合法用户
  // 增加account账户的钱数,返回账户里当前的钱数
}

public float withdraw(AccountInfo account, float money){
  // 验证account是否为合法用户
  // 减少account账户的钱数,返回取出的钱数
}
};

												

这两个方法都需要操作数据库,为了保持数据完整性,项目负责人又提出了新的要求--给Bank类的每个操作数据库的方法加上事务控制。

于是,我们不得不分别在上面的两个方法中加入安全认证的代码。

类和方法的定义如下:(新增加的代码用不同的背景标出)

 

														
Code 2.3 Bank.java
class Bank{
public float deposit(AccountInfo account, float money){
  // 验证account是否为合法用户
  // Begin Transaction
  // 增加account账户的钱数,返回账户里当前的钱数
  // End Transaction
}

public float withdraw(AccountInfo account, float money){
  // 验证account是否为合法用户
  // Begin Transaction
  // 减少account账户的钱数,返回取出的钱数
  // End Transaction
}
};

												

我们看到,这些与商业逻辑无关的重复代码遍布在整个程序中。实际的工程项目中涉及到的类和函数,远远不止两个。如何解决这种问题?

我们首先来看看OOP能否解决这个问题。

我们利用Design Pattern的Template Pattern,可以抽出一个框架,改变上面的例子的整个设计结构。

类和方法的定义如下:

 

														
Code 2.4 Base.java
abstract class Base{
public float importantMethod(AccountInfo account, float money){
  // 验证account是否为合法用户
  // Begin Transaction
  
  float result = yourBusiness(account, money)

  // End Transaction
  return result;	
}

protected abstract float yourBusiness(AccountInfo account, float money);
};

Code 2.5 BankDeposit.java
class BankDeposit extends Base{ 
protected float yourBusiness(AccountInfo account, float money){
  // 增加account账户的钱数,返回账户里当前的钱数
}
};

Code 2.6 BankWithdraw.java
class BankWithdraw extends Base{ 
protected float yourBusiness(AccountInfo account, float money){
  // 减少account账户的钱数,返回取出的钱数
}
};

												

这里我们用一种很勉强的方法实现了认证和事务代码的重用。而且,有心的读者可能会注意到,这种方法的前提是,强制所有的方法都遵守同样的signature。

如果有一个转账方法transfer(AccountInfo giver, AccountInfo receiver, float money),由于transfer方法的signature不同于yourBusiness的signature,这个方法无法使用上面的框架。

这个例子中提到的认证,事务等方面,就是AOP所关心的Aspect。

AOP就是为了解决这种问题而出现的。AOP的目的就是--Separation of Aspects (or Separation of Concerns).

下面的章节,解释EJB Descriptor,AspectJ,xDoclet等工具如何解决Separation of Aspects的问题。

3.EJB Descriptor
如果我们使用EJB实现上面的例子,Bank类可以作为一个Stateless Session Bean实现。

在Bank的代码中只用考虑商业逻辑,不用考虑认证和事务等方面。

认证和事务等方面在EJB Descriptor中定义,由EJB Container提供这些方面的实现。

我们来看一下,如何使用EJB Descriptor描述上面的例子。

EJB Descriptor包括一个ejb-jar.xml文件。ejb-jar.xml文件包含两大部分,enterprise-beans和 assembly-descriptor部分。enterprise-beans部分包含EJB的定义--JNDI Name,EJB Home, Interface, Bean Class Path等;assembly-descriptor部分包括配置信息的定义--安全角色,事务控制等等。

下面给出上面例子对应的模拟EJB Descriptor。

 

														
<ejb-jar>
<enterprise-beans>
  <session>
     <ejb-name>Bank</ejb-name>
     …
     <ejb-class>example.Bank</ejb-class>
     <session-type>Stateless</session-type>
     <transaction-type>Container</transaction-type>
<security-role-ref>
<role-name>bank-account</role-name>
</security-role-ref>
  </session>
</enterprise-beans>

<assembly-descriptor>
  <security-role>
    <role-name>bank-account</role-name>
  </security-role>

<method-permission>
<role-name>employee</role-name>
<method>
<ejb-name>Bank</ejb-name>
<method-name>deposit</method-name>
</method>
<method>
<ejb-name>Bank</ejb-name>
<method-name>withdraw</method-name>
</method>
</method-permission>

<container-transaction>
<method>
<ejb-name>Bank</ejb-name>
<method-name>deposit</method-name>
</method>
<method>
<ejb-name>Bank</ejb-name>
<method-name>withdraw</method-name>
</method>

<trans-attribute>Required</trans-attribute>
</container-transaction>
</assembly-descriptor>
</ejb-jar>

												

本文后面会讲到如何用AspectJ实现上例中的Separation of Aspects。

读者可以比较一下AspectJ语法和EJB Descriptor定义之间的对应关系。

两者都提供了类名、方法名的匹配规则,能够把类的方法映射到认证,事务等Aspect(方面)。

4.AspectJ
这一节我们来看看AspectJ如何实现上例中的Separation of Aspects。

使用AspectJ,我们不用对原有的代码做任何修改,就可以为代码提供不同的Aspect(方面)--比如,认证,事务等。

我们只需要提供两个不同的Aspect--认证Aspect和事务Aspect。

 

														
Code 4.1 AuthAspect.java
aspect AuthAspect{
  pointcut bankMethods() : execution (* Bank.deposit(…)) || execution (* Bank. withdraw (…));

  Object around(): bankMethods(){
  // 验证account是否为合法用户

  return proceed();
  }
};

Code 4.2 TransactionAspect.java
aspect TransactionAspect{
  pointcut bankMethods() : execution(* Bank.deposit(…)) || execution (* Bank. withdraw (…));

  Object around(): bankMethods(){
  // Begin Transaction
  Object result = proceed();
  // End Transaction
  return result;
  }
};

												

如果您暂时不能理解这段代码,没有关系,后面会讲到,这些aspect的定义,不过是定义了一些代码生成规则。

我们用AspectJ编译器编译Bank文件和含有aspect的这个文件,出来的结果就是带有安全认证和事务处理的Bank类。编译出来的这个 Bank类调用了AspectJ Runtime Lib,所以,如果你要运行这个Bank类,你需要把AspectJ Runtime Lib设置在你的classpath里面。

我们来看看,AspectJ编译器为我们做了什么事情。

  1. 首先,AspectJ从文件列表里取出所有的文件名,然后读取这些文件,进行分析。
  2. AspectJ发现一些文件含有aspect的定义,在这个例子里,就是AuthAspect和TransactionAspect的定义;这些aspect就是代码生成规则。
  3. AspectJ根据这些aspect代码生成规则,修改添加你的源代码。在这个例子里,就是修改添加Bank文件。
  4. AspectJ读取AuthAspect的定义,发现了一个pointcut--bankMethods();这个pointcut的定义是execution(* Bank.deposit(…)) || execution(* Bank. withdraw (…)),表示所有对Bank类的deposit和withdraw方法的执行点。
  5. AspectJ继续读取AuthAspect的定义,发现了一个around(),这在AspectJ中叫做Advice,我不明白为什么叫这个名字,不过没关系,我们只要知道它是干什么的就行了。Advice允许你在某个类的方法的调用之前或调用之后,加入另外的代码。Code 4.1所示代码中的around()的" // 验证account是否为合法用户"部分,就是要加入的代码。这段代码要加在哪里呢?around()后面跟了一个pointcut-- bankMethods()。根据这个pointcut,AspectJ会把这段代码加入到Bank.deposit和Bank.withdraw两个方法的执行之前。达到的效果就如同Code 2.2所示。
  6. AspectJ读取TransactionAspect的定义,象第(4)步一样,发现了发现了一个pointcut--bankMethods()。
  7. AspectJ继续读取AuthAspect的定义,发现了一个around()。这次AspectJ把"Begin Transaction"和"End Transaction"两段代码加在Bank.deposit和Bank. withdraw两个方法的执行前后。达到的效果就如同Code 2.3所示。

如何验证这一点?您可以到http://www.eclipse.org/aspectj/下载安装AspectJ,编译里面的Sample,把编译结果反编译一下,就可以看到AspetJ自动生成的代码。

我们看到,AspectJ是一种代码自动生成工具。你编写一段通用的代码,比如认证方面的代码,事务方面的代码,然后根据AspectJ语法定义一套代码生成规则(aspect定义),AspectJ就会帮助你自动把这段通用代码分布到对应的代码里面去,简单快捷,算无遗策。

无独有偶,一个著名的编译器生成工具--Java Compiler Compiler (JavaCC),也采用了非常相似的代码生成机制。JavaCC允许你在语法定义规则文件中,加入你自己的Java代码,用来处理读入的各种语法元素。

AspectJ令你的代码更精简,结构更良好。AspectJ的好处,我就不多说了,网上很多精彩的文章探讨AspectJ的各种用途。

下面介绍一个著名的代码自动生成器--xDoclet,和EJB Descriptor,AspectJ之间的联系和比较。

5.xDoclet
我们知道,Doclet用来生成Javadoc,xDoclet是Doclet的扩展,不仅仅能生成Javadoc,还能够生成源代码和配置信息等。

Doclet和xDoclet的工作原理,就是处理源代码中的注释中的tag,生成相应的信息。这些tag都以@开头,你可以自己定义tag和对tag的处理,生成自定义的信息。

(这里提一下Apache Maven Project。Maven是一种Project Build工具。用Maven进行管理的项目,能够同时生成Javadoc和XRef。XRef是Source Code Cross Reference。)

JBoss就利用xDoclet为EJB自动生成EJB Home和EJB Object Interface源文件,和EJB Descriptor文件。

在Sourceforge.net上看到一个叫做Barter的开源项目,利用xDoclet为类方法生成AspectJ代码。

请注意,EJB Descriptor和AspectJ都是把方方面面的Aspects集中在一处进行管理,而xDoclet的思想是处理散布在源代码中的各种tag。

xDoclet在生成EJB Descriptor和AspectJ等方面的应用,正应了中国的一句古话--分久必合,合久必分。

6.总结
开源项目的出现,打破了软件技术领域的众多壁垒,推动软件技术进程的日新月异。

同时,一些新名词,新概念也层出不穷,令人眼花缭乱,无所适从。其实,很多东西都是换汤不换药,我们理解应用这些新技术的时候,要抓住本质,要破除迷信,破除任何人为的神秘感。

举个例子,现在炒作的很热的一些概念,"Web Service",还有"Grid Computation"(网格计算),都是基于原有的各种技术发展出来的。媒体和技术文章不应该人为地制造任何神秘感。

互联网时代的权威,不是说出来的,而是做出来的。

另外,围绕着一些有前途的新技术,总会出现大量的"快速入门手册",有些简直就是对该技术帮助文档的翻译,而且,有难度的地方没有翻译出来,大家都明白的地方翻译得非常详尽,详尽到了没有必要的地步。这种因为市场需求而产生的应景时文,大量地出现在技术文章领域。

笔者对本文的期望是,决不迷信,决不重复。并试图引入一种洁净的,毫无废话的文风。笔者期待一针见血的驳斥和批评。

分享到:
评论

相关推荐

    stm32网络远程固件升级keil5工程

    STM32 开发板:选择合适的 STM32 系列开发板,如 STM32F407、STM32F767 等,需具备足够的存储容量(用于存放固件)、网络接口(如以太网接口或可外接 WiFi 模块等实现网络连接)。 网络模块(可选): 如果开发板本身没有集成网络接口,需要外接网络模块。例如,可选用 ESP8266、ESP32 等 WiFi 模块通过 SPI、USART 等接口与 STM32 开发板连接,实现无线连接到网络。 若开发板有以太网接口,如 STM32F407 开发板带有以太网 MAC 控制器,还需外接以太网 PHY 芯片(如 DP83848 等)及相应的网络变压器等元件来实现完整的以太网功能。

    1-全国各省份、各地级市、各区县逐年平均降水数据(1950-2022年)-社科数据.zip

    全国各省份、各地级市、各区县逐年平均降水数据集提供了从1950年至2022年的详细降水记录。这些数据覆盖了广泛的地理区域,包括不同的气候带和地形,为研究中国各地区的降水模式提供了宝贵资料。该数据集包含了省级、城市级和区县级的降水量,以年为单位,记录了日降水总量的年平均值,单位为米(m)。这些数据对于理解各地区的水资源状况、农业灌溉需求、防洪措施的制定等方面至关重要,并且对地理研究和经济管理研究具有重要的参考价值。数据集包含了省份、城市、区县以及每年的降水量等指标,以面板数据格式呈现,方便进行多维度分析。

    [net毕业设计]ASP.NET网上鲜花销售系统的设计(源代码+论文).zip

    【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、python、web、C#、EDA、proteus、RTOS等项目的源码。【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。

    2020年中国行政村级区划代码及经纬度 - 权威数据

    中国行政村级区划的经纬度数据,更是精准地描绘了每一个村落的地理位置。从北国的雪域高原到南疆的热带雨林,从东部的浩瀚大海到西部的广袤戈壁,每一个村落都以其独特的经纬度坐标,镶嵌在祖国的版图上。 指标 市级、市级代码、县级、县级代码、乡镇级、乡镇级代码、村级、村级代码、城乡分类代码、address、lng_84、lat_84。

    1-全国各省地区犯罪率统计数据1988-2020年-社科数据.zip

    全国各省地区犯罪率统计数据集提供了1988年至2020年的详细犯罪率数据,覆盖全国31个省份。这些数据通过刑事案件发生率来衡量社会犯罪率,为研究者提供了一个重要的社会犯罪变量测度。该数据集不仅记录了各省份每年的犯罪率,还包含了从1988年到2020年连续多年的统计数据,为分析犯罪趋势和模式提供了丰富的信息。此外,这些数据被广泛用于研究收入不平等与刑事犯罪之间的关系,以及其他社会经济因素对犯罪率的影响。通过这些数据,研究者可以深入探讨犯罪率与社会经济发展之间的联系,为制定相关政策提供科学依据。

    统计学课程设计报告说明.doc

    统计学课程设计报告说明.doc

    shell脚本编程实践,分享给有需要的人,仅供参考

    模拟退火算法shell脚本编程实践,分享给有需要的人,仅供参考。内容来源于网络分享,如有侵权请联系我删除。另外如果没有积分的同学需要下载,请私信我。

    [net毕业设计]ASP.NET电子购物商城系统(源代码+论文).zip

    【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、python、web、C#、EDA、proteus、RTOS等项目的源码。【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。

    1-全国高校专利申请量与授权量统计数据1985-2020年-社科数据.zip

    全国高校专利申请量与授权量统计数据集提供了1985年至2020年间中国高校在专利领域的详细统计信息。这些数据不仅记录了高校专利申请和授权的数量,还涵盖了专利的类型,包括发明专利、实用新型专利和外观设计专利。该数据集是衡量高校科技创新成效的重要指标,反映了高校科研成果转化的机制完善程度和科研人员转化积极性。数据内容丰富,包括高校名称、年度、独立及联合申请的各类专利数量,以及授权的专利数量等关键指标。这些统计数据有助于分析和评估高校的创新能力和科技成果转化效率,对于研究高校科技创新政策、管理决策以及发展趋势具有重要价值。

    spark中文文档,spark操作手册以及使用规范

    spark中文文档,spark操作手册以及使用规范

    yolo算法-车辆行人数据集-127张图像带标签-汽车-人.zip

    yolo系列算法目标检测数据集,包含标签,可以直接训练模型和验证测试,数据集已经划分好,包含数据集配置文件data.yaml,适用yolov5,yolov8,yolov9,yolov7,yolov10,yolo11算法; 包含两种标签格:yolo格式(txt文件)和voc格式(xml文件),分别保存在两个文件夹中; yolo格式:<class> <x_center> <y_center> <width> <height>, 其中: <class> 是目标的类别索引(从0开始)。 <x_center> 和 <y_center> 是目标框中心点的x和y坐标,这些坐标是相对于图像宽度和高度的比例值,范围在0到1之间。 <width> 和 <height> 是目标框的宽度和高度,也是相对于图像宽度和高度的比例值

    员工培训授训积分标准表.docx

    员工培训授训积分标准表.docx

    神经网络项目介绍.docx

    神经网络项目介绍

    [net毕业设计]ASP.NET学生信息管理系统(源代码+论文).zip

    【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、python、web、C#、EDA、proteus、RTOS等项目的源码。【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。

    ASP物流管理系统设计(源代码+论文)(源代码+论文+说明文档).zip

    【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、python、web、C#、EDA、proteus、RTOS等项目的源码。【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。

    毕业设计心得.txtdfhfn

    毕业设计心得.txtdfhfn

    ASP+ACCESS人事管理系统设计(源代码+论文)(源代码+论文+说明文档).zip

    【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、python、web、C#、EDA、proteus、RTOS等项目的源码。【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。

    1-全国各地区(省)人口相关统计面板数据1990-2021年-社科数据.zip

    全国各地区(省)人口相关统计面板数据集覆盖了1990至2021年的时间跨度,提供了全国31个省的详细人口统计信息。该数据集包含了常住人口数、年末常住人口、各年龄段人口数、受教育人口数、出生人口数、人口自然增长率、死亡率以及人口性别比例等多项指标。数据内容涉及0-14岁、15-64岁、65岁及以上的人口分布,以及6岁及以上按性别和教育程度划分的人口结构。此外,还包括了15岁及以上未婚人口数、市县总人口数、家庭户和集体户人口数等细分数据。这些数据不仅涵盖了人口的自然增长和减少情况,还包括了人口性别比、农业人口与非农业人口数、城镇与乡村人口比重等重要社会经济指标。通过这些数据,研究人员可以深入分析中国各地区的人口变化趋势,为政策制定和社会科学研究提供有力支持。

    降成本工作流程说明表.docx

    降成本工作流程说明表.docx

    13.html

    13

Global site tag (gtag.js) - Google Analytics