Zookeeper源码阅读(五) ACL基础

前言

之前看代码的时候也同步看了看一些关于zk源码的博客,有一两篇讲到了ZK里ACL的基础的结构,我自己这边也看了看相关的代码,在这里分享一下!

ACL和ID

ACL和ID都是有Jute生成的实体类,分别代表了ZK里ACL和不同ACL模式下的具体实体。

ACL:

public class ACL implements Record {
  private int perms;
  private org.apache.zookeeper.data.Id id;

可以看到,ACL包含了两个域,分别代表了权限值(perms)和ACL的验证实体(id)。

ID:

public class Id implements Record {
  private String scheme;
  private String id;
  public Id() {
  }
  public Id( //参数构造器
        String scheme,
        String id) {
    this.scheme=scheme;
    this.id=id;
  }

在ID类中,主要有两个域,scheme即是验证模式,而id则代表在scheme的验证模式下的具体内容。

perms

关于perms,ZK中的权限类型和linux系统中的文件权限很类似,大致上都会有读、写、操作的权限,而且都是通过位操作来控制,非常的优雅。但是有两点需要强调:

  1. zk的权限系统中没有所谓user,group,others的概念,也就是说没有一个用户或者说用户组是一个znode的拥有者,但是可以给一群用户或一个用户赋予某个znode admin的权限。
  2. 对某个znode设置的ACL只对它自己有效,对它的子节点无效的。
@InterfaceAudience.Public
public interface Perms {
    int READ = 1 << 0;//getdata/getchildren是否可以

    int WRITE = 1 << 1;//zookeeper中write是表示是否可以setdata

    int CREATE = 1 << 2;//创建子节点

    int DELETE = 1 << 3;//删除子节点

    int ADMIN = 1 << 4;//可以通过setacl设置权限

    int ALL = READ | WRITE | CREATE | DELETE | ADMIN;
}

总结:可以看到通过位操作为不同的权限赋予不同的值,类似linux中权限值的概念。

ID

@InterfaceAudience.Public
    public interface Ids {
        /**
         * This Id represents anyone.
         */
         //默认的为world模式设置的ID
        public final Id ANYONE_ID_UNSAFE = new Id("world", "anyone");

        /**
         * This Id is only usable to set ACLs. It will get substituted with the
         * Id's the client authenticated with.
         */
         //默认的为auth模式设置的ID,代表了任何已经被确认的用户,在setacl的时候使用
        public final Id AUTH_IDS = new Id("auth", "");

        /**
         * This is a completely open ACL .
         */
         //默认的open ACL LIst,表示所有用户(ANYONE_ID_UNSAFE)有所有权限
        public final ArrayList<ACL> OPEN_ACL_UNSAFE = new ArrayList<ACL>(
                Collections.singletonList(new ACL(Perms.ALL, ANYONE_ID_UNSAFE)));

        /**
         * This ACL gives the creators authentication id's all permissions.
         */
         //默认的creator ACL LIst,表示auth_ids这些账号有所有权限
        public final ArrayList<ACL> CREATOR_ALL_ACL = new ArrayList<ACL>(
                Collections.singletonList(new ACL(Perms.ALL, AUTH_IDS)));

        /**
         * This ACL gives the world the ability to read.
         */
         //默认的read ACL LIst,表示所有账号(ANYONE_ID_UNSAFE)有read权限
        public final ArrayList<ACL> READ_ACL_UNSAFE = new ArrayList<ACL>(
                Collections
                        .singletonList(new ACL(Perms.READ, ANYONE_ID_UNSAFE)));
    }

总结:可以看到,zk内部在ZooDefs提供了两个默认的ID实例,分别是world和auth两种schema的实现。同时在DigestAuthenticationProvider中实现了super schema的访问。

/** specify a command line property with key of
 * "zookeeper.DigestAuthenticationProvider.superDigest"
 * and value of "super:<base64encoded(SHA1(password))>" to enable
 * super user access (i.e. acls disabled)
 */
//superDigest 的值是super:<base64encoded(SHA1(password))>,可以在zk启动时配置zookeeper.DigestAuthenticationProvider.superDigest的值
private final static String superDigest = System.getProperty(
    "zookeeper.DigestAuthenticationProvider.superDigest");
public KeeperException.Code
    handleAuthentication(ServerCnxn cnxn, byte[] authData)
{
    String id = new String(authData);//把验证信息转换为string
    try {
        String digest = generateDigest(id);//加密
        if (digest.equals(superDigest)) {//判断是否是super
            cnxn.addAuthInfo(new Id("super", ""));//加入一个super的ID
        }
        cnxn.addAuthInfo(new Id(getScheme(), digest));//加入digest schema下的id为digest变量值的ID
        return KeeperException.Code.OK;
    } catch (NoSuchAlgorithmException e) {
        LOG.error("Missing algorithm",e);
    }
    return KeeperException.Code.AUTHFAILED;
}

schema

上面说到了zk内部的world,auth和super三种schema的实现,实际上,zk还有三种不提供固定id的schema。这三种schema的实现类都实现了AuthenticationProvider接口。

/**
 * This interface is implemented by authentication providers to add new kinds of
 * authentication schemes to ZooKeeper.
 */
public interface AuthenticationProvider {
    /**
     * The String used to represent this provider. This will correspond to the
     * scheme field of an Id.
     *
     * @return the scheme of this provider.
     */
     //获取当前的schema
    String getScheme();

