OneCoder


  • 首页

  • 归档

  • 标签

  • 关于

  • 搜索

白话Java - try-finally块

发表于 2012-06-29

本文讲述的是Java中try finally代码块执行顺序,和当其存在于循环中的时候的跳出和执行问题。白话,也要简化,一段代码,来说明问题

  /**
	 * @author lihzh
	 * @date 2012-6-8 下午9:21:22
	 * @blog http://www.coderli.com
	 */
	public static void main(String[] args) {
		for (int i = 0; i < 10; i++) {
			System.out.println("Begin loop: " + i);
			if (i == 2) {
				System.out.println("Continue: " + i);
				continue;
			}
			try {
				System.out.println("i = " + i);
				if (i == 4) {
					System.out.println("In try continue: " + i);
					continue;
				}
				if (i == 5) {
					return;
				}
			} finally {
				System.out.println("This is finally. " + i);
			}
		}
	}

执行结果:

Begin loop: 0
i = 0
This is finally. 0
Begin loop: 1
i = 1
This is finally. 1
Begin loop: 2
Continue: 2
Begin loop: 3
i = 3
This is finally. 3
Begin loop: 4
i = 4
In try continue: 4
This is finally. 4
Begin loop: 5
i = 5
This is finally. 5

如果还没看明白,那我再啰嗦两句:finally就是最后的,跟try和catch是兄弟,就好像正常人走try分支,走着走着你不正常了,就开始走catch分支,但是不管你正常不正常,最后都要通过最终的检测,才算完。他们是一个组合。至于外面的for循环,就好像你在跑圈,本来每圈你都路过这个关卡(try-finnaly),但是你说,第二圈(i=2)跑一半的时候,突然说,下面我不跑了,我要开始跑第三圈,那关卡也拿你没辙。拦不住你。至于跑到第五圈了,你说不行了,我跑不动了,以后都不跑了,那也行你退出了,不过你已经进入关卡了,一样,唯一的出口就在finally。通过再退出。

阅读全文 »

白话Java - Double.NaN

发表于 2012-06-28

今天处理一个关于Double.NaN的异常。

Unknown column 'NaN' in 'field list'

NaN = Not a Number。就是不是数字。我们用0/0.0打印出来的结果就是NaN。

Double d = 0/0.0;
System.out.println(d);

JDK的Double类里,提供的NaN的实现是:

public static final double NaN = 0.0d / 0.0;

如果是非零的数除以0.0,得出的是:Infinity。正数除以0.0,就是正Infinity,负数就是-Infinity。JDK里给出样例是:

    /**
     * A constant holding the positive infinity of type
     * {@code double}. It is equal to the value returned by
     * {@code Double.longBitsToDouble(0x7ff0000000000000L)}.
     */
    public static final double POSITIVE_INFINITY = 1.0 / 0.0;

    /**
     * A constant holding the negative infinity of type
     * {@code double}. It is equal to the value returned by
     * {@code Double.longBitsToDouble(0xfff0000000000000L)}.
     */
    public static final double NEGATIVE_INFINITY = -1.0 / 0.0;

用控制台啊打印的结果是:

Infinity/-Infinity

既然,NaN不是一个数,那他跟任何数比较都不相等,即使跟他自己比较。

System.out.println(Double.NaN == Double.NaN);//输出:false

说点通俗的,什么情况下出现NaN?其实这就是数学老师教的那些,没有意义的计算的结果。比如0/0没有意义。老师还教过什么?对啊,负数的平方根啊。所以,用Math.sqrt(-n),算出来的结果,也是NaN。

不过有一点,我也不能很好解释的就是(int) Double.NaN = 0。。这个,就先这样吧。

阅读全文 »

Maven批量安装本地Jar文件小工具

发表于 2012-06-27

Maven 批量安装本地 Jar文件到本地Maven库小程序。根据自己的需求临时开发完成。

使用方式:

  • 在config.properties中,配置待安装jar文件的存放路径。
  • 安装时groupId,artifactId,version等信息,根据jar文件的文件名获得。采用分割”-“的方式,解析出来。所以,推荐jar的文件名中含有两个”-“。例如:group-artifact-version.jar。如果为group-artifactversion.jar,则groupId=group,artifactId=version=artifactversion。
public class Main { 
     
    private static final Log _log = LogFactory.getLog(Main.class); 
    private static PropertyHelper propHelper = new PropertyHelper("config"); 
    private static Runtime _runRuntime = Runtime.getRuntime(); 
    private static boolean isDelete = Boolean.valueOf(propHelper.getValue("delete-installed-jar")); 
    private static boolean isMove = Boolean.valueOf(propHelper.getValue("move-installed-jar")); 
    private static final String KEY_JARPATH = "jar-path"; 
    private static final String KEY_BACKUPPATH = "back-path"; 
    private static final String ENCODE = "gbk"; 
    private static final String INSTALL_PATH = propHelper.getValue(KEY_JARPATH); 
    private static  String CMD_INSTALL_FILE; 
    private static  String CMD_BACKUP_JAR; 
     
    public static void main(String[] args) { 
         
        _log.info("The path of the jars is ["+INSTALL_PATH+"]."); 
        File file = new File(INSTALL_PATH); 
        if(!file.isDirectory()){ 
            _log.warn("The path must be a directory."); 
            return; 
        } 
        FilenameFilter filter = new JarFilter(); 
        File[] jarFiles = file.listFiles(filter); 
        for(File jar: jarFiles){ 
            installJarToMaven(jar); 
            if(isDelete){ 
                _log.info("Delete the original jar file ["+jar.getName()+"]."); 
                jar.delete(); 
            }else{ 
                if(isMove){ 
                    String backupPath = propHelper.getValue(KEY_BACKUPPATH); 
                    backupJar(jar,file,backupPath); 
                } 
            } 
        } 
    } 
 
    private static void backupJar(File jar, File file, String backupPath) { 
        CMD_BACKUP_JAR = "copy "+INSTALL_PATH+File.separator+jar.getName()+" "+backupPath; 
        String[] cmds = new String[]{"cmd", "/C",CMD_BACKUP_JAR}; 
        try { 
            Process process =_runRuntime.exec(cmds,null,file); 
            printResult(process); 
        } catch (IOException e) { 
            e.printStackTrace(); 
        } 
            _log.info("The jar ["+jar.getName()+"]  is backup, it&#39;s will be deleted.\r"); 
            jar.delete(); 
    } 
 
