10章 command内置对象

 

  本章将要介绍最后一个内置对象command,先前介绍的内置对象都是针对web程序的,而本章所要介绍的对象是针对服务器本身的。

 

 

10.1 command对象的简介

  command对象是比较特殊的内置对象,也是DQM技术所特有的,用户可以通过此对象来查看或修改服务器当前信息,利用此对象可以在不停服务器的情况修改服务器的某些设置。

 

注意:command对象默认是关闭的,既无法使用,如果需要使用则必须开启command对象。打开或关闭command指令请参见3.2节。

 

 

10.2 相关sessionapplication的方法

1.       public int getSessionCount()

查看当前主机或虚拟主机中所有session数量,包括没有过期的和已经过期但还没有清除的session(参见8.4节)。

返回:当前主机或虚拟主机中所有session数量。

 

2.       public void clearAllSession()

清除当前主机或虚拟主机中所有的session,不管是没有过期的还是已过期但并未清除的session都将全部从内存中清除。

 

commandSession.dqm用于查看和清除当前主机或虚拟主机中的session,源程序如下:

1

2

3

4

 

5

6

7

8

9

10

<%@page command = "true" %>

 

<%if (request.getParameter("clear") == null) {%>

  当前主机或虚拟主机中session数(包括已过期但尚未清除的):<%=command.getSessionCount()%>

  <p><a href="?clear">清除当前主机或虚拟主机中所有的session</a></p>

<%}

else {

  command.clearAllSession();%>

  清除当前主机或虚拟主机中所有的session

<%}%>

 

  当访问此动态文件时就会显示出当前的session数(源程序第4行),可以试着清除所有session后再看看当前的session数(源程序510行),不过即使清除了所有的session,你还是会看到当前有1session,其实这个session就是当前访问的你所生成的session

 

3.       public int getApplicationCount()

查看当前主机或虚拟主机对应的application中已存放的内容数。

返回:当前主机或虚拟主机对应的application中已存放的内容数。

 

4.       public void clearAllApplication()

清除当前主机或虚拟主机对应的application中所有存放的内容

 

commandApplication1.dqm用于向当前主机或虚拟主机对应的application中添加5个内容,源程序如下:

1

2

3

4

5

6

application添加5个元素

<%

for (int i = 0; i < 5; i++) {

  application.setAttribute("" + i, i);

}

%>

 

commandApplication2.dqm用于查看或删除当前主机或虚拟主机对应的application中内容,源程序如下:

1

2

3

4

 

5

6

 

7

8

9

10

<%@page command = "true" %>

 

<%if (request.getParameter("clear") == null) {%>

  当前主机或虚拟主机对应的application中已存放的内容数:<%=command.getApplicationCount()%>

  <p><a href="?clear">清除当前主机或虚拟主机对应的application中所有存放的内容</a></p>

<%}

else {

  command.clearAllApplication();%>

  清除当前主机或虚拟主机对应的application中所有存放的内容

<%}%>

 

  首先访问commandApplication1.dqm用以向application中存入5个内容(源程序35行),再访问commandApplication2.dqm就会看到当前的application中共有5个内容(如果先前还有其他程序向application中添加内容则显示的内容数会大于5,源程序第4行),可以试着清除application中所有内容后再看看当前的application内容数是否为0

 

5.       public String getDhtmlExtName()

返回:当前主机或虚拟主机所设置的可执行动态文件扩展名。如果你设置的可执行文件扩展名为dqm则返回.dqm(设置可执行文件扩展名参见2.42.5节)。

 

注意:返回的可执行文件扩展名总是小写的且最前面是点符号,而在判断一个文件是否是可执行文件时是不会区分其扩展名的大小写,既如果可执行文件扩展名设置为dqma.Dqmb.dQmc.dqm都是可执行文件,即使在linuxunix下也是这样。

 

 

10.3 相关动态文件缓存池的方法

 

DQM容器中有用于存放动态文件实例的“动态可执行文件缓存池”(详细介绍参见附录1),这里介绍的方就是与其相关的。

 

1.       public int getDhtmlInstanceCount()

返回当前主机或虚拟主机的“动态可执行文件缓存池”中含有的动态文件实例数。

返回:“动态可执行文件缓存池”中含有的动态文件实例数

 

2.       public void clearAllDhtmlInstance()