    /**
     * This method is called when a client passes authentication data for this
     * scheme. The authData is directly from the authentication packet. The
     * implementor may attach new ids to the authInfo field of cnxn or may use
     * cnxn to send packets back to the client.
     *
     * @param cnxn
     *                the cnxn that received the authentication information.
     * @param authData
     *                the authentication data received.
     * @return TODO
     */
    //客户端发送的验证信息处理
    KeeperException.Code handleAuthentication(ServerCnxn cnxn, byte authData[]);

    /**
     * This method is called to see if the given id matches the given id
     * expression in the ACL. This allows schemes to use application specific
     * wild cards.
     *
     * @param id
     *                the id to check.
     * @param aclExpr
     *                the expression to match ids against.
     * @return true if the id can be matched by the expression.
     */
    //校验id是否符合表达式
    boolean matches(String id, String aclExpr);

    /**
     * This method is used to check if the authentication done by this provider
     * should be used to identify the creator of a node. Some ids such as hosts
     * and ip addresses are rather transient and in general don't really
     * identify a client even though sometimes they do.
     *
     * @return true if this provider identifies creators.
     */
    //判断这种schema的provider是否能定位creator
    boolean isAuthenticated();

    /**
     * Validates the syntax of an id.
     *
     * @param id
     *                the id to validate.
     * @return true if id is well formed.
     *
     //检验语法
    boolean isValid(String id);
}

这里以DigestAuthenticationProvider做例子,SASLAuthenticationProvider(不清楚具体作用,在后面的ProviderRegistry也没有注册)和IPAuthenticationProvider是差不多的,可以类比着看看:

public class DigestAuthenticationProvider implements AuthenticationProvider {
    private static final Logger LOG =
        LoggerFactory.getLogger(DigestAuthenticationProvider.class);

    /** specify a command line property with key of
     * "zookeeper.DigestAuthenticationProvider.superDigest"
     * and value of "super:<base64encoded(SHA1(password))>" to enable
     * super user access (i.e. acls disabled)
     */
    //去读zookeeper.DigestAuthenticationProvider.superDigest配置
    private final static String superDigest = System.getProperty(
        "zookeeper.DigestAuthenticationProvider.superDigest");

    //当前是digest schema
    public String getScheme() {
        return "digest";
    }

    //base64加密
    static final private String base64Encode(byte b[]) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < b.length;) {
            int pad = 0;
            int v = (b[i++] & 0xff) << 16;
            if (i < b.length) {
                v |= (b[i++] & 0xff) << 8;
            } else {
                pad++;
            }
            if (i < b.length) {
                v |= (b[i++] & 0xff);
            } else {
                pad++;
            }
            sb.append(encode(v >> 18));
            sb.append(encode(v >> 12));
            if (pad < 2) {
                sb.append(encode(v >> 6));
            } else {
                sb.append('=');
            }
            if (pad < 1) {
                sb.append(encode(v));
            } else {
                sb.append('=');
            }
        }
        return sb.toString();
    }

    static final private char encode(int i) {
        i &= 0x3f;
        if (i < 26) {
            return (char) ('A' + i);
        }
        if (i < 52) {
            return (char) ('a' + i - 26);
        }
        if (i < 62) {
            return (char) ('0' + i - 52);
        }
        return i == 62 ? '+' : '/';
    }