    private static void installJarToMaven(File file) { 
        String fileName = file.getName(); 
        String jarName = getJarName(fileName); 
        String groupId=null; 
        String artifactId=null; 
        String version=null; 
        int groupIndex = jarName.indexOf("-"); 
        if(groupIndex==-1){ 
            version = artifactId = groupId = jarName; 
        }else{ 
            groupId = jarName.substring(0,groupIndex); 
            int versionIndex = jarName.lastIndexOf("-"); 
            if(groupIndex==versionIndex){ 
                version = artifactId = jarName.substring(versionIndex+1,jarName.length()); 
            }else{ 
                artifactId = jarName.substring(groupIndex+1,versionIndex); 
                version = jarName.substring(versionIndex+1,jarName.length()); 
            } 
        } 
        _log.info("Jar ["+jarName+"] will be installed with the groupId="+groupId+" ," 
                +"artifactId="+artifactId+" , version="+version+"."); 
        executeInstall( groupId,  artifactId,  version, file.getPath()); 
    } 
 
    private static void executeInstall(String groupId, String artifactId, 
            String version, String path) { 
        CMD_INSTALL_FILE = createInstallFileCMD( groupId,  artifactId, 
                 version,  path); 
        String[] cmds = new String[]{"cmd", "/C",CMD_INSTALL_FILE}; 
        try { 
            Process process = _runRuntime.exec(cmds); 
            printResult(process); 
        } catch (IOException e) { 
            e.printStackTrace(); 
        } 
    } 
     
    private static void printResult(Process process) throws IOException { 
        InputStream is = process.getInputStream(); 
        BufferedReader br = new BufferedReader(new InputStreamReader(is,ENCODE)); 
        String lineStr; 
        while((lineStr= br.readLine()) !=null){ 
            System.out.println(lineStr); 
        } 
    } 
 
    private static String createInstallFileCMD(String groupId, 
            String artifactId, String version, String path) { 
        StringBuffer sb = new StringBuffer(); 
        sb.append("mvn install:install-file -DgroupId=").append(groupId) 
            .append(" -DartifactId=").append(artifactId) 
            .append(" -Dversion=").append(version) 
            .append(" -Dpackaging=jar") 
            .append(" -Dfile=").append(path); 
        _log.debug(sb.toString()); 
        return sb.toString(); 
    } 
 
    private static String getJarName(String fileName) { 
        int index = fileName.indexOf(".jar"); 
        return fileName.substring(0, index); 
    } 
 
} 
public class PropertyHelper { 
     
    private ResourceBundle propBundle;  
     
    public PropertyHelper(String bundle){ 
        propBundle = PropertyResourceBundle.getBundle(bundle); 
    } 
     
    public  String getValue(String key){ 
        return this.propBundle.getString(key); 
    } 
 
} 

sourceforge地址:

  • https://sourceforge.net/projects/maventools/files/
阅读全文 »

Maven库中.lastUpdated文件自动清除工具

发表于 2012-06-26

最近开发过程中,在更新maven库时,如果网络问不定或者是一些自己手动安装到本地maven库的jar包,在中心库找不到对应的jar,会生成一些.lastUpdated文件,会导致m2e工具无法找到依赖的jar包,从而提示编译错误。

对于该问题,我也没有找到很好的解决方案,只能手动删除一下lastUpdated文件。文件多时十分繁琐。网上看到别人的解决方案也有利用命令行命令,匹配文件扩展名批量删除的。命令行不会,于是就写了几行代码用于删除.lastUpdated文件。如有其他直接的解决方案,望不吝赐教,写代码实属无奈之举。

public class DelLastUpdated { 
 
    private static PropertyHelper propHelper = new PropertyHelper("config"); 
    private static final String KEY_MAVEN_REPO = "maven.repo"; 
    private static final String MAVEN_REPO_PATH = propHelper 
            .getValue(KEY_MAVEN_REPO); 
    private static final String FILE_SUFFIX = "lastUpdated"; 
    private static final Log _log = LogFactory.getLog(DelLastUpdated.class); 
 
    /** 
     * @param args 
     */ 
    public static void main(String[] args) { 
        File mavenRep = new File(MAVEN_REPO_PATH); 
        if (!mavenRep.exists()) { 
            _log.warn("Maven repos is not exist."); 
            return; 
        } 
        File[] files = mavenRep.listFiles((FilenameFilter) FileFilterUtils 
                .directoryFileFilter()); 
        delFileRecr(files,null); 
        _log.info("Clean lastUpdated files finished."); 
    } 
 
    private static void delFileRecr(File[] dirs, File[] files) { 
        if (dirs != null && dirs.length &gt; 0) { 
            for(File dir: dirs){ 
                File[] childDir = dir.listFiles((FilenameFilter) FileFilterUtils 
                .directoryFileFilter()); 
                File[] childFiles = dir.listFiles((FilenameFilter) FileFilterUtils 
                .suffixFileFilter(FILE_SUFFIX)); 
                delFileRecr(childDir,childFiles); 
            } 
        } 
        if(files!=null&&files.length&gt;0){ 
            for(File file: files){ 
                if(file.delete()){ 
                    _log.info("File: ["+file.getName()+"] has been deleted."); 
                } 
            } 
        } 
    } 
 
} 

配置文件:config.properties

maven.repo=D:\\.m2\\repository 

源码下载地址:

  • svn:https://svn.code.sf.net/p/maventools/code/trunk/maven-tools

工程里还包括一个批量安装jar包到本地maven库的工具。以后再另外介绍。

阅读全文 »

白话Java - 守护线程

发表于 2012-06-25

关于”白话”, 偶然想到的词。目的就是用简洁,明快的语言来告诉您,我所知道的一切。

Java中的线程分两类,用户线程和守护线程。

Thread commonThread = new Thread("Common Thread");

这样就是用户线程。

Thread daemonThread = new Thread("Daemon Thread");
daemonThread.setDaemon(true);

这样就是守护线程。

起了”守护”线程这么动听的名字,自然要起到”守护”的作用。就好比男人要守护妹子。守护线程的作用,按照网上的说法是:

守护线程则是用来服务用户线程的,如果没有其他用户线程在运行,那么就没有可服务对象,也就没有理由继续下去。

说白了就是妹子没了,男人也就自尽了。分情况写几个例子,一跑便知。

1. 两个妹子 - 互不相干,你挂你的,我挂我的

	/**
	 * 测试两个用户线程的情况
	 * 
	 * @author lihzh(OneCoder)
	 * @date 2012-6-25 下午10:07:16
	 */
	private static void twoCommonThread() {
		String girlOneName = "Girl One";
		Thread girlOne = new Thread(new MyRunner(3000, girlOneName), girlOneName);
		String girlTwoName = "Girl Two";
		Thread girlTwo = new Thread(new MyRunner(5000, girlTwoName), girlTwoName);
		girlOne.start();
		System.out.println(girlOneName + "is starting.");
		girlTwo.start();
		System.out.println(girlTwoName + "is starting");
	}

	private static class MyRunner implements Runnable {
		
		private long sleepPeriod;
		private String threadName;
		
		public MyRunner(long sleepPeriod, String threadName) {
			this.sleepPeriod = sleepPeriod;
			this.threadName = threadName;
		}
		@Override
		public void run() {
			try {
				Thread.sleep(sleepPeriod);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println(threadName + " has finished.");
		}
	}

开始都活着。

3秒后,妹子1挂了,妹子2活的好好的,她的寿命是5秒。

2. 一妹子一王子

   /**
	 * 测试一个用户一个守护线程
	 * 
	 * @author lihzh(OneCoder)
	 * @date 2012-6-25 下午10:22:58
	 */
	private static void oneCommonOneDaemonThread() {
		String girlName = "Girl";
		Thread girl = new Thread(new MyRunner(3000, girlName), girlName);
		String princeName = "Prince";
		Thread prince = new Thread(new MyRunner(5000, princeName), princeName);
		girl.start();
		System.out.println(girlName + "is starting.");
		prince.setDaemon(true);
		prince.start();
		System.out.println(prince + "is starting");
	}

开始快乐的生活着,妹子能活3秒,王子本来能活5秒

但是3秒后,妹子挂了,王子也殉情了。

你可能会问,如果王子活3秒,妹子能活5秒呢。我只能说,虽然你是王子,该挂也得挂,妹子还会找到其他高富帅的,懂?

看,王子已经挂了。

3. 两个王子

   /**
	 * 测试两个守护线程
	 * 
	 * @author lihzh(OneCoder)
	 * @date 2012-6-25 下午10:29:18
	 */
	private static void twoDaemonThread() {
		String princeOneName = "Prince One";
		Thread princeOne = new Thread(new MyRunner(5000, princeOneName), princeOneName);
		String princeTwoName = "Prince Two";
		Thread princeTwo = new Thread(new MyRunner(3000, princeTwoName), princeTwoName);
		princeOne.setDaemon(true);
		princeOne.start();
		System.out.println(princeOneName + "is starting.");
		princeTwo.setDaemon(true);
		princeTwo.start();
		System.out.println(princeTwoName + "is starting");
	}

我只能说,没有妹子,没有活着的理由,直接就都挂了。

现在,你懂守护线程了吗?

阅读全文 »

Windows下Libvirt Java API使用教程(二)- 接口使用说明

发表于 2012-06-21

介绍完libvirt Java API的部署工作,接下来我们就介绍一下接口的使用和代码样例。

libvirt的管理单位是单个主机,所以探测和监控接口所能获取的信息的最大范围也是主机。所以先从主机入手,验证libvirt接口。主机(libvirt所在管理节点)探测相关接口验证代码如下:

   @Before
	public void init() {
		System.setProperty("jna.library.path",
				"D:/Git-Repo/git/libvirt-java/libvirt-java/src/test/java/kubi/coder/");
		try {
			xenConn = new Connect("xen+tcp://10.4.55.203/");
			// system代表拥有系统权限/session是用户权限
			kvmConn = new Connect("qemu+tcp://10.4.54.10/system");
		} catch (LibvirtException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 主机信息探测接口验证,验证可以获取的主机属性和监控指标,分别考虑Xen环境和KVM环境
	 * 
	 * 
	 * @author lihzh
	 * @date 2012-5-15 下午1:28:00
	 */
	@Test
	public void testDetectHost() {
		// KVM
		doDetectHost(kvmConn);
		// XEN
		doDetectHost(xenConn);
	}

	/**
	 * 执行探测主机测试函数
	 * 
	 * @param conn
	 * @author lihzh
	 * @date 2012-5-15 下午1:37:37
	 */
	private void doDetectHost(Connect conn) {
		try {
			// Returns the free memory for the connection
			// System.out.println("FreeMemory: " + conn.getFreeMemory());// 不支持
			
			// Returns the system hostname on which the hypervisor is running.
			// (the result of the gethostname(2) system call)
			// If we are connected to a remote system,
			// then this returns the hostname of the remote system
			System.out.println("Host name: " + conn.getHostName());
			// Gets the name of the Hypervisor software used.
			System.out.println("Type: " + conn.getType());
			// Gets the version level of the Hypervisor running. This may work
			// only with hypervisor call, i.e. with priviledged access to the
			// hypervisor, not with a Read-Only connection. If the version can't
			// be extracted by lack of capacities returns 0.
			// Returns:
			// major * 1,000,000 + minor * 1,000 + release
			System.out.println(conn.getVersion());

			NodeInfo nodeInfo = conn.nodeInfo();
			System.out.println("the number of active CPUs: " + nodeInfo.cpus);
			System.out.println("number of core per socket: " + nodeInfo.cores);
			System.out.println("memory size in kilobytes: " + nodeInfo.memory);
			System.out.println("expected CPU frequency: " + nodeInfo.mhz);
			System.out.println("string indicating the CPU model: "
					+ nodeInfo.model);
			System.out.println("the number of NUMA cell, 1 for uniform: "
					+ nodeInfo.nodes);
			System.out.println("number of CPU socket per node: "
					+ nodeInfo.sockets);
			System.out.println("number of threads per core: "
					+ nodeInfo.threads);
			System.out
					.println("the total number of CPUs supported but not necessarily active in the host.: "
							+ nodeInfo.maxCpus());

			// for (String interName : conn.listInterfaces()) {
			// System.out.println(interName);
			// } 不支持

			// Provides the list of names of defined interfaces on this host

			// for (String interName : conn.listDefinedInterfaces()) {
			// System.out.println(interName);
			// } // 不支持

			// Lists the active networks.
			for (String networkName : conn.listNetworks()) {
				System.out.println("Network name: " + networkName);
			}

			// Lists the names of the network filters
			for (String networkFilterName : conn.listNetworkFilters()) {
				System.out.println("Network filter name: " + networkFilterName);
			}

			System.out.println(conn.getCapabilities());
		} catch (LibvirtException e) {
			e.printStackTrace();
		}
	}

分别在KVM和XEN环境下测试了libvirt接口,测试结果如下:

Host name: s5410
Type: QEMU
9001
the number of active CPUs: 64
number of core per socket: 8
memory size in kilobytes: 49444896
expected CPU frequency: 2131
string indicating the CPU model: x86_64
the number of NUMA cell, 1 for uniform: 1
number of CPU socket per node: 4
number of threads per core: 2
the total number of CPUs supported but not necessarily active in the host.: 64
Network name: hello
Network name: default
Network filter name: no-other-l2-traffic
Network filter name: allow-dhcp
Network filter name: allow-dhcp-server
Network filter name: no-other-rarp-traffic
Network filter name: no-mac-spoofing
Network filter name: qemu-announce-self-rarp
Network filter name: clean-traffic
Network filter name: no-arp-spoofing
Network filter name: allow-ipv4
Network filter name: no-ip-spoofing
Network filter name: qemu-announce-self
Network filter name: allow-arp
Network filter name: no-mac-broadcast
Network filter name: allow-incoming-ipv4
Network filter name: no-ip-multicast
<capabilities>

  <host>
    <uuid>30b940dd-f79a-21a2-82d5-ddc1b1b4a7e4</uuid>
    <cpu>
      <arch>x86_64</arch>
      <model>core2duo</model>
      <topology sockets='4' cores='8' threads='2'/>
      <feature name='lahf_lm'/>
      <feature name='rdtscp'/>
      <feature name='pdpe1gb'/>
      <feature name='popcnt'/>
      <feature name='x2apic'/>
      <feature name='sse4.2'/>
      <feature name='sse4.1'/>
      <feature name='dca'/>
      <feature name='xtpr'/>
      <feature name='cx16'/>
      <feature name='tm2'/>
      <feature name='est'/>
      <feature name='vmx'/>
      <feature name='ds_cpl'/>
      <feature name='pbe'/>
      <feature name='tm'/>
      <feature name='ht'/>
      <feature name='ss'/>
      <feature name='acpi'/>
      <feature name='ds'/>
    </cpu>
    <migration_features>
      <live/>
      <uri_transports>
        <uri_transport>tcp</uri_transport>
      </uri_transports>
    </migration_features>
  </host>

  <guest>
    <os_type>hvm</os_type>
    <arch name='i686'>
      <wordsize>32</wordsize>
      <emulator>/usr/libexec/qemu-kvm</emulator>
      <machine>rhel5.4.0</machine>
      <machine canonical='rhel5.4.0'>pc</machine>
      <machine>rhel5.4.4</machine>
      <machine>rhel5.5.0</machine>
      <machine>rhel5.6.0</machine>
      <domain type='qemu'>
      </domain>
      <domain type='kvm'>
        <emulator>/usr/libexec/qemu-kvm</emulator>
      </domain>
    </arch>
    <features>
      <cpuselection/>
      <pae/>
      <nonpae/>
      <acpi default='on' toggle='yes'/>
      <apic default='on' toggle='no'/>
    </features>
  </guest>

  <guest>
    <os_type>hvm</os_type>
    <arch name='x86_64'>
      <wordsize>64</wordsize>
      <emulator>/usr/libexec/qemu-kvm</emulator>
      <machine>rhel5.4.0</machine>
      <machine canonical='rhel5.4.0'>pc</machine>
      <machine>rhel5.4.4</machine>
      <machine>rhel5.5.0</machine>
      <machine>rhel5.6.0</machine>
      <domain type='qemu'>
      </domain>
      <domain type='kvm'>
        <emulator>/usr/libexec/qemu-kvm</emulator>
      </domain>
    </arch>
    <features>
      <cpuselection/>
      <acpi default='on' toggle='yes'/>
      <apic default='on' toggle='no'/>
    </features>
  </guest>

</capabilities>

Host name: s55203
Type: Xen
3001000
the number of active CPUs: 32
number of core per socket: 8
memory size in kilobytes: 50276352
expected CPU frequency: 1995
string indicating the CPU model: x86_64
the number of NUMA cell, 1 for uniform: 1
number of CPU socket per node: 2
number of threads per core: 2
the total number of CPUs supported but not necessarily active in the host.: 32
Network name: default
Network filter name: allow-dhcp-server
Network filter name: qemu-announce-self-rarp
Network filter name: no-arp-spoofing
Network filter name: allow-arp
Network filter name: no-ip-multicast
Network filter name: no-other-rarp-traffic
Network filter name: allow-incoming-ipv4
Network filter name: no-mac-spoofing
Network filter name: allow-ipv4
Network filter name: no-ip-spoofing
Network filter name: clean-traffic
Network filter name: qemu-announce-self
Network filter name: no-other-l2-traffic
Network filter name: allow-dhcp
Network filter name: no-mac-broadcast
<capabilities>

  <host>
    <cpu>
      <arch>x86_64</arch>
      <features>
        <vmx/>
      </features>
    </cpu>
    <migration_features>
      <live/>
      <uri_transports>
        <uri_transport>xenmigr</uri_transport>
      </uri_transports>
    </migration_features>
  </host>

  <guest>
    <os_type>xen</os_type>
    <arch name='x86_64'>
      <wordsize>64</wordsize>
      <emulator>/usr/lib64/xen/bin/qemu-dm</emulator>
      <machine>xenpv</machine>
      <domain type='xen'>
      </domain>
    </arch>
  </guest>

  <guest>
    <os_type>xen</os_type>
    <arch name='i686'>
      <wordsize>32</wordsize>
      <emulator>/usr/lib64/xen/bin/qemu-dm</emulator>
      <machine>xenpv</machine>
      <domain type='xen'>
      </domain>
    </arch>
    <features>
      <pae/>
    </features>
  </guest>

  <guest>
    <os_type>hvm</os_type>
    <arch name='i686'>
      <wordsize>32</wordsize>
      <emulator>/usr/lib64/xen/bin/qemu-dm</emulator>
      <loader>/usr/lib/xen/boot/hvmloader</loader>
      <machine>xenfv</machine>
      <domain type='xen'>
      </domain>
    </arch>
    <features>
      <pae/>
      <nonpae/>
      <acpi default='on' toggle='yes'/>
      <apic default='on' toggle='yes'/>
    </features>
  </guest>

  <guest>
    <os_type>hvm</os_type>
    <arch name='x86_64'>
      <wordsize>64</wordsize>
      <emulator>/usr/lib64/xen/bin/qemu-dm</emulator>
      <loader>/usr/lib/xen/boot/hvmloader</loader>
      <machine>xenfv</machine>
      <domain type='xen'>
      </domain>
    </arch>
    <features>
      <acpi default='on' toggle='yes'/>
      <apic default='on' toggle='yes'/>
    </features>
  </guest>

</capabilities>
  • 注1:标注不支持的,是在当前环境当前libvirt版本下,运行会报: unsupported in sys interface的接口。
  • 注2:名词解释
    • hvm:gives similar information but when running a 32 bit OS fully virtualized with Xen using the hvm support。
    • numa:For processors that support hyperthreading, this is the number of hyperthreads they have per core. On a machine that doesn’t support hyperthreading, this will be 1.

说实话,这么多信息中,笔者关注的不多,有很多甚至说不出其代表的含义,笔者关注只是cpu的个数,核心数,内存总量等直观信息。有就足以。

看完了主机,再看看虚拟机。一个虚拟化环境中的核心资源自然是虚拟机,所以其属性和信息也自然多很多,上测试代码:

/**
	 * 测试探测虚拟机接口
	 * 
	 * @author lihzh
	 * @date 2012-5-16 上午11:14:20
	 */
	@Test
	public void testDetectDomains() {
		// KVM
		doDetectDomains(kvmConn);
		// XEN
		doDetectDomains(xenConn);
	}

        /**
	 * 执行探测虚拟机测试函数
	 * 
	 * @param conn
	 * @author lihzh
	 * @date 2012-5-16 上午11:15:27
	 */
	private void doDetectDomains(Connect conn) {
		try {
			// Lists the active domains.(列出所有处于启动(激活)状态的虚拟机的id)
			for (int activeDomId : conn.listDomains()) {
				System.out.println("Active vm id: " + activeDomId);
				// 根据Id,探测各个虚拟机的详细信息
				Domain domain = conn.domainLookupByID(activeDomId);
				// Gets the hypervisor ID number for the domain
				System.out.println("Domain id: " + domain.getID());
				// Gets the public name for this domain
				System.out.println("Domain name: " + domain.getName());
				// Gets the type of domain operation system.
				System.out.println("Domain os type: " + domain.getOSType());
				// Gets the UUID for this domain as string.
				System.out.println("Domain uuid: " + domain.getUUIDString());
				// Retrieve the maximum amount of physical memory allocated to a
				// domain.
				System.out.println("Domain max memory: "
						+ domain.getMaxMemory());
				// Provides the maximum number of virtual CPUs supported for the
				// guest VM. If the guest is inactive, this is basically the
				// same as virConnectGetMaxVcpus. If the guest is running this
				// will reflect the maximum number of virtual CPUs the guest was
				// booted with.
				System.out.println("Domain max vcpu: " + domain.getMaxVcpus());
				// Provides an XML description of the domain. The description
				// may be
				// reused later to relaunch the domain with createLinux().
				System.out.println("Domain xml description: "
						+ domain.getXMLDesc(0));
				System.out.println("Domain maxMen allowed: "
						+ domain.getInfo().maxMem);
				System.out.println("Domain memory: " + domain.getInfo().memory);
				// domain.getJobInfo()
				// 不支持
				System.out.println("Domain state: " + domain.getInfo().state);
				// Provides a boolean value indicating whether the network is
				// configured to be automatically started when the host machine
				// boots.
				System.out.println("Domain network autostart: "
						+ domain.getAutostart());
				// Extracts information about virtual CPUs of this domain
				for (VcpuInfo vcpuInfo : domain.getVcpusInfo()) {
					System.out.println("cpu: " + vcpuInfo.cpu);
					System.out.println("cpu time: " + vcpuInfo.cpuTime);
					System.out.println("cpu number: " + vcpuInfo.number);
					System.out.println("cpu state: " + vcpuInfo.state);
				}
			
				// 如果是KVM环境
				if (conn.getURI().startsWith("qemu")) {
					// This function returns block device (disk) stats for block
					// devices attached to the domain
					DomainBlockInfo blockInfo = domain
							.blockInfo("/opt/awcloud/instance/admin/"
									+ domain.getName() + "/disk");
					System.out.println("Disk Capacity: "
							+ blockInfo.getCapacity());
					System.out.println("Disk allocation: "
							+ blockInfo.getAllocation());
					System.out.println("Disk physical: "
							+ blockInfo.getPhysical());

					DomainBlockStats blockStats = domain.blockStats("vda");
					// 磁盘读取请求总数
					System.out.println("read request num: " + blockStats.rd_req);
					// 磁盘读取总bytes数
					System.out.println("read request num: " + blockStats.rd_bytes);
					// 磁盘写入请求总数
					System.out.println("read request num: " + blockStats.wr_req);
					// 磁盘写入总bytes数
					System.out.println("read request num: " + blockStats.wr_bytes);
				}

			}
			
			// 列出所有停止态的虚拟机
			for (String name : conn.listDefinedDomains()) {
				System.out.println("Inactive domain name: " + name);
			}

		} catch (LibvirtException e) {
			e.printStackTrace();
		}
	}

循环较多,摘取部分测试结果如下:

Active vm id: 53
Domain id: 53
Domain name: i-546A099E
Domain os type: hvm
Domain uuid: e608560a-2c03-8e48-2e60-d0d01693f530
Domain max memory: 147456
Domain max vcpu: 1
Domain xml description: <domain type='xen' id='53'>
  <name>i-546A099E</name>
  <uuid>e608560a-2c03-8e48-2e60-d0d01693f530</uuid>
  <memory>131072</memory>
  <currentMemory>131072</currentMemory>
  <vcpu>1</vcpu>
  <os>
    <type>hvm</type>
    <loader>/usr/lib/xen/boot/hvmloader</loader>
    <boot dev='hd'/>
  </os>
  <features>
    <acpi/>
    <apic/>
    <pae/>
  </features>
  <clock offset='utc'/>
  <on_poweroff>destroy</on_poweroff>
  <on_reboot>restart</on_reboot>
  <on_crash>restart</on_crash>
  <devices>
    <emulator>/usr/lib64/xen/bin/qemu-dm</emulator>
    <disk type='file' device='disk'>
      <driver name='file'/>
      <source file='/opt/awcloud/instance/admin/i-546A099E/disk'/>
      <target dev='hda' bus='ide'/>
    </disk>
    <disk type='file' device='disk'>
      <driver name='file'/>
      <source file='/opt/awcloud/instance/admin/i-546A099E/disk2'/>
      <target dev='hdb' bus='ide'/>
    </disk>
    <interface type='bridge'>
      <mac address='d0:0d:54:6a:09:9e'/>
      <source bridge='xenbr0'/>
      <script path='vif-bridge'/>
      <target dev='vif53.0'/>
    </interface>
    <serial type='file'>
      <source path='/opt/awcloud/instance/admin/i-546A099E/console.log'/>
      <target port='0'/>
    </serial>
    <console type='file'>
      <source path='/opt/awcloud/instance/admin/i-546A099E/console.log'/>
      <target port='0'/>
    </console>
    <input type='tablet' bus='usb'/>
    <input type='mouse' bus='ps2'/>
    <graphics type='vnc' port='17237' autoport='no'/>
  </devices>
</domain>

Domain maxMen allowed: 147456
Domain memory: 139140
Domain state: VIR_DOMAIN_BLOCKED
Domain network autostart: false
cpu: 31
cpu time: 2225977676675
cpu number: 0
cpu state: VIR_VCPU_BLOCKED
Domain network autostart: false
Inactive domain name: i-46A70811
Inactive domain name: i-38C20705
Inactive domain name: i-498E09B2
Inactive domain name: null
Inactive domain name: null
Inactive domain name: null
Inactive domain name: null
Inactive domain name: null

结果分析: 结果中基本包含了一个虚拟机组成的全部元素信息。如果你想做一个监控系统,你可以发现这里有

  • 虚拟机的名字
  • 虚拟机的Id
  • 虚拟机的内存大小
  • 虚拟CPU个数
  • 虚拟机磁盘文件信息,磁盘文件的大小。甚至包括log等信息。
  • 虚拟磁盘读写速率。
  • 虚拟机网络设备信息。Mac地址,设备类型等。
  • 虚拟机网卡读写速率。

基本可以满足一个监控系统的需求。 解释一下上面的测试代码。libvirt Java API的入口基本都是通过Connect这个类,也就是首先建立与被管理主机之间的连接

Connect kvmConn = new Connect("qemu+tcp://10.4.54.10/system");

然后通过该连接获取信息:

conn.listDomains()

一个接口的如果需要接受参数:

conn.domainLookupByID(activeDomId)

肯定可以从其他的接口返回中找到答案:

for (int activeDomId : conn.listDomains())

只是有的获取的直接,有可能需要解析xml格式的返回值来获取需要参数值。比如:disk的path和interface的path。 最后再简单介绍一下管控接口:

  /**
	 * 测试虚拟机的简单操作
	 * 
	 * @author lihzh
	 * @date 2012-5-16 下午3:35:43
	 */
	@Test
	public void testControlVM() {
		try {
			Domain domain = kvmConn.domainLookupByID(8);
			System.out.println("Domain state: " + domain.getInfo().state);
			domain.suspend();
			System.out.println("Domain state: " + domain.getInfo().state);
			for (int i = 0; i < 5; i++) {
				System.out.println("wait for: " + (5 - i));
				Thread.sleep(1000);
			}
			System.out.println("Resume vm.");
			domain.resume();
			System.out.println("Domain state: " + domain.getInfo().state);
		} catch (LibvirtException e) {
			e.printStackTrace();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

该用例主要测试了虚拟机的挂起和恢复操作。这类操作是比较简单的(因为无需参数)。一个复杂系统肯定需要包括虚拟机创建等操作。libvirt主要通过xml表述来创建资源,首先需要生成被创建虚拟机的完整描述,然后传递给创建的方法即可。描述的格式?呵呵,自然是上面测试结果给出的数据了。有兴趣的,大家可以自己尝试一下。libvirt的文档,还不完善,不过对于创建这样重要的功能,还是给出了说明。大家也可以下载官方的手册作为参考。

好了,相对于VMware、Xenserver等虚拟化平台的SDK,libvirt的Java API还是比较简单的,上手很快,结构很简单。当然,功能上可能还是有所欠缺,信息量上,没有其他的那么充足。基于XML的方式操作资源,减少了接口的个数,使调用更直接,但是对开发人员却增加了困难。不过仍不失为一个不错的虚拟机环境操作的API,尤其是针对KVM/XEN的环境来说,可谓不二的选择。

阅读全文 »

Windows下Libvirt Java API使用教程 - 开发环境部署

发表于 2012-06-19

Libvirt是一个优秀的虚拟化环境管理的工具包。核心用c实现,不过提供了不同语言的调用API。官网的简介如下:

libvirt is:

  • A toolkit to interact with the virtualization capabilities of recent versions of Linux (and other OSes), see our project goals for details.
  • Free software available under the GNU Lesser General Public License.
  • A long term stable C API
  • A set of bindings for common languages
  • A CIM provider for the DMTF virtualization schema
  • A QMF agent for the AMQP/QPid messaging system

libvirt supports:

  • The KVM/QEMU Linux hypervisor
  • The Xen hypervisor on Linux and Solaris hosts.
  • The LXC Linux container system
  • The OpenVZ Linux container system
  • The User Mode Linux paravirtualized kernel
  • The VirtualBox hypervisor
  • The VMware ESX and GSX hypervisors
  • The VMware Workstation and Player hypervisors
  • The Microsoft Hyper-V hypervisor
  • Virtual networks using bridging, NAT, VEPA and VN-LINK.
  • Storage on IDE/SCSI/USB disks, FibreChannel, LVM, iSCSI, NFS and filesystems

libvirt provides:

  • Remote management using TLS encryption and x509 certificates
  • Remote management authenticating with Kerberos and SASL
  • Local access control using PolicyKit
  • Zero-conf discovery using Avahi multicast-DNS
  • Management of virtual machines, virtual networks and storage
  • Portable client API for Linux, Solaris and Windows

由于我只是一个简单而纯粹的Java程序员,所以自然只能依赖于libvirt的Java binding api。

作为一个源码控,我选择下载源码的方式验证使用,git仓库:

  • git clone git://libvirt.org/libvirt-java.git

笔者下载源码后,直接构建了Eclipse的工程,当然你也可以用源码编译(ant)出一份jar来依赖:

cd libvirt-java
ant build

http://www.libvirt.org/maven2/ 没有Maven?可以直接从Maven库中下载Jar包,如 http://www.libvirt.org/maven2/org/libvirt/libvirt/

这么多途径,相信你总可以搞到一份libvirt的源码或者Jar了吧。

由于libvirt的核心都是c写的,Java API只是帮助你封装了对动态链接库(dll)文件的本地调用,所以现在应该做的是安装dll文件。libvirt官网提供了自行编译dll文件的脚本:

The easiest way is to use the msys_setup script, developed by Matthias Bolte. This is actively developed and kept current with libvirt releases, https://github.com/photron/msys_setup

不过笔者并没有尝试该种方式,因为libvirt官网也提供了windows下的安装包:

A windows installation package is in development. An experimental version is available here: http://libvirt.org/sources/win32_experimental/Libvirt-0.8.8-0.exe It is not production ready.(注:其并不是已经发布的产品)

该安装包中不仅包含了需要的dll文件,还提供了一个方便好用的virsh-shell 命令行工具,通过命令可以调用libvirt的所有接口(查看,管理虚拟机等。),对于我们的开发调试是非常有帮助的。

安装完成后,想让Java API找到dll文件,还需要指定jna路径,有两种方式,一种是直接设置系统环境变量:

另一种是可在程序中动态指定,笔者选择了后者,比较灵活简单,编写测试代码如下

public void testGetXenVMs() {
		try {
- System.setProperty("jna.library.path", "D:/Git-Repo/git/libvirt-java/libvirt-java/src/test/java/kubi/coder/");
- Connect conn = new Connect("xen+tcp://10.4.55.203/");
- System.out.println(conn.nodeInfo().cores);
- for (String name : conn.listDefinedDomains()) {
- 	System.out.println(name);
- 	if (name != null) {
- 		Domain domain = conn.domainLookupByName(name);
- 		System.out.println(domain.getMaxMemory());
- 		System.out.println(domain.getUUIDString());
- 		System.out.println(domain.getInfo().maxMem);
- 		System.out.println(domain.getInfo().state);
- 		System.out.println(conn.listDomains().length);
- 	}
- }
		} catch (LibvirtException e) {
- e.printStackTrace();
		}
	}

是不是还是找不到dll?报异常

Exception in thread “main” java.lang.UnsatisfiedLinkError: Unable to load library ‘virt’

原来他是搜索叫virt的dll文件。

查看源码

Libvirt INSTANCE = (Libvirt) Native.loadLibrary("virt", Libvirt.class);

原来如此,将libvirt-0.dll改名为virt.dll。结果终于出来了。

注:libvirt的Java API封装的比较直观,上手很容易,其入口就是Connect 这个连接类,获取连接后,即可对虚拟机环境进行查看和管理操作。笔者后续会奉上Java API详细使用介绍。

阅读全文 »

教你打包Java程序,jar转exe随处可跑

发表于 2012-06-16

发现很多人问如何把Jar转成exe程序。可能是想双击运行和随处运行。其实这个并不难,我就简单总结几种方法,供大家参考,关键还是要知其所以然。

Java程序的运行不可能脱离JRE,不管你是Jar包还是exe程序。这点你必须了解。那么在没有JRE的机器上你的程序怎么跑?很简单,在你程序里带一份JRE就行了。

先介绍集中打包的方法。以Eclipse为例,最简单直接的方法,选择你想打包的程序,右键export…

选择Runnable Jar file。(即可执行的Jar包)

选择你程序的主类,就是还有Main函数的类。点Finish即可。

在你的机器上,设置好Jar文件的打开方式(别默认用解压缩的工具打开就行),双击即可运行。

这个跟在命令行执行命令的效果是一样的。

java -jar forfun.jar

其实一个Jar能运行,关键还是配置Jar内部的MANIFEST.MF文件。该文件存在于Jar包根目录的META-INF文件夹内。主要由于指定主类(Main)的位置:

Manifest-Version: 1.0
Main-Class: one.coder.jdk.JDKMain

版本可以自己指定,默认生成是1.0。主类位置需要指定。

注意:Main-Class的冒号后,要跟一个空格。

如果你还有要依赖的Jar包,则可以配置Class-Path来指定。

Class-Path: ./ logback-core-0.9.29.jar junit-4.9.jar slf4j-api-1.6.1.jar logback-classic-0.9.29.jar hamcrest-core-1.1.jar

知道了这些,我们再打开刚才生成的Jar文件,你可能发现多了一些Eclipse的东西,并且主类变成了

Main-Class: org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader

也就是通过Eclipse提供的这个主类来加载的你程序。如果你不喜欢这样,将其去掉。自己进行配置。笔者通过一个不依赖任何Jar包的小程序进行说明。

这是笔者打出Jar的内部截图,去掉所有跟我的程序不相关的东西。MANIFEST.MF的配置也很简单。

Manifest-Version: 1.0
Main-Class: one.coder.jdk.JDKMain

在有JRE的机器上,双击一样可以运行。

注:这里需要提一下,尽量不用用解压软件自带的编辑器进行编辑,如果你编辑后发现不能运行,提示打开jar错误等信息,很可能是由于你编辑的MANIFEST.MF文件的编码错误。导致无法解析。默认是采用ANSI编码格式的。不要改成UTF-8等。笔者被这个问题,困扰了近半个小时。

接下来说说在没有JRE的机器上怎么办?最简单的手动的办法就是写一个bat脚本。并且带一份jre在你的程序里。

把图中的三个文件,放入同一个文件夹中。start.bat内容如下:

.\jre7\bin\java -jar .\run.jar

说白了就是调用jre中的java命令,执行指定的jar程序。 双击start.bat,执行成功。

如果你非要打成exe程序,笔者推荐一个工具JSmooth。简单好用。同样这也肯定是需要JRE指定的。关于JSmooth的教程,笔者找到了一个不错的教学贴:http://yisufuyou.iteye.com/blog/403556 按照里面的步骤,你一定可以成功。

说了这么多,如果还有什么不明白的,可以给我留言,一起讨论研究。

  • PS1:默认的JRE体积实在太大,你可以考虑精简JRE还节约空间,这部分内容,不在本文讨论。另外,如果你想把你的软件做成安装包的形势,可考虑InstallAnyWhere这个工具。

  • PS2:笔者研究的过程中,为了模拟没有JRE的环境,真是百般折腾,因为笔者把所有环境变量都删掉,还有可以运行。不知道是不是从JDK7开始,Java居然在我的System32路径下,也放置Java.exe等程序,也就是说,不用配置Path了。jre路径的指定,貌似也写入了注册表,不过这点,笔者没有亲自证实,只是在注册表中简单的搜索了一下,仅发现了JavaFX的配置和一些其他的Java配置,没有深入研究,不好定论。有兴趣可以研究下,也麻烦告诉我一声。

阅读全文 »

Logback控制台输出类名行号带链接的Pattern配置

发表于 2012-06-14

从log4j切换到logback会发现,原来在log4j使用的日志格式 %l 的功能不见了。Eclipse控制台的输出,不再带有可快速进入的链接了。

在logback里,需要使用%c%L才能打印出完整的类路径和行号。但是却没有链接。查阅了一下,发现了caller这个Pattern。配置好caller:%caller{1}后,链接终于又出现了。效果如下:

虽然感觉上,没原来的好看了,不过好歹,这个功能是有了。如果你想去掉烦人的Caller+0字样,还可以继续使用replace进行替换。

附上笔者使用的logback pattern配置:

%d{yyyy/MM/dd-HH:mm:ss} %level [%thread] %caller{1} - %msg%n

关于logback pattern 转换符的说明,我找到了这个帖子,说的还是比较详细的

  • http://aub.iteye.com/blog/1103685
阅读全文 »

未初始化的String相 "+" 为什么会打印出“nullnull"

发表于 2012-06-14

今天在我的一个qq群里有人问了这样一个问题。

private static String a;

private static String b;

public static void main(String[] args) {

    String c = a+b;

    System.out.println(c);

}

输出是nullnull。问为什么是这样。

其实问题并不复杂,很多同学也觉得自己知道原因,遂不予关注。但是我相信还是有初学Java的同学在这里是存在误会的。很典型的误会就是如一个群里的朋友说的String类型的变量如果没有显示初始化,默认的值就是”null”。支持的理由就是

private static String a;

public static void main(String[] args) {

System.out.println(a);

}

输出是null。

这个现象确实很容易迷惑一些初学的人,包括我也忽略了挺久。其实呢证明这种想法错误很简单。如果默认值是null,那么就意味着,该变量不是空(null)。而是字符串的“null”。

private static String a;

public static void main(String[] args) {

System.out.println(a==null);

System.out.println("null".equals(a));

}

上述代码输出分别是true,false。(呵呵,挺弱智的。)

说明String类型变量a,其实是空(null),而并没有被赋值。那么打印出null是为什么呢?我们查看PrintStream的源码就很清晰的明白了,其实是Java在println的时候进行了处理。

public void print(String s) {

if (s == null) {

s = "null";

}

write(s);

}

回到开头的问题,既然没有初始化赋值,那么输出为什么是”nullnull“,两个”null“连接的结果呢。这里略微细说一下,查看编译过的class文件,我们可以看到

public static void main(java.lang.String[] args);

0 new java.lang.StringBuilder [19]

3 dup

4 getstatic cn.home.pratice.jdk.string.StringMain.a : java.lang.String [21]

7 invokestatic java.lang.String.valueOf(java.lang.Object) : java.lang.String [23]

10 invokespecial java.lang.StringBuilder(java.lang.String) [29]

13 getstatic cn.home.pratice.jdk.string.StringMain.b : java.lang.String [32]

16 invokevirtual java.lang.StringBuilder.append(java.lang.String) : java.lang.StringBuilder [34]

19 invokevirtual java.lang.StringBuilder.toString() : java.lang.String [38]

22 astore_1 [c][/c]

23 getstatic java.lang.System.out : java.io.PrintStream [42]

26 aload_1 [c][/c]

27 invokevirtual java.io.PrintStream.println(java.lang.String) : void [48]

30 return System.out.println(c);

}

String的相加实际在变异后被处理成了StringBuilder的append.(注:我的JDK是1.6.0_u29)。那么好,我们就应该查看StringBuilder的源码,发现是调用的父类里的方法,继续查看,道理就在这里。

public StringBuilder append(String str) {

super.append(str);

return this;

}

public AbstractStringBuilder append(String str) {

if (str == null) str = "null";

int len = str.length();

if (len == 0) return this;

int newCount = count + len;

if (newCount &gt; value.length)

expandCapacity(newCount);

str.getChars(0, len, value, count);

count = newCount;

return this;

}

原来也是对空null,进行了特殊的处理,那么输出是”nullnull“,自然也就明白了。

这里我想说的是,很多问题,可能表面上很简单,或者我们可能会有很多想当然的想法,不过还是眼见为实,而且所有代码都放在那里,我们为什么不勤快的多翻开看看其中的实现,道理自然就在眼前。多动手,丰衣足食:)

阅读全文 »
1 … 32 33 34 … 36
LiHongZhe

LiHongZhe

onecoder's blog.

354 日志
8 分类
RSS
Creative Commons
Links
  • 酷壳
  • 煮酒品茶
  • 小弟子的网络之路
  • 图表秀-在线图表制作
© 2012 - 2023 LiHongZhe
由 Jekyll 强力驱动
主题 - NexT.Muse
本站访客数 人次 本站总访问量 次