清除当前主机或虚拟主机的“动态可执行文件缓存池”中所有动态文件实例。

 

3.       public boolean clearDhtmlInstance(String http_file)

清除当前主机或虚拟主机的“动态可执行文件缓存池”中指定的动态文件实例。

参数:http_file指定要删除的动态文件实例。比如需要删除http://youname/chat/main.dqm这个动态文件,则http_file值应该为:“/chat/main.dqm”。

返回:如果删除成功返回true,否则返回false

 

我们来举个例子,testDhtmlInstancePool.dqm可以证明动态文件实例是存放在缓存池中的,其源代码如下:

<%! private int ct = 0;%> 这是此动态文件第 <%=++ct%> 次被访问。

 

<%!%>是用于声明动态文件代表的java类的成员变量和方法,在这里我们声明了一个私有的成员变量ct用于记录访问此动态文件的次数,但是如果此动态文件重新new的话则此成员变量ct又会复原成0,事实上当你访问此动态文件时你会看到这是第几次被访问(多用户同时访问的情况下计数器有可能不正确),这证明了动态文件并不是每次访问时重新初始化的,而是只初始化一次后放入“动态可执行文件缓存池”的。

 

clearDhtmlInstance.dqm这个程序是用于查看和删除“动态文件缓存池”的程序,其源代码如下:

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

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

<%@page command="true"%>

<%

String password = "123456";

if (request.getParameter("B1") == null) {

%>

 

<form method="POST" action="">

       <p align="center"><b><font size="5">动态文件实例缓存池清除工具</font></b></p>

       <p align="center">操作密码:<input type="password" name="psw" size="20"></p>

       <p align="center"><input type="radio" value="getSize" checked name="system">返回当前主机中含有的动态文件实例数</p>

       <p align="center"><input type="radio" name="system" value="clearAll">清除当前主机中所有动态文件实例</p>

       <p align="center"><input type="radio" name="system" value="clear">清除当前主机中指定的动态文件实例 实例名字:<input type="text" name="dhtmlName" size="20"></p>

       <p align="center"><input type="submit" value="Submit" name="B1"><input type="reset" value="Reset" name="B2"></p>

</form>

 

<%}

else {%>

 

<p align="center"><a href="<%=request.getNowUrlFolder() + request.getNowFile().getName()%>"> </a></p>

 

<%

if (!password.equals(request.getParameter("psw"))) {

  out.println("操作密码错误!!");

  return;

}

//

String system = request.getParameter("system");

 

if ("getSize".equals(system)) {

  out.println("当前主机中含有的动态文件实例数:" + command.getDhtmlInstanceCount());

  return;

}

 

if ("clearAll".equals(system)) {

  command.clearAllDhtmlInstance();

  out.println("已清除当前主机中所有动态文件实例");

  return;

}

 

if ("clear".equals(system)) {

  if (command.clearDhtmlInstance(request.getParameter("dhtmlName"))) {

    out.println("清除当前主机中指定的动态文件实例 成功");

  }

  else {

    out.println("清除当前主机中指定的动态文件实例 失败");

  }

  return;

}

 

%>

 

<%}%>

 

程序运行后的界面如下:

10-3-1

 

这个程序具有三个功能,用户可以通过三个单选按钮来选择需要完成的功能,不过只有输入了正确的操作密码才行,在这里密码是“123456”,是由源程序第3行中的password变量定义的,如果想换成其它密码请修改这个变量的值。

我们来看第一个功能(源程序2932行),返回当前主机中含有的动态文件实例数,使用了getDhtmlInstanceCount()这个方法,执行后会显示当前主机或虚拟主机的“动态可执行文件缓存池”中所含有的实例数,如果重新启动服务器即确保一开始缓存池中不含有任何实例,然后访问testDhtmlInstancePool.dqm,之后再执行本程序的本功能就会看到当前主机中含有的动态文件实例数为2,为什么是2个呢,我们首先访问了testDhtmlInstancePool.dqm这个动态文件,所以此动态文件的实例放入了。那还有一个实例呢?不要忘记我们通过clearDhtmlInstance.dqm来查看实例数,而clearDhtmlInstance.dqm也是动态可执行文件,因此它的实例也要放入缓存池,所以缓存池中有2个实例。