    //生成加密的id
    static public String generateDigest(String idPassword)
            throws NoSuchAlgorithmException {
        String parts[] = idPassword.split(":", 2);//split字符串
        byte digest[] = MessageDigest.getInstance("SHA1").digest(
                idPassword.getBytes());//SHA1加密
        return parts[0] + ":" + base64Encode(digest);//id+":"+base64加密
    }

    public KeeperException.Code
        handleAuthentication(ServerCnxn cnxn, byte[] authData)
    {
        String id = new String(authData);
        try {
            String digest = generateDigest(id);//拿到digest id
            if (digest.equals(superDigest)) {//判断是不是super用户
                cnxn.addAuthInfo(new Id("super", ""));
            }
            cnxn.addAuthInfo(new Id(getScheme(), digest));//把schema和digest值添加到连接信息里
            return KeeperException.Code.OK;
        } catch (NoSuchAlgorithmException e) {
            LOG.error("Missing algorithm",e);
        }
        return KeeperException.Code.AUTHFAILED;
    }

    public boolean isAuthenticated() {
        return true;//可以定位creator
    }

    public boolean isValid(String id) {
        String parts[] = id.split(":");
        return parts.length == 2;//校验合法性,通过判断是否是以“:”分割的字符串
    }

    public boolean matches(String id, String aclExpr) {
        return id.equals(aclExpr);//字符串相等时才匹配
    }

    /** Call with a single argument of user:pass to generate authdata.
     * Authdata output can be used when setting superDigest for example.
     * @param args single argument of user:pass
     * @throws NoSuchAlgorithmException
     */
    public static void main(String args[]) throws NoSuchAlgorithmException {
        for (int i = 0; i < args.length; i++) {
            System.out.println(args[i] + "->" + generateDigest(args[i]));
        }
    }
}

关于isAuthenticated的一点解释:zookeeper官方文档是这样说的:If the new ACL includes an "auth" entry, isAuthenticated is used to see if the authentication information for this scheme that is assocatied with the connection should be added to the ACL. Some schemes should not be included in auth. For example, the IP address of the client is not considered as an id that should be added to the ACL if auth is specified.

也就是说如果是request的authinfo是auth的schema,那么它对应的Id应该被加入当前ACL的list里,但是zk在这里做了限制,并不是所有的schema的Id都可以加入ACL的list里的,如果用IP的schema设置的就不行,但如果是digest模式的就可以。结合后面在PrepRequestProcessor的fixupACL一起看。

ProviderRegistry

三种provider都会在ProviderRegistry中注册,使用了策略器模式。

public class ProviderRegistry {
    private static final Logger LOG = LoggerFactory.getLogger(ProviderRegistry.class);

    private static boolean initialized = false;
    private static HashMap<String, AuthenticationProvider> authenticationProviders =
        new HashMap<String, AuthenticationProvider>();

    public static void initialize() {
        synchronized (ProviderRegistry.class) {
            if (initialized)
                return;
            //ip和digest两种schema的provider注册
            IPAuthenticationProvider ipp = new IPAuthenticationProvider();
            DigestAuthenticationProvider digp = new DigestAuthenticationProvider();
            //加入ProviderRegistry的域
            authenticationProviders.put(ipp.getScheme(), ipp);
            authenticationProviders.put(digp.getScheme(), digp);
            //去读properties文件,拿到所有的key
            Enumeration<Object> en = System.getProperties().keys();
            while (en.hasMoreElements()) {
                String k = (String) en.nextElement();
                //自定义的acl provider在开发后需要注册到zk中,后面详细说下
                if (k.startsWith("zookeeper.authProvider.")) {
                    String className = System.getProperty(k);//获取类名
                    try {
                        Class<?> c = ZooKeeperServer.class.getClassLoader()
                                .loadClass(className);//类加载
                        AuthenticationProvider ap = (AuthenticationProvider) c
                                .getDeclaredConstructor().newInstance();
                        authenticationProviders.put(ap.getScheme(), ap);//把自定义的权限控制器加入map中
                    } catch (Exception e) {
                        LOG.warn("Problems loading " + className,e);
                    }
                }
            }
            initialized = true;
        }
    }

    //根绝schema获取对应的authentication provider
    public static AuthenticationProvider getProvider(String scheme) {
        if(!initialized)
            initialize();
        return authenticationProviders.get(scheme);
    }

    //列出所有的provider
    public static String listProviders() {
        StringBuilder sb = new StringBuilder();
        for(String s: authenticationProviders.keySet()) {
        sb.append(s + " ");
}
        return sb.toString();
    }
}

