??xml version="1.0" encoding="utf-8" standalone="yes"?>久久久国产一区二区三区四区小说,一区二区久久久久,欧美久色视频http://www.aygfsteel.com/kingwell/category/10891.htmlAspire to Professionalismzh-cnFri, 02 Mar 2007 06:41:38 GMTFri, 02 Mar 2007 06:41:38 GMT60Java Reflectionhttp://www.aygfsteel.com/kingwell/articles/51747.htmlKingWellKingWellFri, 09 Jun 2006 09:37:00 GMThttp://www.aygfsteel.com/kingwell/articles/51747.htmlhttp://www.aygfsteel.com/kingwell/comments/51747.htmlhttp://www.aygfsteel.com/kingwell/articles/51747.html#Feedback0http://www.aygfsteel.com/kingwell/comments/commentRss/51747.htmlhttp://www.aygfsteel.com/kingwell/services/trackbacks/51747.html
Java 的这一能力在实际应用中也许用得不是很多Q但是在其它的程序设计语a中根本就不存在这一Ҏ(gu)。例如,Pascal、C 或?C++ 中就没有办法在程序中获得函数定义相关的信息?br />
JavaBean ?reflection 的实际应用之一Q它能让一些工具可视化的操作Y件组件。这些工具通过 reflection 动态的载入q取?Java lg(c? 的属性?br />


1. 一个简单的例子

考虑下面q个单的例子Q让我们看看 reflection 是如何工作的?br />
import java.lang.reflect.*;
public class DumpMethods {
    public static void main(String args[]) {
        try {
            Class c = Class.forName(args[0]);
            Method m[] = c.getDeclaredMethods();
            for (int i = 0; i < m.length; i++)
                System.out.println(m[i].toString());
        } catch (Throwable e) {
            System.err.println(e);
        }
    }
}

按如下语句执行:(x)

java DumpMethods java.util.Stack

它的l果输出为:(x)

public java.lang.Object java.util.Stack.push(java.lang.Object)

public synchronized java.lang.Object java.util.Stack.pop()

public synchronized java.lang.Object java.util.Stack.peek()

public boolean java.util.Stack.empty()

public synchronized int java.util.Stack.search(java.lang.Object)

q样列Zjava.util.Stack cȝ各方法名以及(qing)它们的限制符和返回类型?br />
q个E序使用 Class.forName 载入指定的类Q然后调?getDeclaredMethods 来获取这个类中定义了的方法列表。java.lang.reflect.Methods 是用来描q某个类中单个方法的一个类?br />
2.开始?Reflection

用于 reflection 的类Q如 MethodQ可以在 java.lang.relfect 包中扑ֈ。用这些类的时候必要遵@三个步骤Q第一步是获得你想操作的类?java.lang.Class 对象。在q行中的 Java E序中,?java.lang.Class cL描述cd接口{?br />
下面是获得一?Class 对象的方法之一Q?br />
Class c = Class.forName("java.lang.String");

q条语句得到一?String cȝcd象。还有另一U方法,如下面的语句Q?br />
Class c = int.class;

或?br />
Class c = Integer.TYPE;

它们可获得基本类型的cM息。其中后一U方法中讉K的是基本cd的封装类 (?Integer) 中预先定义好?TYPE 字段?br />
W二步是调用诸如 getDeclaredMethods 的方法,以取得该cM定义的所有方法的列表?br />
一旦取得这个信息,可以进行第三步了——?reflection API 来操作这些信息,如下面这D代码:(x)

Class c = Class.forName("java.lang.String");

Method m[] = c.getDeclaredMethods();

System.out.println(m[0].toString());

它将以文本方式打印出 String 中定义的W一个方法的原型?br />
在下面的例子中,q三个步骤将Z?reflection 处理Ҏ(gu)应用E序提供例证?br />
模拟 instanceof 操作W?br />
得到cM息之后,通常下一个步骤就是解军_?Class 对象的一些基本的问题。例如,Class.isInstance Ҏ(gu)可以用于模拟 instanceof 操作W:(x)

class A {
}

public class instance1 {
    public static void main(String args[]) {
        try {
            Class cls = Class.forName("A");
            boolean b1 = cls.isInstance(new Integer(37));
            System.out.println(b1);
            boolean b2 = cls.isInstance(new A());
            System.out.println(b2);
        } catch (Throwable e) {
            System.err.println(e);
        }
    }
}

在这个例子中创徏了一?A cȝ Class 对象Q然后检查一些对象是否是 A 的实例。Integer(37) 不是Q但 new A() 是?br />
3.扑ևcȝҎ(gu)

扑և一个类中定义了些什么方法,q是一个非常有价g非常基础?reflection 用法。下面的代码实Cq一用法Q?br />
import java.lang.reflect.*;

public class method1 {
    private int f1(Object p, int x) throws NullPointerException {
        if (p == null)
            throw new NullPointerException();
        return x;
    }

    public static void main(String args[]) {
        try {
            Class cls = Class.forName("method1");
            Method methlist[] = cls.getDeclaredMethods();
            for (int i = 0; i < methlist.length; i++) {
                Method m = methlist[i];
                System.out.println("name = " + m.getName());
                System.out.println("decl class = " + m.getDeclaringClass());
                Class pvec[] = m.getParameterTypes();
                for (int j = 0; j < pvec.length; j++)
                    System.out.println("param #" + j + " " + pvec[j]);
                Class evec[] = m.getExceptionTypes();
                for (int j = 0; j < evec.length; j++)
                    System.out.println("exc #" + j + " " + evec[j]);
                System.out.println("return type = " + m.getReturnType());
                System.out.println("-----");
            }
        } catch (Throwable e) {
            System.err.println(e);
        }
    }
}

q个E序首先取得 method1 cȝ描述Q然后调?getDeclaredMethods 来获取一pd?Method 对象Q它们分别描qC定义在类中的每一个方法,包括 public Ҏ(gu)、protected Ҏ(gu)、package Ҏ(gu)?private Ҏ(gu){。如果你在程序中使用 getMethods 来代?getDeclaredMethodsQ你q能获得l承来的各个Ҏ(gu)的信息?br />
取得?Method 对象列表之后Q要昄q些Ҏ(gu)的参数类型、异常类型和q回值类型等׃难了。这些类型是基本cdq是cȝ型,都可以由描述cȝ对象按顺序给出?br />
输出的结果如下:(x)

name = f1

decl class = class method1

param #0 class java.lang.Object

param #1 int

exc #0 class java.lang.NullPointerException

return type = int

-----

name = main

decl class = class method1

param #0 class [Ljava.lang.String;

return type = void

-----


4.获取构造器信息

获取cL造器的用法与上述获取Ҏ(gu)的用法类|如:(x)

import java.lang.reflect.*;

public class constructor1 {
    public constructor1() {
    }

    protected constructor1(int i, double d) {
    }

    public static void main(String args[]) {
        try {
            Class cls = Class.forName("constructor1");
            Constructor ctorlist[] = cls.getDeclaredConstructors();
            for (int i = 0; i < ctorlist.length; i++) {
                Constructor ct = ctorlist[i];
                System.out.println("name = " + ct.getName());
                System.out.println("decl class = " + ct.getDeclaringClass());
                Class pvec[] = ct.getParameterTypes();
                for (int j = 0; j < pvec.length; j++)
                    System.out.println("param #" + j + " " + pvec[j]);
                Class evec[] = ct.getExceptionTypes();
                for (int j = 0; j < evec.length; j++)
                    System.out.println("exc #" + j + " " + evec[j]);
                System.out.println("-----");
            }
        } catch (Throwable e) {
            System.err.println(e);
        }
    }
}

q个例子中没能获得返回类型的相关信息Q那是因为构造器没有q回cd?br />
q个E序q行的结果是Q?br />
name = constructor1

decl class = class constructor1

-----

name = constructor1

decl class = class constructor1

param #0 int

param #1 double

-----

5.获取cȝ字段(?

扑և一个类中定义了哪些数据字段也是可能的,下面的代码就在干q个事情Q?br />

import java.lang.reflect.*;

public class field1 {
    private double d;
    public static final int i = 37;
    String s = "testing";

    public static void main(String args[]) {
        try {
            Class cls = Class.forName("field1");
            Field fieldlist[] = cls.getDeclaredFields();
            for (int i = 0; i < fieldlist.length; i++) {
                Field fld = fieldlist[i];
                System.out.println("name = " + fld.getName());
                System.out.println("decl class = " + fld.getDeclaringClass());
                System.out.println("type = " + fld.getType());
                int mod = fld.getModifiers();
                System.out.println("modifiers = " + Modifier.toString(mod));
                System.out.println("-----");
            }
        } catch (Throwable e) {
            System.err.println(e);
        }
    }
}

q个例子和前面那个例子非常相伹{例中用了一个新东西 ModifierQ它也是一?reflection c,用来描述字段成员的修饰语Q如“private int”。这些修饰语自n由整数描qͼ而且使用 Modifier.toString 来返回以“官方”顺序排列的字符串描q?(如“static”在“final”之?。这个程序的输出是:(x)

name = d

decl class = class field1

type = double

modifiers = private

-----

name = i

decl class = class field1

type = int

modifiers = public static final

-----

name = s

decl class = class field1

type = class java.lang.String

modifiers =

-----

和获取方法的情况一下,获取字段的时候也可以只取得在当前cMx了的字段信息 (getDeclaredFields)Q或者也可以取得父类中定义的字段 (getFields) ?br />

6.Ҏ(gu)Ҏ(gu)的名U来执行Ҏ(gu)

文本到这里,所丄例子无一例外都与如何获取cȝ信息有关。我们也可以?reflection 来做一些其它的事情Q比如执行一个指定了名称的方法。下面的CZ演示了这一操作Q?br />
import java.lang.reflect.*;
public class method2 {
    public int add(int a, int b) {
        return a + b;
    }
    public static void main(String args[]) {
        try {
            Class cls = Class.forName("method2");
            Class partypes[] = new Class[2];
            partypes[0] = Integer.TYPE;
            partypes[1] = Integer.TYPE;
            Method meth = cls.getMethod("add", partypes);
            method2 methobj = new method2();
            Object arglist[] = new Object[2];
            arglist[0] = new Integer(37);
            arglist[1] = new Integer(47);
            Object retobj = meth.invoke(methobj, arglist);
            Integer retval = (Integer) retobj;
            System.out.println(retval.intValue());
        } catch (Throwable e) {
            System.err.println(e);
        }
    }
}

假如一个程序在执行的某处的时候才知道需要执行某个方法,q个Ҏ(gu)的名U是在程序的q行q程中指定的 (例如QJavaBean 开发环境中׃(x)做这L(fng)?Q那么上面的E序演示了如何做到?br />
上例中,getMethod 用于查找一个具有两个整型参C名ؓ(f) add 的方法。找到该Ҏ(gu)q创Z相应?Method 对象之后Q在正确的对象实例中执行它。执行该Ҏ(gu)的时候,需要提供一个参数列表,q在上例中是分别包装了整?37 ?47 的两?Integer 对象。执行方法的q回的同h一?Integer 对象Q它?yu)装了返回?84?br />
7.创徏新的对象

对于构造器Q则不能像执行方法那栯行,因ؓ(f)执行一个构造器意味着创徏了一个新的对?(准确的说Q创Z个对象的q程包括分配内存和构造对?。所以,与上例最怼的例子如下:(x)

import java.lang.reflect.*;

public class constructor2 {
    public constructor2() {
    }

    public constructor2(int a, int b) {
        System.out.println("a = " + a + " b = " + b);
    }

    public static void main(String args[]) {
        try {
            Class cls = Class.forName("constructor2");
            Class partypes[] = new Class[2];
            partypes[0] = Integer.TYPE;
            partypes[1] = Integer.TYPE;
            Constructor ct = cls.getConstructor(partypes);
            Object arglist[] = new Object[2];
            arglist[0] = new Integer(37);
            arglist[1] = new Integer(47);
            Object retobj = ct.newInstance(arglist);
        } catch (Throwable e) {
            System.err.println(e);
        }
    }
}

Ҏ(gu)指定的参数类型找到相应的构造函数ƈ执行它,以创Z个新的对象实例。用这U方法可以在E序q行时动态地创徏对象Q而不是在~译的时候创建对象,q一炚w常有价倹{?br />
8.改变字段(?的?br />
reflection 的还有一个用处就是改变对象数据字D늚倹{reflection 可以从正在运行的E序中根据名U找到对象的字段q改变它Q下面的例子可以说明q一点:(x)

import java.lang.reflect.*;

public class field2 {
    public double d;

    public static void main(String args[]) {
        try {
            Class cls = Class.forName("field2");
            Field fld = cls.getField("d");
            field2 f2obj = new field2();
            System.out.println("d = " + f2obj.d);
            fld.setDouble(f2obj, 12.34);
            System.out.println("d = " + f2obj.d);
        } catch (Throwable e) {
            System.err.println(e);
        }
    }
}

q个例子中,字段 d 的D变ؓ(f)?12.34?br />
9.使用数组

本文介绍?reflection 的最后一U用法是创徏的操作数l。数l在 Java 语言中是一U特D的cȝ型,一个数l的引用可以赋给 Object 引用。观察下面的例子看看数组是怎么工作的:(x)

import java.lang.reflect.*;

public class array1 {
    public static void main(String args[]) {
        try {
            Class cls = Class.forName("java.lang.String");
            Object arr = Array.newInstance(cls, 10);
            Array.set(arr, 5, "this is a test");
            String s = (String) Array.get(arr, 5);
            System.out.println(s);
        } catch (Throwable e) {
            System.err.println(e);
        }
    }
}

例中创徏?10 个单位长度的 String 数组Qؓ(f)W?5 个位|的字符串赋了|最后将q个字符串从数组中取得ƈ打印了出来?br />
下面q段代码提供了一个更复杂的例子:(x)

import java.lang.reflect.*;

public class array2 {
    public static void main(String args[]) {
        int dims[] = new int[]{5, 10, 15};
        Object arr = Array.newInstance(Integer.TYPE, dims);
        Object arrobj = Array.get(arr, 3);
        Class cls = arrobj.getClass().getComponentType();
        System.out.println(cls);
        arrobj = Array.get(arrobj, 5);
        Array.setInt(arrobj, 10, 37);
        int arrcast[][][] = (int[][][]) arr;
        System.out.println(arrcast[3][5][10]);
    }
}
例中创徏了一?5 x 10 x 15 的整型数l,qؓ(f)处于 [3][5][10] 的元素赋了gؓ(f) 37。注意,多维数组实际上就是数l的数组Q例如,W一?Array.get 之后Qarrobj 是一?10 x 15 的数l。进而取得其中的一个元素,即长度ؓ(f) 15 的数l,q?Array.setInt 为它的第 10 个元素赋倹{?br />
注意创徏数组时的cd是动态的Q在~译时ƈ不知道其cd?br />


作者BlogQhttp://blog.csdn.net/leek2000/

KingWell 2006-06-09 17:37 发表评论
]]>
ldap介绍http://www.aygfsteel.com/kingwell/articles/46269.htmlKingWellKingWellMon, 15 May 2006 11:18:00 GMThttp://www.aygfsteel.com/kingwell/articles/46269.htmlhttp://www.aygfsteel.com/kingwell/comments/46269.htmlhttp://www.aygfsteel.com/kingwell/articles/46269.html#Feedback0http://www.aygfsteel.com/kingwell/comments/commentRss/46269.htmlhttp://www.aygfsteel.com/kingwell/services/trackbacks/46269.htmlQ-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-

介绍LDAP
原文Qhttp://ldapman.org/articles/intro_to_ldap.html
原文作者:(x)Michael Donnelly
译QBrimmer
如果你在计算业工作,那么对LDAP可能早有耳闻了。想深入C解LDAP吗?那么可以好好地读一下这文章。这介l性的文章是一pd介绍如何在企业中设计、实现和集成LDAP环境的文章的头一。主要是先让你熟(zhn)一下LDAP的基本概念,那些比较困难的细节问题将攑ֈ以后讨论。在q篇文章中我们将要介l:(x)
什么是LDAP?
什么时候该用LDAP存储数据Q?br />LDAP目录?wi)的l构
单独的LDAP记录
作ؓ(f)例子的一个单独的数据?br />LDAP复制
安全和访问控?br />现在LDAP技术不仅发展得很快而且也是Ȁ动h心的。在企业范围内实现LDAP可以让运行在几乎所有计机q_上的所有的应用E序从LDAP目录中获取信息。LDAP目录中可以存储各U类型的数据Q电(sh)子邮件地址、邮件\׃息、h力资源数据、公用密匙、联pMh列表Q等{。通过把LDAP目录作ؓ(f)pȝ集成中的一个重要环节,可以化员工在企业内部查询信息的步骤,甚至q主要的数据源都可以攑֜M地方。如果Oracle、Sybase、Informix或Microsoft SQL数据库中已经存储了类似的数据Q那么LDAP和这些数据库到底有什么不同呢Q是什么让它更具优势?L(fng)l读下去吧!
什么是LDAP?
LDAP的英文全U是Lightweight Directory Access ProtocolQ一般都UCؓ(f)LDAP。它是基于X.500标准的,但是单多了ƈ且可以根据需要定制。与X.500不同QLDAP支持TCP/IPQ这对访问Internet是必ȝ。LDAP的核心规范在RFC中都有定义,所有与LDAP相关的RFC都可以在LDAPman RFC|页中找到?br />怎么使用LDAPq个术语呢?
在日怺谈中Q你可能?x)听到有些hq么_(d)(x)“我们要把那些东西存在LDAP中吗Q”,或者“从LDAP数据库中取出那些数据Q”,又或者“我们怎么把LDAP和关pd数据库集成在一P”。严格地_(d)LDAPҎ(gu)不是数据库而是用来讉K存储在信息目录(也就是LDAP目录Q中的信息的协议。更为确切和正式的说法应该是象这L(fng)Q“通过使用LDAPQ可以在信息目录的正位|读取(或存储)(j)数据”。但是,也没有必要吹毛求疵,管表达得不够准,我们也都知道Ҏ(gu)在说什么?br />LDAP目录是数据库吗?
pSybase、Oracle、Informix或Microsoft的数据库理pȝQDBMSQ是用于处理查询和更新关pd数据库那PLDAP服务器也是用来处理查询和更新LDAP目录的。换句话来说LDAP目录也是一U类型的数据库,但是不是关系型数据库。不象被设计成每分钟需要处理成百上千条数据变化的数据库Q例如:(x)在电(sh)子商务中l常用到的在U交易处理(OLTPQ系l,LDAP主要是优化数据读取的性能?br />LDAP目录的优?br />现在该说说LDAP目录到底有些什么优势了。现在LDAP的流行是很多因数共同作用的结果。我在这里说的不q是一些基本的原因Q请你注意一下这不过是一部分原因?br />可能LDAP最大的优势是:(x)可以在Q何计机q_上,用很Ҏ(gu)获得的而且数目不断增加的LDAP的客L(fng)E序讉KLDAP目录。而且也很Ҏ(gu)定制应用E序为它加上LDAP的支持?br />LDAP协议是跨q_的和标准的协议,因此应用E序׃用ؓ(f)LDAP目录攑֜什么样的服务器上操心了。实际上QLDAP得到了业界的q泛认可Q因为它是Internet的标准。商都很愿意在产品中加入对LDAP的支持,因ؓ(f)他们Ҏ(gu)不用考虑另一端(客户端或服务端)(j)是怎么L(fng)。LDAP服务器可以是M一个开发源代码或商用的LDAP目录服务器(或者还可能是具有LDAP界面的关pd数据库)(j)Q因为可以用同样的协议、客L(fng)q接软g包和查询命o(h)与LDAP服务器进行交互。与LDAP不同的是Q如果Y件商想在Y件品中集成对DBMS的支持,那么通常都要Ҏ(gu)一个数据库服务器单独定制?br />不象很多商用的关pd数据库,你不必ؓ(f)LDAP的每一个客L(fng)q接或许可协议付贏V?br />大多数的LDAP服务器安装v来很单,也容易维护和优化?br />LDAP服务器可以用“推”或“拉”的Ҏ(gu)复制部分或全部数据,例如Q可以把数据“推”到q程的办公室Q以增加数据的安全性。复制技术是内置在LDAP服务器中的而且很容易配|。如果要在DBMS中用相同的复制功能Q数据库产商׃(x)要你支付额外的费用,而且也很隄理?br />LDAP允许你根据需要用ACIQ一般都UCؓ(f)ACL或者访问控制列表)(j)控制Ҏ(gu)据读和写的权限。例如,讑֤理员可以有权改变员工的工作地点和办公室L(fng)Q但是不允许改变记录中其它的域。ACI可以Ҏ(gu)谁访问数据、访问什么数据、数据存在什么地方以?qing)其它对数据q行讉K控制。因些都是由LDAP目录服务器完成的Q所以不用担心在客户端的应用E序上是否要q行安全(g)查?br />LDAP对于q样存储q样的信息最为有用,也就是数据需要从不同的地点读取,但是不需要经常更新。例如,q些信息存储在LDAP目录中是十分有效的:(x)
l        公司员工的电(sh)话号码簿和组l结构图
l        客户的联pM?br />l        计算机管理需要的信息Q包括NIS映射、email假名Q等{?br />l        软g包的配置信息
l        公用证书和安全密?br />什么时候该用LDAP存储数据Q?br />大多数的LDAP服务器都密集型的操作q行专门的优化。因此,当从LDAP服务器中d数据的时候会(x)比从专门为OLTP优化的关pd数据库中d数据快一个数量。也是因Z门ؓ(f)ȝ性能q行优化Q大多数的LDAP目录服务器ƈ不适合存储需要需要经常改变的数据。例如,用LDAP服务器来存储?sh)话L(fng)是一个很好的选择Q但是它不能作ؓ(f)?sh)子商务站点的数据库服务器?br />如果下面每一个问题的{案都是“是”,那么把数据存在LDAP中就是一个好L?br />l        需要在Mq_上都能读取数据吗Q?br />l        每一个单独的记录Ҏ(gu)不是每一天都只有很少的改变?
l        可以把数据存在^面数据库Qflat databaseQ而不是关pd数据库中吗?换句话来_(d)也就是不什么范式不范式的,把所有东襉K存在一个记录中Q差不多只要满W一范式Q?br />最后一个问题可能会(x)唬住一些hQ其实用q面数据库去存储一些关pd的数据也是很一般的。例如,一条公司员工的记录可以包含经理的d名。用LDAP来存储这cM息是很方便的。一个简单的判断Ҏ(gu)Q如果可以把保数据存在一张张的卡片里Q就可以很容易地把它存在LDAP目录里?br />LDAP目录?wi)的l构
LDAP目录以树(wi)状的层次l构来存储数据。如果你对自向下的DNS?wi)或UNIX文g的目录树(wi)比较熟?zhn)Q也很Ҏ(gu)掌握LDAP目录?wi)这个概念了。就象DNS的主机名那样QLDAP目录记录的标识名QDistinguished NameQ简UDNQ是用来d单个记录Q以?qing)回溯到树(wi)的剙。后面会(x)做详l地介绍?br />Z么要用层ơ结构来l织数据呢?原因是多斚w的。下面是可能遇到的一些情况:(x)
l        如果你想把所有的国客户的联pM息都“推”到位于到西雅图办公室(负责营销Q的LDAP服务器上Q但是你不想把公司的资񔽎理信息“推”到那里?br />l        你可能想Ҏ(gu)目录?wi)的l构l予不同的员工组不同的权限。在下面的例子里Q资产管理组对“asset-mgmt”部分有完全的访问权限,但是不能讉K其它地方?br />l        把LDAP存储和复制功能结合v来,可以定制目录?wi)的l构以降低对WAN带宽的要求。位于西雅图的营销办公室需要每分钟更新的美国销售状늚信息Q但是欧z的销售情况就只要每小时更Cơ就行了?br />刨根问底Q基准DN
LDAP目录?wi)的最剙是根,也就是所谓的“基准DN”。基准DN通常使用下面列出的三U格式之一。假定我在名为FooBar的电(sh)子商务公司工作,q家公司在Internet上的名字是foobar.com?br />o="FooBar, Inc.", c=US
Q以X.500格式表示的基准DNQ?br />在这个例子中Qo=FooBar, Inc. 表示l织名,在这里就是公司名的同义词。c=US 表示公司的总部在美国。以前,一般都用这U方式来表示基准DN。但是事物L在不断变化的Q现在所有的公司都已l(或计划)(j)上Internet上。随着Internet的全球化Q在基准DN中用国家代码很Ҏ(gu)让h产生h。现在,X.500格式发展成下面列出的两种格式?br />o=foobar.com
Q用公司的Internet地址表示的基准DNQ?br />q种格式很直观,用公司的域名作ؓ(f)基准DN。这也是现在最常用的格式?br />dc=foobar, dc=com
Q用DNS域名的不同部分组成的基准DNQ?br />p上面那一U格式,q种格式也是以DNS域名为基的,但是上面那种格式不改变域名(也就更易读)(j)Q而这U格式把域名Qfoobar.com分成两部?dc=foobar, dc=com。在理论上,q种格式可能?x)更灉|一点,但是对于最l用h说也更难记忆一炏V考虑一下foobar.comq个例子。当foobar.com和gizmo.com合ƈ之后Q可以简单的把“dc=com”当作基准DN。把新的记录攑ֈ已经存在的dc=gizmo, dc=com目录下,q样q化了很多工作Q当?dng)如果foobar.com和wocket.edu合ƈQ这个方法就不能用了Q。如果LDAP服务器是新安装的Q我你用这U格式。再h意一下,如果你打用活动目录(Actrive DirectoryQ,Microsoft已经限制你必M用这U格式?br />更上一层楼Q在目录?wi)中怎么l织数据
在UNIX文gpȝ中,最层是根目录QrootQ。在根目录的下面有很多的文g和目录。象上面介绍的那PLDAP目录也是用同L(fng)Ҏ(gu)l织h的?br />在根目录下,要把数据从逻辑上区分开。因为历史上QX.500Q的原因Q大多数LDAP目录用OU从逻辑上把数据分开来。OU表示“Organization Unit”,在X.500协议中是用来表示公司内部的机构:(x)销售部、胦(ch)务部Q等{。现在LDAPq保留ou=q样的命名规则,但是扩展了分cȝ范围Q可以分cMؓ(f)Qou=people, ou=groups, ou=devicesQ等{。更低一U的OU有时用来做更l的归类。例如:(x)LDAP目录?wi)(不包括单独的记录Q可能会(x)是这L(fng)Q?br />    dc=foobar, dc=com
        ou=customers
            ou=asia
            ou=europe
            ou=usa
        ou=employees
        ou=rooms
        ou=groups
        ou=assets-mgmt
        ou=nisgroups
        ou=recipes
单独的LDAP记录
DN是LDAP记录的名字
在LDAP目录中的所有记录项都有一个唯一的“Distinguished Name”,也就是DN。每一个LDAP记录的DN是由两个部分l成的:(x)相对DNQRDNQ和记录在LDAP目录中的位置?br />RDN是DN中与目录?wi)的l构无关的部分。在LDAP目录中存储的记录w要有一个名字,q个名字通常存在cnQCommon NameQ这个属性里。因为几乎所有的东西都有一个名字,在LDAP中存储的对象都用它们的cng为RDN的基。如果我把最喜欢的吃燕麦_食谱存Z个记录,我就?x)用cn=Oatmeal Deluxe作ؓ(f)记录的RDN?br />l         我的LDAP目录的基准DN是dc=foobar,dc=com
l         我把自己的食׃为LDAP的记录项存在ou=recipes
l        我的LDAP记录的RDN设ؓ(f)cn=Oatmeal Deluxe
上面q些构成了燕麦粥食谱的LDAP记录的完整DN。记住,DN的读法和DNSL名类伹{下面就是完整的DNQ?br />cn=Oatmeal Deluxe,ou=recipes,dc=foobar,dc=com
举一个实际的例子来说明DN
现在为公司的员工讄一个DN。可以用Zcn或uidQUser IDQ,作ؓ(f)典型的用户帐受例如,FooBar的员工Fran SmithQ登录名QfsmithQ的DN可以Z面两U格式:(x)
uid=fsmith,ou=employees,dc=foobar,dc=com
Q基于登录名Q?br />LDAPQ以?qing)X.500Q用uid表示“User ID”,不要把它和UNIX的uidh؜淆了。大多数公司都会(x)l每一个员工唯一的登录名Q因此用q个办法可以很好C存员工的信息。你不用担心以后q会(x)有一个叫Fran Smith的加入公司,如果Fran改变了她的名字(l婚Q离婚?或宗教原因?Q,也用不着改变LDAP记录的DN?br />cn=Fran Smith,ou=employees,dc=foobar,dc=com
Q基于姓名)(j)
可以看到q种格式使用了Common NameQCNQ。可以把Common Name当成一个h的全名。这U格式有一个很明显的缺点就是:(x)如果名字改变了,LDAP的记录就要从一个DN转移到另一个DN。但是,我们应该可能地避免改变一个记录项的DN?br />定制目录的对象类?br />你可以用LDAP存储各种cd的数据对象,只要q些对象可以用属性来表示Q下面这些是可以在LDAP中存储的一些信息:(x)
l        员工信息Q员工的姓名、登录名、口令、员工号、他的经理的d名,邮g服务器,{等?br />l        物品跟踪信息Q计机名、IP地址、标{、型受所在位|,{等?br />l        客户联系列表Q客L(fng)公司名、主要联pMh的电(sh)话、传真和?sh)子邮gQ等{?br />l        ?x)议厅信息?x)?x)议厅的名字、位|、可以坐多少人、电(sh)话号码、是否有投媄(jing)机?br />l        食谱信息Q菜的名字、配料、烹调方法以?qing)准备方法?br />因ؓ(f)LDAP目录可以定制成存储Q何文本或二进制数据,到底存什么要׃自己军_。LDAP目录用对象类型(object classesQ的概念来定义运行哪一cȝ对象使用什么属性。在几乎所有的LDAP服务器中Q你都要Ҏ(gu)自己的需要扩展基本的LDAP目录的功能,创徏新的对象cd或者扩展现存的对象cd?br />LDAP目录以一pd“属性对”的形式来存储记录项Q每一个记录项包括属性类型和属性|q与关系型数据库用行和列来存取数据有Ҏ(gu)的不同)(j)。下面是我存在LDAP目录中的一部分食谱记录Q?br />  dn: cn=Oatmeal Deluxe, ou=recipes, dc=foobar, dc=com
  cn: Instant Oatmeal Deluxe
  recipeCuisine: breakfast
  recipeIngredient: 1 packet instant oatmeal
  recipeIngredient: 1 cup water
  recipeIngredient: 1 pinch salt
  recipeIngredient: 1 tsp brown sugar
  recipeIngredient: 1/4 apple, any type