第二个功能(源程序3438行),清除当前主机中所有动态文件实例,使用了clearAllDhtmlInstance()这个方法,执行后用于清除缓存池中的所有实例。你可以试着多访问几个动态文件,用第一个功能查看前主机中含有的动态文件实例数,然后执行此功能清除所有的实例后再用第一个功能查看实例数,你会发现实例数变成了1,因为你当前访问的clearDhtmlInstance.dqm又在缓存池里了。

  有时候我们只想清除某个或某些指定的实例,而不想清除全部的实例,毕竟重新初始化放入缓存池需要消耗资源,这个时候用clearDhtmlInstance(String http_file)这个方法就可以了,第三个功能就是清除当前主机中指定的动态文件实例(源程序4048行)。首先访问多个动态文件,利用第一个功能查看实例数,然后通过本功能删除某个动态文件后再用第一个功能查看实例数,看看是不是少了一个实例。比如说要清除testDhtmlInstancePool.dqm这个实例,只需要输入参数/testDhtmlInstancePool.dqm就可以了,因为testDhtmlInstancePool.dqm文件位于主机的根目录下。删除指定的实例会返回一个boolean值,删除成功是true否则为false

 

 

10.4 相关类缓存池的方法

在前面3.4节中曾介绍过主机或虚拟主机的/WEB-INF/classes/WEB-INF/lib目录下可以存放各种classjar文件,如果动态文件需要这些类则服务器会自动从这二个目录中寻找后加载。为了提高效率,服务器的类加载器设置了一个类缓存池,当需要加载类时首先检查类缓存池中是否已有加载的类,如果有则直接使用类缓存池中的类,而如果没有则加载后放入类缓存池中,以后其它动态文件要使用相同的类则就可以从类缓存池中直接读取了。然而有一个问题是类缓存池不会检测那二个目录下类文件是否改变了,这样做其实很聪明,因为classeslib目录下的类通常都不太会改变,所以没有必要浪费资源去检测,真的需要改变这些类而又不想重新启动服务器也是有办法的,就是使用本节所介绍的方法。

 

1.       public boolean clearAllLoadedClass()

清除当前主机或虚拟主机的“类缓存池”中所有已缓存的类。

返回:如果删除成功返回true,否则返回false

 

  我们来举个例子,首先建立一个class文件,我们取名叫test.Test,其源代码如下:

1

2

3

4

5

6

7

package test;

 

public class Test {

  public static String getInfo() {

    return "one";

  }

}

 

将上面类文件编译后放入/WEB-INF/classes目录下(注意包名,类文件完整路径是/WEB-INF/classes/test/Test.class),然后再编写testClassPool.dqm动态文件用于使用这个类,此动态文件源程序如下:

Test类的内容:<%=test.Test.getInfo()%>

 

  执行此动态文件后会从test.Test类读取信息,从上面的源程序可以看出执行结果为:Test类的内容:one

 

接下来我们修改一下test.Test,其修改的源代码如下:

1

2

3

4

5

6

7

package test;

 

public class Test {

  public static String getInfo() {

    return "two";

  }

}

 

可以看到返回的信息修改成了“two”了,重新编译后覆盖掉原先的类文件,然后再次执行testClassPool.dqm这个动态文件(途中不能重启服务器),你会发现执行结果还是显示“one”,前面介绍过了,因为服务器不会检测类缓存池中的类已有更新版本,所以还是使用第一次那个已缓存的类了,自然执行结果还是显示“one”,为了在不停机的情况下使用更新后的类则可以用到上面介绍的方法先删除“类缓存池”中所有的类(对于“类缓存池”而言无法删除指定的类缓存),这样当再要使用此类的话服务器会重新读取后放入类缓存池了。

动态文件clearClassPool.dqm就是用于清除“类缓存池”中的缓存,源程序如下:

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

33

<%@page command="true"%>

<%

String password = "123456";

if (request.getParameter("B1") == null) {

%>

 

<form method="POST" action="">

       <p align="center"><b><font size="5">动态文件类缓存池清除工具</font></b></p>

       <p align="center">操作密码:<input type="password" name="psw" size="20"></p>

       <p align="center">清除当前主机中所有类缓存</p>

       <p align="center"><input type="submit" value="Submit" name="B1"><input type="reset" value="Reset" name="B2"></p>

</form>

 

<%}