补充:前面说的自定义权限控制器在zk中主要分为两步:

  1. 自定义类实现AuthenticationProvider接口
  2. 注册自定义的权限控制器,有两种方法:
    1. 在启动zk时在启动参数中配置-Dzookeeper.authProvider.序号(1,2...)=类路径(com.a.b.cprovider);
    2. 在zoo.cfg中配置authProvider.序号(1,2...)=类路径(com.a.b.cprovider);

一旦自己写了自定义的权限控制器,在ProviderRegistry中会去扫描所有的权限控制器,并负责注册他们。

总结一下zk的ACL系统schema,供user使用的主要有4种:

ip:形式为"ip:expression" ,expression可以为单个Ip也可以为表达多个ip的表达式;

digest:"username:password",最常见的;

world:对所有客户端开放;

super:超级管理员权限,可以在zookeeper启动时设置,不设置也有默认值。

其实根据代码还有两种,auth模式表示已经认证的用户,sasl这种看代码也没看到哪里使用了,不是特别清楚。

ACL的使用

这里所说的ACL的使用不只是说代码里那里验证用到了acl,而是从创建、修改到使用都会有相关的代码分析。

其中,在Zookeeper类中create()方法(create节点)中首先有对ACL的简单校验和设置,这里仅仅贴出相关代码。

if (acl != null && acl.size() == 0) { //设置的acl不可以为空
    throw new KeeperException.InvalidACLException();
}
request.setAcl(acl);//在请求中添加acl,记得之前提到过request中包含path,data和acl列表。

同时,Zookeeper类中又同步和异步两种setacl的方法,也和zookeeper的很多接口一样,都提供同步和异步两种方案。这里看下异步的代码,其实同步的和异步的逻辑差不多。

/**
 * The asynchronous version of create.
 *
 * @see #create(String, byte[], List, CreateMode)
 */

public void setACL(final String path, List<ACL> acl, int version,
            StatCallback cb, Object ctx)
{
    final String clientPath = path;
    PathUtils.validatePath(clientPath, createMode.isSequential());//首先去校验一下path字符串的合法性

    final String serverPath = prependChroot(clientPath);//这是prepend命名空间的一步,zookeeper可以在配置的时候就规定命名空间,然后把clientpath append到命名空间后

    RequestHeader h = new RequestHeader();
    h.setType(ZooDefs.OpCode.setACL);//请求头中设置setacl的opcode
    SetACLRequest request = new SetACLRequest();
    request.setPath(serverPath);//设置路径
    request.setAcl(acl);//设置路径
    request.setVersion(version);//设置版本
    SetACLResponse response = new SetACLResponse();
    cnxn.queuePacket(h, new ReplyHeader(), request, response, cb,
                     clientPath, serverPath, ctx, null);//把请求放入queue中
}

PrepRequestProcessor类是负责请求处理链的功能类,后面会详细讲到,这里先简单说下和ACL基本验证有关的方法fixupACL和校验的方法checkACL。

/**
 * This method checks out the acl making sure it isn't null or empty,
 * it has valid schemes and ids, and expanding any relative ids that
 * depend on the requestor's authentication information.
 *
 * @param authInfo list of ACL IDs associated with the client connection
 * @param acl list of ACLs being assigned to the node (create or setACL operation)
 * @return
 */
//
private boolean fixupACL(List<Id> authInfo, List<ACL> acl) {
    if (skipACL) { //zk可以配置是否跳过ACL检查
        return true;
    }
    if (acl == null || acl.size() == 0) {//acl列表不可为null或空
        return false;
    }

    Iterator<ACL> it = acl.iterator();
    LinkedList<ACL> toAdd = null;
    while (it.hasNext()) {
        ACL a = it.next();
        Id id = a.getId();
        if (id.getScheme().equals("world") && id.getId().equals("anyone")) {
            // wide open
            //如果是world模式,对所有客户端开放
        } else if (id.getScheme().equals("auth")) {//id的schema是auth
            // This is the "auth" id, so we have to expand it to the
            // authenticated ids of the requestor
            it.remove();//auth模式下吧这个从acl列表中删掉
            if (toAdd == null) {
                toAdd = new LinkedList<ACL>();
            }
            boolean authIdValid = false;
            for (Id cid : authInfo) {
                AuthenticationProvider ap =
                    ProviderRegistry.getProvider(cid.getScheme());//根据schema去获取验证控制器
                if (ap == null) {
                    LOG.error("Missing AuthenticationProvider for "
                            + cid.getScheme());//验证控制器不存在就打log
                } else if (ap.isAuthenticated()) {//ip的会返回false, digest的会返回true,表示是否符合验证
                    authIdValid = true;
                    toAdd.add(new ACL(a.getPerms(), cid));//把ACL加入list中
                }
            }
            if (!authIdValid) {//在auth模式下是否valid
                return false;
            }
        } else {//在其他模式下,ip, digest
            AuthenticationProvider ap = ProviderRegistry.getProvider(id
                    .getScheme());//去ProviderRegistry获取对应的AuthenticationProvider
            if (ap == null) {//AuthenticationProvider校验
                return false;
            }
            if (!ap.isValid(id.getId())) {//调用AuthenticationProvider的检验方法去查询格式是否合法
                return false;
            }
        }
    }
    if (toAdd != null) {//toAdd不为空表示auth模式下有增加的id
        for (ACL a : toAdd) {
            acl.add(a);
        }
    }
    return acl.size() > 0;
}