h意上面每一U配料都作ؓ(f)属性recipeIngredient倹{LDAP目录被设计成象上面那样ؓ(f)一个属性保存多个值的Q而不是在每一个属性的后面用逗号把一pd值分开?br />因ؓ(f)用这L(fng)方式存储数据Q所以数据库有很大的灵zL,不必为加入一些新的数据就重新创徏表和索引。更重要的是QLDAP目录不必p内存或硬盘空间处理“空”域Q也是_(d)实际上不使用可选择的域也不?x)花费你M资源?br />作ؓ(f)例子的一个单独的数据?br />让我们看看下面这个例子。我们用Foobar, Inc.的员工Fran Smith的LDAP记录。这个记录项的格式是LDIFQ用来导入和导出LDAP目录的记录项?br />  dn: uid=fsmith, ou=employees, dc=foobar, dc=com
  objectclass: person
  objectclass: organizationalPerson
  objectclass: inetOrgPerson
  objectclass: foobarPerson
  uid: fsmith
  givenname: Fran
  sn: Smith
  cn: Fran Smith
  cn: Frances Smith
  telephonenumber: 510-555-1234
  roomnumber: 122G
  o: Foobar, Inc.
  mailRoutingAddress: fsmith@foobar.com
  mailhost: mail.foobar.com
  userpassword: {crypt}3x1231v76T89N
  uidnumber: 1234
  gidnumber: 1200
  homedirectory: /home/fsmith
  loginshell: /usr/local/bin/bash
