Spring--之旅
spring的地位
如图可以看出,sping纵跨整个项目架构,它是一个容器框架。下面使用一个简单的项目来认识spring。
快速入门
step
1、新建一个普通Java工程,spring只是一种容器,所以支持Javase和javaee
2、引入spring的开发包(最小配置spring.jar 该包把常用的jar都包括, 还要 写日志包 common-logging.jar
3、新建一个叫UserService类
package com.ydc.service;
public class UserService {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void sayHello(){
System.out.println("hello "+name );
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21

- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
4、创建spring的一个核心文件 applicationContext.xml, [hibernate有核心 hibernate.cfg.xml struts核心文件 struts-config.xml], 该文件一般放在src目录下,该文件中引入 xsd文件 :
<?xml version="1.0" encoding="utf-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
</beans>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11

- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
5、配置bean
<?xml version="1.0" encoding="utf-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
<bean id="userService" class="com.ydc.service.UserService">
<property name="name">
<value>杨德成</value>
</property>
</bean>
</beans>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16

- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
配置说明:
a、bean元素的作用是,当我们的spring框架加载时候,spring就会自动的创建一个bean对象,。
<bean id="userService" class="com.ydc.service.UserService">
- 1

- 1
执行这段代码会创建一个以下对象
UserService userSerivce=new UserService();
- 1

- 1
b、注入属性
<property name="name">
<value>杨德成</value>
</property>
- 1
- 2
- 3

- 1
- 2
- 3
执行完这个这段代码会给上面创建的对象属性赋值,体现了编程中常说的注入的概念。
userSerivce.setName("杨德成");
- 1

- 1
Bean的作用域
使用scope来配置
<bean id="userService" class="com.ydc.service.UserService" scope="singleton">
- 1

- 1
比如我配置了“singleton”
UserService u=(UserService)ac.getBean("userService");
UserService u2=(UserService)ac.getBean("userService");
- 1
- 2

- 1
- 2
u和u2就是同一个实例对象,如果换成”prototype”,那么u和u2就会是两个不同的实例对象,默认使用的是”singlton”,prototype性能开销比较大,慎用。
其它的可以去查api文档,这里不做一一介绍。
6、新建测试类TestMain
public class TestMain {
public static void main(String[] args) {
// TODO Auto-generated method stub
ApplicationContext ac= new ClassPathXmlApplicationContext("applicationContext.xml");
//ApplicationContext ac=ApplicaionContextUtil.getApplicationContext();
UserService u=(UserService)ac.getBean("userService");
u.sayHello();
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11

- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
a、通过配置文件applicationContext.xml实例化一个spring 的applicationContext对象(容器对象)。
b、解析XML文件,然后通过反射机制实例化bean,并且设置各个属性。
userService= Class.forName("com.service.UserService")
userService.setName("杨德成");
- 1
- 2
- 3

- 1
- 2
- 3
c、获得实例,可进行实例的一系列使用。
UserService u=(UserService)ac.getBean("userService");
u.sayHello();
- 1
- 2

- 1
- 2
通过上面的代码通过在配置文件中的id属性获得了对应的实例对象,我们并没有手动去new一个对象,这里又体现了编程中的另一个概念“ioc”
什么是ioc
ioc(inverse of controll ) 控制反转: 所谓控制反转就是把创建对象(bean),和维护对象(bean)的关系的权利从程序中转移到spring的容器(applicationContext.xml),而程序本身不再维护.
7、运行效果
下面把我的bean(这里指的是UserService类)复杂度提高
8、新建一个BybService类
package com.ydc.service;
public class BybService {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void sayBye(){
System.out.println("bye"+name);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19

- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
9、在UserService引用或是依赖 BybService
10、修改核心配置文件applicationContext.xml
<?xml version="1.0" encoding="utf-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
<bean id="userService" class="com.ydc.service.UserService">
<property name="name">
<value>杨德成</value>
</property>
<property name="byeService" ref="bybService"></property>
</bean>
<bean id="bybService" class="com.ydc.service.BybService">
<property name="name">
<value>张三</value>
</property>
</bean>
</beans>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21

- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
a、同样把新的bean配置进入。
b、配置依赖关系
<property name="byeService" ref="bybService"></property>
- 1

- 1
11、再次运行测试:
到此已经把我们编程中一个重要的概念DI 已经体现出来。
什么是DI
di(dependency injection) 依赖注入: 实际上di和ioc是同一个概念,spring设计者认为di更准确表示spring核心技术
运行原理
继续推进
12、创建一个接口 ChangeLetter
package com.ydc.service;
public interface ChangeLetter {
//声明一个方法
public String change();
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7

- 1
- 2
- 3
- 4
- 5
- 6
- 7
13、创建一个大写字母转化类,并实现ChangeLetter接口
package com.ydc.service;
public class UpperLetter implements ChangeLetter {
private String str;
public String change() {
//把小写字母->大写
return str.toUpperCase();
}
public String getStr() {
return str;
}
public void setStr(String str) {
this.str = str;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23

- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
14、创建一个小写字母转化类,并实现ChangeLetter接口
package com.ydc.service;
public class LowwerLetter implements ChangeLetter {
private String str;
public String change() {
// TODO Auto-generated method stub
return str.toLowerCase();
}
public String getStr() {
return str;
}
public void setStr(String str) {
this.str = str;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24

- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
15、配置UpperLetter类
<?xml version="1.0" encoding="utf-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
<bean id="userService" class="com.ydc.service.UserService">
<property name="name">
<value>杨德成</value>
</property>
<property name="byeService" ref="bybService"></property>
</bean>
<bean id="bybService" class="com.ydc.service.BybService">
<property name="name">
<value>张三</value>
</property>
</bean>
<bean id="changeLette" class="com.ydc.service.UpperLetter">
<property name="str">
<value>yangdecheng</value>
</property>
</bean>
</beans>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28

- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
看到没有,这里并没有配置接口。
16、点击运行
通过代码可以看出,我们可以通过获取接口来调用配置文件中所配置的接口实现类的相应方法。
17、修改为配置另外一个实现类LowwerLetter
<?xml version="1.0" encoding="utf-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
<bean id="userService" class="com.ydc.service.UserService">
<property name="name">
<value>杨德成</value>
</property>
<property name="byeService" ref="bybService"></property>
</bean>
<bean id="bybService" class="com.ydc.service.BybService">
<property name="name">
<value>张三</value>
</property>
</bean>
<!-- <bean id="changeLette" class="com.ydc.service.UpperLetter"> <property
name="str"> <value>yangdecheng</value> </property> </bean> -->
<bean id="changeLette" class="com.ydc.service.LowwerLetter">
<property name="str">
<value>YDC</value>
</property>
</bean>
</beans>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31

- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
18、点击运行
spring可以使用接口编程配合di技术实现层与层的解耦。
bean的生命周期
快速了解
step
1、重新建立一个bean类
public class PersonService {
private String name;
private Integer age;
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getName() {
return name;
}
public PersonService(String abc){
System.out.println("PersonService 有参数构造函数");
}
public PersonService(){
System.out.println("PersonService 无参数构造函数");
}
public void setName(String name) {
System.out.println("setName(String name) 函数");
this.name = name;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32

- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
2、配置bean
<?xml version="1.0" encoding="utf-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
<bean id="personService" class="com.ydc.beanlife.PersonService">
<!-- 这里注入我们属性,前提就是有setName才能ok -->
<property name="name">
<value>xiaoming</value>
</property>
</bean>
</beans>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17

- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
看见没,默认是会调起无参的构造函数,可以修改配置来调用有参构造函数。
3、测试运行
4、让bean(PersonService)实现BeanNameAware接口
@Override
public void setBeanName(String arg0) {
System.out.println("setBeanName 被调用 值"+arg0);
}
- 1
- 2
- 3
- 4
- 5
- 6

- 1
- 2
- 3
- 4
- 5
- 6
看见没,该方法可以获取正在被实例化的bean 指定的id
5、让bean(PersonService)实现BeanFactoryAware接口
@Override
public void setBeanFactory(BeanFactory arg0) throws BeansException {
// TODO Auto-generated method stub
System.out.println("setBeanFactory "+arg0);
}
- 1
- 2
- 3
- 4
- 5

- 1
- 2
- 3
- 4
- 5
看见没,该方法可以传递beanFactroy
6、让bean(PersonService)实现ApplicationContextAware接口
@Override
public void setApplicationContext(ApplicationContext arg0) throws BeansException {
// TODO Auto-generated method stub
System.out.println("setApplicationContext"+arg0);
}
- 1
- 2
- 3
- 4
- 5

- 1
- 2
- 3
- 4
- 5
看见没,该方法传递ApplicationContext
7、让bean(PersonService)实现InitializingBean接口
@Override
public void afterPropertiesSet() throws Exception {
// TODO Auto-generated method stub
System.out.println("afterPropertiesSet()");
}
- 1
- 2
- 3
- 4
- 5
- 6

- 1
- 2
- 3
- 4
- 5
- 6
看见没,该方法实在创建完bean之后被调用的。
8、让bean(PersonService)实现DisposableBean接口
@Override
public void destroy() throws Exception {
System.out.println("释放各种资源");
}
- 1
- 2
- 3
- 4
- 5

- 1
- 2
- 3
- 4
- 5
该方法在当前的bean被销毁时被调起。
可以不实现销毁接口,自己定制一个销毁的方法
@PreDestroy
public void mydestory() {
System.out.println("释放各种资源");
}
- 1
- 2
- 3
- 4

- 1
- 2
- 3
- 4
然后在配置一下定制的方法
<bean id="personService" destroy-method="mydestory" class="com.ydc.beanlife.PersonService" >
- 1

- 1
9、替代上面的InitializingBean接口
a、新建一个类似过滤器的后置处理器MyBeanPostProcessor类
public class MyBeanPostProcessor implements BeanPostProcessor {
public Object postProcessAfterInitialization(Object arg0, String arg1)
throws BeansException {
// TODO Auto-generated method stub
System.out.println("postProcessAfterInitialization 函数被调用");
System.out.println(arg0+" 被创建的时间是"+new java.util.Date());
return arg0;
}
public Object postProcessBeforeInitialization(Object arg0, String arg1)
throws BeansException {
// TODO Auto-generated method stub
System.out.println("postProcessBeforeInitialization 函数被调用");
return arg0;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20

- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
看见没,该类实现了BeanPostProcessor接口,见文生意,bean创建进度监控。
b、在配置文件中添加MyBeanPostProcessor
<bean id="myBeanPostProcessor" class="com.ydc.beanlife.MyBeanPostProcessor" />
- 1

- 1
c、测试
Spring--之旅的更多相关文章
- 我的Spring之旅(二):为请求加入參数
1.前言 在上一篇我的Spring之旅(一)中,我们仅仅是利用不带參数的请求返回一个网页或一段json,在实际的B/S.C/S网络交互中,请求中须要自己定义的參数.本篇将简单地为之前的请求加入參数. ...
- Spring之旅第六篇-事务管理
一.什么是事务 什么是事务(Transaction)?事务是数据库中的概念,是指访问并可能更新数据库中各种数据项的一个程序执行单元(unit). 有个非常经典的转账问题:A向B转款1000元,A转出成 ...
- Spring之旅(2)
Spring简化Java的下一个理念:基于切面的声明式编程 3.应用切面 依赖注入的目的是让相互协作的组件保持松散耦合:而AOP编程允许你把遍布应用各处的功能分离出来形成可重用的组件. AOP面向切面 ...
- Spring之旅
Java使得以模块化构建复杂应用系统成为可能,它为Applet而来,但为组件化而留. Spring是一个开源的框架,最早由Rod Johnson创建.Spring是为了解决企业级应用开发的复杂性而创建 ...
- Spring学习笔记—Spring之旅
1.Spring简介 Spring是一个开源框架,最早由Rod Johnson创建,并在<Expert One-on-One:J2EE Design and Development> ...
- SpringInAction读书笔记--第1章Spring之旅
1.简化Java开发 Spring是一个开源框架,它的根本使命在于简化java开发.为了降低java开发的复杂性,Spring采取了以下4种关键策略: 基于POJO的轻量级和最小侵入性编程 ...
- Spring之旅第五篇-AOP详解
一.什么是AOP? Aspect oritention programming(面向切面编程),AOP是一种思想,高度概括的话是“横向重复,纵向抽取”,如何理解呢?举个例子:访问页面时需要权限认证,如 ...
- Spring之旅第四篇-注解配置详解
一.引言 最近因为找工作,导致很长时间没有更新,找工作的时候你会明白浪费的时间后面都是要还的,现在的每一点努力,将来也会给你回报的,但行好事,莫问前程!努力总不会有错的. 上一篇Spring的配置博客 ...
- Spring之旅第三篇-Spring配置详解
上一篇学习了IOC的概念并初步分析了实现原理,这篇主要学习Spring的配置,话不多说,让我们开始! 一.Bean元素配置 1.1 基本配置 看一个最基本的bean配置 <bean name=& ...
- Spring之旅第二篇-Spring IOC概念及原理分析
一.IOC概念 上一篇已经了解了spring的相关概念,并且创建了一个Spring项目.spring中有最重要的两个概念:IOC和AOP,我们先从IOC入手. IOC全称Inversion of Co ...
随机推荐
- js parseFloat 精度问题
<script type="text/javascript"> //parseFloat function actionoftext(){var price = 10. ...
- GoldenGate 应用系统升级
(仅复制DML时)源端和目标端数据库增减复制表 增加复制表 在GoldenGate的进程参数中,如果通过*来匹配所有表,因此只要符合*所匹配的条件,那么只要在源端建立了表之后GoldenGate就能自 ...
- laravel 自定义全局函数
在 app 目录下创建一个 Helpers 目录,在此目录下创建文件.这些文件就是全局函数文件.如叫:function.php 加载此文件: 1 . 在 bootstrap/autoload.php ...
- 常用模块(hashlib、suprocess、configparser)
hashlib模块 hash是一种接受不了内容的算法,(3.x里代替了md5模块和sha模块,主要提供 SHA1, SHA224, SHA256, SHA384, SHA512 ,MD5 算法),该算 ...
- 使用U盘作为启动盘安装ubuntu系统
一.使用U盘刻录镜像 1.安装之后我们打开软件,点击文件打开,找到我们刚才进行下载的Ubuntu的ISO文件,然后点击打开,完成ISO文件的加载.接着我们插入U盘,点击UltraISO启动选项,然后 ...
- Laravel+vue实现history模式URL可行方案
项目:laravel + vue 实现前后端分离.vue-router 默认 hash 模式 -- 使用 URL 的 hash 来模拟一个完整的 URL,于是当 URL 改变时,页面不会重新加载. h ...
- 洛谷 P2630 图像变换
P2630 图像变换 题目描述 给定3行3列的图像各像素点灰度值,给定最终图像,求最短.字典序最小的操作序列. 其中,可能的操作及对应字符有如下四种: A:顺时针旋转90度: B:逆时针旋转90度: ...
- IOS开发之蘑菇街框架
近期公司的项目全然仿了蘑菇街client的框架,自己从网上找了一下,没有发现源代码.问遍各大QQ群也没有结果.上周五晚上一直在思考这个框架怎样搭建,周六早上有了灵感.写了一半.今天接着完好了一下. 在 ...
- 字符串匹配:KMP
參考:从头到尾彻底理解KMP 在字符串 str 中 匹配模式串 pattern 1. 计算模式串的 next 数组: 2. 在字符串中匹配模式串:当一个字符匹配时,str[i++], pattern[ ...
- 线程池系列一:线程池作用及Executors方法讲解
线程池的作用: 线程池作用就是限制系统中执行线程的数量. 根据系统的环境情况,可以自动或手动设置线程数量,达到运行的最佳效果:少了浪费了系统资源,多了造成系统拥挤效率不高.用线程池控制线程数量 ...