总结:fixupACL其实主要分为三步:

  1. 如果是world, anyone,通过;
  2. 如果是auth模式,那么就跟前面讲isAuthenticated的一样,把符合的schema的id加入acl列表;
  3. 如果是其他的模式下,那么就要去检验id的格式合法性。

再看下checkACL:

/**
*
* @param zks zk server对象
* @param acl 对应节点或者父节点拥有的权限
* @param perm 目前操作需要的权限
* @param ids 目前请求提供的权限
* 参数解释 from https://www.jianshu.com/p/1dee7ad908fe
*/
static void checkACL(ZooKeeperServer zks, List<ACL> acl, int perm,
        List<Id> ids) throws KeeperException.NoAuthException {
    if (skipACL) {//是否跳过acl
        return;
    }
    if (acl == null || acl.size() == 0) {//ACL不能为空
        return;
    }
    for (Id authId : ids) {
        if (authId.getScheme().equals("super")) {//如果是request的authinfo里有super用户,那么直接返回
            return;
        }
    }
    for (ACL a : acl) {//遍历ACL列表
        Id id = a.getId();
        if ((a.getPerms() & perm) != 0) {如果当前节点可以做perm的操作
            if (id.getScheme().equals("world")
                    && id.getId().equals("anyone")) {//如果节点提供了world的访问权限,那么直接返回
                return;
            }
            AuthenticationProvider ap = ProviderRegistry.getProvider(id
                    .getScheme());//根据id获取对应的AuthenticationProvider
            if (ap != null) {
                for (Id authId : ids) {//遍历request拥有的id
                    if (authId.getScheme().equals(id.getScheme())
                            && ap.matches(authId.getId(), id.getId())) {//节点的id和request的id作对比,如果match就返回
                        return;
                    }
                }
            }
        }
    }
    throw new KeeperException.NoAuthException();
}

总结:checkACL是用来做ACL校验的重要方法,如果验证失败会直接抛出NoAuthException的异常。还有fixupACL和checkACL的主要区别在于前者是判断新的id是否合理以及加入ACL列表中;而后者是当前请求和节点权限合法性的检查,即当前请求是否能对节点进行某种操作。

思考

工厂模式和策略期模式

两者感觉很近似,看了些资料,大致的相同点在于都利用了封装,把具体的实现或者说操作隐藏在了第三方类的内部,客户端不需要关注内部的细节;

而大致的不同在于说工厂模式更关于于不同条件下实例的生成,而策略器模式则更关注的是在封装类内部可以自定义不同的操作,是否返回实例并不是关注的重点。

可以看看 策略模式和工厂模式的区别简单工厂,工厂,抽象工厂和策略的区别

命名空间

我以前都不知道zk可以设置命名空间,也是之前看代码的时候看到了去查资料看到的,感觉有时候用起来还是挺有意义的。很简单,可以看下 zk命名空间

参考

https://blog.csdn.net/summer_thirtyOne/article/details/51901575

https://blog.csdn.net/lovingprince/article/details/6935465

https://blog.csdn.net/lovingprince/article/details/6935465 最后关于super,world区别和前面用auth设置的例子可以看下

原文地址:https://www.cnblogs.com/gongcomeon/p/9814071.html

时间: 2024-07-29 11:35:27

Zookeeper源码阅读(五) ACL基础的相关文章

Zookeeper源码阅读(十八) 选举之快速选举算法FastLeaderElection