属性的值在保存的时候是保留大小写的Q但是在默认情况下搜索的时候是不区分大写的。某些特D的属性(例如QpasswordQ在搜烦(ch)的时候需要区分大写?br />让我们一点一点地分析上面的记录项?br />dn: uid=fsmith, ou=employees, dc=foobar, dc=com
q是Fran的LDAP记录的完整DNQ包括在目录?wi)中的完整\径。LDAPQ和X.500Q用uidQUser IDQ,不要把它和UNIX的uidh؜淆了?br />  objectclass: person
  objectclass: organizationalPerson
  objectclass: inetOrgPerson
  objectclass: foobarPerson
可以ZQ何一个对象根据需要分配多个对象类型。person对象cd要求cnQcommon nameQ和snQsurnameQ这两个域不能ؓ(f)I。persion对象cd允许有其它的可选域Q包括givenname、telephonenumberQ等{。organizational Personlperson加入更多的可选域QinetOrgPerson又加入更多的可选域Q包括电(sh)子邮件信息)(j)。最后,foobarPerson是ؓ(f)Foobar定制的对象类型,加入了很多定制的属性?br />  uid: fsmith
  givenname: Fran
  sn: Smith
  cn: Fran Smith
  cn: Frances Smith
  telephonenumber: 510-555-1234
  roomnumber: 122G
  o: Foobar, Inc.