else {%>

 

<p align="center"><a href="<%=request.getNowUrlFolder() + request.getNowFile().getName()%>"> </a></p>

 

<%

if (!password.equals(request.getParameter("psw"))) {

  out.println("操作密码错误!!");

  return;

}

//

 

if (command.clearAllLoadedClass()) {

  out.println("清除当前主机中所有类缓存 成功");

}

else {

  out.println("清除当前主机中所有类缓存 失败");

}

 

}%>

 

程序运行后的界面如下:

10-4-1

 

这个程序很像上一节介绍过的clearDhtmlInstance.dqm,这里只有一个功能即删除当前主机中所有类缓存,不过只能输入了正确的操作密码才行,在这里密码是“123456”,也是由源程序第3行中的password变量定义的,如果想换成其它密码请修改这个变量的值。

清除当前主机中所有的类缓存,在源程序26行使用了clearAllLoadedClass ()这个方法,执行后用于清除类缓存池中的所有缓存类。

 

  有了上面这个删除类缓存的程序我们可以继续先前的例子了,输入操作密码后执行可以看到提示类缓存删除成功,如果不成功请重试一下。清除完后再次执行testClassPool.dqm这个动态文件,这次执行的结果应该变成了“two”吧,不过很抱歉还是让您失望了,执行的结果仍然是显示“one”,为什么呢?类缓存不是已经删除了吗,但是不要忘记还有“动态可执行文件缓存池”呢,所以必须也要删除动态文件实例缓存(使用10.3节的clearDhtmlInstance.dqm动态文件),现在再执行testClassPool.dqm,执行结果终于显示了“two”。

 

注意: java本身就有一个类叫java.lang.Class,这里所指的类是指类型(就是指java.lang.Class这个类)而不是指类的实例。只有是/WEB-INF/classes/WEB-INF/lib目录下的类才会进入类缓存,如果通过其他方法载入的类是不会进入类缓存,请参见附录5

 

 

10.5 软重启服务器

内置command对象中还有一个方法用于软重启服务器。

public void resetHost()

此方法用于重新设置当前所在的主机或虚拟主机为开机时状态,等于重新启动整个服务器,但其实并没有关机重启,同时也只能作用于当前所在的虚拟主机中。实际上这个方法等同于同时执行clearAllApplication()clearAllDhtmlInstance()clearAllLoadedClass()clearAllSession()clearAllStaticPage()这五个方法,前四个方法在本章中都以介绍过了,最后的clearAllStaticPage()方法我们将在12.2节中介绍。

 

 

10.6 日志操作

在前面提到过服务器的访问日志,参见2.1节可以看到saveLogs可以设定日志的一些功能,其中有一项就是bufSize,如果开启了日志记录到文件功能,就象前面提到的只有达到设定的缓存容量后才会输出到文件,如果没有达到缓存容量则日志将会保存在缓存中。那么怎么才能看到当前缓存中的日志呢,command提供了以下方法。

public String getLogBuf(String psw)

读取当前缓存中所记录的还未保存到日志文件的日志内容。

参数:psw查看所需要的密码。因为所查看到的日志是整个服务器的而不仅仅是当前主机或虚拟主机的,为此需要提供密码,密码设定请参见2.1节的systemPsw功能项。

返回:如果密码正确则返回当前缓存中的日志内容,否则返回null

 

 

10.7 密码保护操作

在前面提到过服务器可以开启密码保护(参见2.4节和2.5节的"needPassword"配置项),如果开启了密码保护则访问时就需要用户输入用户名和密码,如果通过的话就可以访问服务器资源了,但是有的时候我们需要知道用户使用哪个身份通过了密码保护,为此command提供了以下方法。

public String getAuthUser()

读取通过当前主机或虚拟主机密码保护的那个用户名。

返回:如果启用密码保护且通过则返回那个通过的用户名,其他情况则返回null

 

为什么需要有这个方法呢?如果不想使用动态语言编写用户认证,那么就可以用服务器本身提供的密码保护来实现(用户可以采用CheckServerPSW接口来编写自己的密码验证程序),在这种情况下就可以使用本方法来获取通过验证的用户名,从而进行某些操作,例如根据本方法获取当前通过验证的用户名,然后根据此用户名设置不同的功能权限(比如根据用户名的不同将不同的权限标志写入session)。