目录 前言 FastLeaderEleaction基本结构 选举方法分析 思考 参考 前言 在过去的两节里已经分析了选举过程中的一些实体类和网络IO相关的机制与源码,这一节将会对zookeeper选举的核心类FastLeaderElection进行分析. FastLeaderEleaction基本结构 可以看到FastLeaderElection的基本结构还是比较清晰的,主要从新的成员变量类和内部类来分析下FastLeaderElection的基本结构. Notification /** * N

Zookeeper源码阅读(九) ZK Client-Server(2)

前言 前面一篇博客主要从大致流程的角度说了下client和server建立连接的流程,这篇和下一篇博客会详细的把上一篇不是很细致的地方展开和补充. 初始化阶段 初始化阶段主要就是把Zookeeper类中比较重要的功能类实例化,前面对这个过程说的已经比较详细了.这里主要补充几点: ClientCnxn初始化 cnxn = new ClientCnxn(connectStringParser.getChrootPath(), hostProvider, sessionTimeout, this, w

Zookeeper源码阅读(十二) Seesion(1)

前言 前面三篇主要从client的角度说了下client和server建立连接的过程,这一篇和后面一篇开始看下Zookeeper中非常重要的一个概念:Session,session是zookeeper client和server建立和维护连接的单位(我这个描述感觉有点奇怪 ?? ). Session状态 Zookeeper的所有操作基本都是基于session的,如之前提到的wathcer的机制,客户端请求的顺序执行和临时节点的生命周期. 从我们使用API的角度,session的连接和保持就是客户

zookeeper 源码阅读---框架

1. 启动类 QuorumPeerMain.java 集群方式:调用runFromConfig(QuorumPeerConfig config) 创建一个QuorumPeer 对象,并初始化设置其相关属性,如ZKDatabase,ServerCnxnFactory成员等. QuorumPeer继承了Thread(ublic class QuorumPeer extends Thread implements QuorumStats.Provider),所以 调用 对象的 start() 和 jo

Zookeeper源码阅读(十四) 单机Server

前言 前面两篇主要说了下client-server的session相关的内容,到这里client的内容以及client-server的连接的内容也就基本告一段落了,剩下的部分就是server部分内部的结构,zk的选举以及server部分的工作机制等了. 这一篇主要说下单机server的启动过程,里面会涉及到一些server内部的工作机制和机构. Server架构 可以看到Zookeeper的server端主要分为几个大模块,ZKDatabase是zk server内部的内存数据库,内部维护了节点

SDWebImage源码阅读(五)SDImageCacheConfig/SDImageCache(下)

在上篇中已经了解分析了 SDImageCache.h 文件中所有的方法和属性.大概对 SDImageCache 能实现的功能已经有了全面的认识.在这篇则着重学习研究这些功能的实现过程和实现原理. SDImageCache  是 SDWebImage 里面用来做缓存的类,虽然只是针对的图片的缓存,但是其实在 iOS 开发甚至在程序开发中,缓存类对缓存文件的类型区别而要单独针对文件类型做处理的需要并不多,不管是图片的缓存还是别的类型文件的缓存,它们在缓存原理上是基本一致的.通过对 SDImageCa

JDK源码阅读(五)java.io.Serializable接口

package java.io; public interface Serializable { } (1)实现Serializable接口的类,将会被提示提供一个 serialVersionUID 注意点一.序列化时为了保持版本的兼容性,即在版本升级时反序列化仍保持对象的唯一性. 有两种生成方式:              ①一个是默认的1L,比如:private static final long serialVersionUID = 1L;              ②一个是根据类名.接口

Zookeeper源码阅读(七) Server端Watcher

前言 前面一篇主要介绍了Watcher接口相关的接口和实体类,但是主要是zk客户端相关的代码,如前一篇开头所说,client需要把watcher注册到server端,这一篇分析下server端的watcher. 主要分析Watchmanager类. Watchmanager 这是WatchManager的类图介绍.来看看代码: /** * This class manages watches. It allows watches to be associated with a string *

Struts2源码阅读(一)_Struts2框架流程概述

1. Struts2架构图  当外部的httpservletrequest到来时 ,初始到了servlet容器(所以虽然Servlet和Action是解耦合的,但是Action依旧能够通过httpservletrequest取得请求参数), 然后通过Filter chain,Filter主要包括ActionContextCleanUp,它主要清理当前线程的ActionContext和 Dispatcher:FilterDispatcher主要通过AcionMapper来决定需要调用哪个Actio