以前说过了,uid表示User ID。当看到uid的时候,在脑袋里想一想“login”?br />h意CN有多个倹{就象上面介l的QLDAP允许某些属性有多个倹{ؓ(f)什么允许有多个值呢Q假定你在用公司的LDAP服务器查找Fran的电(sh)话号码。你可能只知道她的名字叫FranQ但是对人力资源处的人来说她的正式名字叫做Frances。因Z存了她的两个名字Q所以用M一个名字检索都可以扑ֈFran的电(sh)话号码、电(sh)子邮件和办公戉KP{等?br />  mailRoutingAddress: fsmith@foobar.com
  mailhost: mail.foobar.com
p现在大多数的公司都上|了QFoobar用Sendmail发送邮件和处理外部邮g路由信息。Foobar把所有用L(fng)邮g信息都存在LDAP中。最新版本的Sendmail支持q项功能?br />  Userpassword: {crypt}3x1231v76T89N
  uidnumber: 1234
  gidnumber: 1200
  gecos: Frances Smith
  homedirectory: /home/fsmith
  loginshell: /usr/local/bin/bash
注意QFoobar的系l管理员把所有用L(fng)口o(h)映射信息也都存在LDAP中。FoobarPersoncd的对象具有这U能力。再注意一下,用户口o(h)是用UNIX的口令加密格式存储的。UNIX的uid在这里ؓ(f)uidnumber。提醒你一下,关于如何在LDAP中保存NIS信息Q有完整的一份RFC。在以后的文章中我会(x)谈一谈NIS的集成?br />LDAP复制

KingWell 2006-05-15 19:18 发表评论
]]>
JDK1.5枚Dcdhttp://www.aygfsteel.com/kingwell/articles/45794.htmlKingWellKingWellFri, 12 May 2006 02:54:00 GMThttp://www.aygfsteel.com/kingwell/articles/45794.htmlhttp://www.aygfsteel.com/kingwell/comments/45794.htmlhttp://www.aygfsteel.com/kingwell/articles/45794.html#Feedback0http://www.aygfsteel.com/kingwell/comments/commentRss/45794.htmlhttp://www.aygfsteel.com/kingwell/services/trackbacks/45794.html
  1Q它不能有public?a class="bluekey" target="_blank">构造函?/a>Q这样做可以保证客户代码没有办法新徏一个enum的实例?br />
  2Q所有枚丑ր都是public , static , final的。注意这一点只是针对于枚D|我们可以和在普通类里面定义 变量一样定义其它Q何类型的非枚丑֏量,q些变量可以用Q何你想用的修饰符?br />
  3QEnum默认实现了java.lang.Comparable接口?br />
  4QEnum覆蝲了了toStringҎ(gu)Q因此我们如果调用Color.Blue.toString()默认q回字符东yBlue?

  5QEnum提供了一个valueOfҎ(gu)Q这个方法和toStringҎ(gu)是相对应的。调用valueOf(“Blue?返回Color.Blue.因此我们在自己重写toStringҎ(gu)的时候就要注意到q一点,一把来说应该相对应地重写valueOfҎ(gu)?br />
  6QEnumq提供了valuesҎ(gu)Q这个方法你能够方便的遍历所有的枚D倹{?br />
  7QEnumq有一个oridinal的方法,q个Ҏ(gu)q回枚D值在枚Dcȝ的顺序,q个序Ҏ(gu)枚D值声明的序而定Q这里Color.Red.ordinal()q回0?br />
  了解了这些基本特性,我们来看看如何用它们?br />
  1Q遍历所有有枚D? 知道了有valuesҎ(gu)Q我们可以轻车熟路地用ForEach循环来遍历了枚Dg?br />
for (Color c: Color.values())
System.out.println(?a class="bluekey" target="_blank">find value:?+ c);

  2Q在enum中定义方法和变量Q比如我们可以ؓ(f)Color增加一个方法随回一个颜艌Ӏ?br />
public enum Color {
 Red,
 Green,
 Blue;

 /*
 *定义一个变量表C枚丑ր的数目?br /> *(我有点奇怪ؓ(f)什么sun没有lenum直接提供一个sizeҎ(gu)).
 */
 private static int number = Color.values().length ;

 /**
 * 随机q回一个枚丑ր?br /> @return a random enum value.
 */
 public static Color getRandomColor(){
  long random = System.currentTimeMillis() % number;
  switch ((int) random){
   case 0:
    return Color.Red;
   case 1:
    return Color.Green;
   case 2:
    return Color.Blue;
   default : return Color.Red;
  }
 }
}

  可以看出q在枚Dcd里定义变量和Ҏ(gu)和在普通类里面定义Ҏ(gu)和变量没有什么区别。唯一要注意的只是变量和方法定义必L在所有枚丑ր定义的后面Q否则编译器?x)给Z个错误?br />
  3Q覆?Override)toString, valueOfҎ(gu)

  前面我们已经知道enum提供了toString,valueOf{方法,很多时候我们都需要覆载默认的toStringҎ(gu)Q那么对于enum我们怎么做呢。其实这和覆载一个普通class的toStringҎ(gu)没有什么区别?br />
?
public String toString(){
 switch (this){
  case Red:
   return "Color.Red";
  case Green:
   return "Color.Green";
  case Blue:
   return "Color.Blue";
  default:
   return "Unknow Color";
 }
}
?

  q时我们可以看到Q此时再用前面的遍历代码打印出来的是

Color.Red
Color.Green
Color.Blue

  而不?br />
Red
Green
Blue.

  可以看到toString实是被覆蝲了。一般来说在覆蝲toString的时候我们同时也应该覆蝲valueOfҎ(gu)Q以保持它们怺的一致性?br />
  4Q用构造函?br />
  虽然enum不可以有public的构造函敎ͼ但是我们q是可以定义private的构造函敎ͼ在enum内部使用。还是用Colorq个例子?br />
public enum Color {
 Red("This is Red"),
 Green("This is Green"),
 Blue("This is Blue");

 private String desc;

 Color(String desc){
  this.desc = desc;
 }

 public String getDesc(){
  return this.desc;
 }

}

  q里我们为每一个颜色提供了一个说明信? 然后定义了一个构造函数接受这个说明信息?br />
  要注意这里构造函C能ؓ(f)public或者protected, 从而保证构造函数只能在内部使用Q客户代码不能new一个枚丑ր的实例出来。这也是完全W合情理的,因ؓ(f)我们知道枚D值是public static final的常量而已?br />
  5Q实现特定的接口

  我们已经知道enum可以定义变量和方法,它要实现一个接口也和普通class实现一个接口一Pq里׃作示例了?br />
  6Q定义枚丑րDqҎ(gu)?br />
  前面我们看到可以为enum定义一些方法,其实我们甚至可以为每一个枚丑ր定义方法。这P我们前面覆蝲 toString的例子可以被改写成这栗?br />
public enum Color {
 Red {
  public String toString(){
   return "Color.Red";
  }
 },
 Green {
  public String toString(){
   return "Color.Green";
  }
 },
 Blue{
  public String toString(){
   return "Color.Blue";
  }
 };
}

  从逻辑上来说这h原先提供一个“全局“的toStringҎ(gu)要清C些?br />
  ȝ来说Qenum作ؓ(f)一个全新定义的cdQ是希望能够帮助E序员写出的代码更加单易?/a>Q个得一般也不需要过多的使用enum的一些高U特性,否则和单易懂的初衷惌背了?br />
Q以上代码在win2k+ 1.5.0-beta2-b51下运行通过Q?


KingWell 2006-05-12 10:54 发表评论
]]>
Java中ThreadLocal的设计与使用http://www.aygfsteel.com/kingwell/articles/45163.htmlKingWellKingWellTue, 09 May 2006 02:55:00 GMThttp://www.aygfsteel.com/kingwell/articles/45163.htmlhttp://www.aygfsteel.com/kingwell/comments/45163.htmlhttp://www.aygfsteel.com/kingwell/articles/45163.html#Feedback0http://www.aygfsteel.com/kingwell/comments/commentRss/45163.htmlhttp://www.aygfsteel.com/kingwell/services/trackbacks/45163.html
   ThreadLocal是什?br />
   ThreadLocal是什么呢Q其实ThreadLocalq是一个线E的本地实现版本Q它q不是一个ThreadQ而是thread local variableQ线E局部变量)(j)。也许把它命名ؓ(f)ThreadLocalVar更加合适。线E局部变量(ThreadLocalQ其实的功用非常单,是为每一个用该变量的线E都提供一个变量值的副本Q是每一个线E都可以独立地改变自q副本Q而不?x)和其它U程的副本冲H。从U程的角度看Q就好像每一个线E都完全拥有该变量。线E局部变量ƈ不是Java的新发明Q在其它的一些语a~译器实玎ͼ如IBM XL FORTRANQ中Q它在语a的层ơ提供了直接的支持。因为Java中没有提供在语言层次的直接支持,而是提供了一个ThreadLocal的类来提供支持,所以,在Java中编写线E局部变量的代码相对比较W拙Q这也许是线E局部变量没有在Java中得到很好的普及(qing)的一个原因吧?br />
   ThreadLocal的设?br />
   首先看看ThreadLocal的接口:(x)

    Object get() ; // q回当前U程的线E局部变量副?protected Object initialValue(); // q回该线E局部变量的当前U程的初始?br />    void set(Object value); // 讄当前U程的线E局部变量副本的?br />
   ThreadLocal?个方法,其中值得注意的是initialValue()Q该Ҏ(gu)是一个protected的方法,昄是ؓ(f)了子c重写而特意实现的。该Ҏ(gu)q回当前U程在该U程局部变量的初始|q个Ҏ(gu)是一个gq调用方法,在一个线E第1ơ调用get()或者set(Object)时才执行Qƈ且仅执行1ơ。ThreadLocal中的实实现直接q回一个nullQ?br />
protected Object initialValue() { return null; }

  ThreadLocal是如何做Cؓ(f)每一个线E维护变量的副本的呢Q其实实现的思\很简单,在ThreadLocalcM有一个MapQ用于存储每一个线E的变量的副本。比如下面的CZ实现Q?br />
public class ThreadLocal
{
  private Map values = Collections.synchronizedMap(new HashMap());
  public Object get()
  {
   Thread curThread = Thread.currentThread();
   Object o = values.get(curThread);
   if (o == null && !values.containsKey(curThread))
   {
    o = initialValue();
    values.put(curThread, o);
   }
   return o;
  }

  public void set(Object newValue)
  {
   values.put(Thread.currentThread(), newValue);
  }

  public Object initialValue()
  {
   return null;
  }
}

  当然Q这q不是一个工业强度的实现Q但JDK中的ThreadLocal的实现M思\也类g此?br />
   ThreadLocal的?br />
   如果希望U程局部变量初始化其它|那么需要自己实现ThreadLocal的子cdƈ重写该方法,通常使用一个内部匿名类对ThreadLocalq行子类化,比如下面的例子,SerialNumcMؓ(f)每一个类分配一个序P(x)

public class SerialNum
{
  // The next serial number to be assigned

  private static int nextSerialNum = 0;
  private static ThreadLocal serialNum = new ThreadLocal()
  {
   protected synchronized Object initialValue()
   {
    return new Integer(nextSerialNum++);
   }
  };

  public static int get()
  {
   return ((Integer) (serialNum.get())).intValue();
  }
}

  SerialNumcȝ使用非常地单,因ؓ(f)get()Ҏ(gu)是static的,所以在需要获取当前线E的序号Ӟ单地调用Q?br />
int serial = SerialNum.get();

  卛_?br />
   在线E是zd的ƈ且ThreadLocal对象是可讉K的时Q该U程持有一个到该线E局部变量副本的隐含引用Q当该线E运行结束后Q该U程拥有的所以线E局部变量的副本都将失效Qƈ{待垃圾攉器收集?br />
   ThreadLocal与其它同步机制的比较

   ThreadLocal和其它同步机制相比有什么优势呢QThreadLocal和其它所有的同步机制都是Z解决多线E中的对同一变量的访问冲H,在普通的同步机制中,是通过对象加锁来实现多个线E对同一变量的安全访问的。这时该变量是多个线E共享的Q用这U同步机刉要很l致地分析在什么时候对变量q行dQ什么时候需要锁定某个对象,什么时候释放该对象的锁{等很多。所有这些都是因为多个线E共享了资源造成的。ThreadLocal׃另一个角度来解决多线E的q发讉KQThreadLocal?x)?f)每一个线E维护一个和该线E绑定的变量的副本,从而隔M多个U程的数据,每一个线E都拥有自己的变量副本,从而也没有必要对该变量进行同步了。ThreadLocal提供了线E安全的׃n对象Q在~写多线E代码时Q可以把不安全的整个变量装qThreadLocalQ或者把该对象的特定于线E的状态封装进ThreadLocal?br />
   ׃ThreadLocal中可以持有Q何类型的对象Q所以用ThreadLocal get当前U程的值是需要进行强制类型{换。但随着新的Java版本Q?.5Q将模版的引入,新的支持模版参数的ThreadLocal<T>cd从中受益。也可以减少强制cd转换Qƈ一些错误检查提前到了编译期Q将一定程度地化ThreadLocal的用?br />
   ȝ

   当然ThreadLocalq不能替代同步机Ӟ两者面向的问题领域不同。同步机制是Z同步多个U程对相同资源的q发讉KQ是Z多个U程之间q行通信的有效方式;而ThreadLocal是隔d个线E的数据׃nQ从Ҏ(gu)上就不在多个U程之间׃n资源Q变量)(j)Q这样当然不需要对多个U程q行同步了。所以,如果你需要进行多个线E之间进行通信Q则使用同步机制Q如果需要隔d个线E之间的׃n冲突Q可以用ThreadLocalQ这极大地化你的程序,使程序更加易诅R简z?br />
文章来源Qjavajia


KingWell 2006-05-09 10:55 发表评论
]]>
վ֩ģ壺 | Ƹ| | ϰ| | ͼ| ɽ| Ӫ| ͨ| | ϲ| ױ| | | | | | °Ͷ| ɽ| ֱ| | | | | ±| | | ʡ| | | Թ| | ƺ| | | Ϫ| | | | Ƥ| |