| ±à¼ÍƼö: |
±¾ÎÄÖ÷Òª½éÉÜͨ¹ýʵ¼Ê¹¤×÷ÖеÄÒ»¸öÀý×Ó£¬½²½âzookeeperÊÇÈçºÎ°ïÎÒ½â¾ö·Ö²¼Ê½ÎÊÌ⣬ÒÔ´ËÒýµ¼´ó¼Ò·¢ÏÖ×Ô¼ºÏµÍ³ÖпÉÒÔÓ¦ÓÃzookeeperµÄ³¡¾°¡£
À´×ÔÓÚCSDN,ÓÉ»ðÁú¹ûÈí¼þAlice±à¼¡¢ÍƼö¡£ |
|
ÏîÄ¿±³¾°½éÉÜ
Ê×Ïȸø´ó¼Ò½éÉÜһϱ¾ÎÄÃèÊöÏîÄ¿µÄÇé¿ö¡£ÕâÊÇÒ»¸ö¼ìË÷ÍøÕ¾£¬ËüÈÃÄãÄÜÔÚ¼¸Ç§Íò·Ý¸´ÔÓÎĵµÊý¾ÝÖмìË÷³öÄãËùÐèÒªµÄÎĵµÊý¾Ý¡£ÎªÁ˼ӿì¼ìË÷ËÙ¶È£¬ÏîÄ¿µÄÊý¾Ý·Ö²¼ÔÚ100̨»úÆ÷µÄÄÚ´æÀÎÒÃdzÆÖ®ÎªÊý¾Ý·þÎñÆ÷¡£³ýÁËÊý¾Ý£¬Õâ100̨»úÆ÷ÉϾù²¿Êð׿ìË÷³ÌÐò¡£ÕâЩserverÖ®Í⣬»¹ÓÐÊý̨¸øÇ°¶ËÌṩ½Ó¿ÚµÄËÑË÷server£¬ÕâЩ»úÆ÷ÊôÒ»¸ö¼¯Èº£¬ÎÒÃdzÆÖ®Îª¼ìË÷·þÎñÆ÷¡£µ±ËÑË÷ÇëÇó¹ýÀ´Ê±£¬ËûÃǸºÔð°ÑËÑË÷ÇëÇóת·¢µ½ÄÇ100̨»úÆ÷£¬´ýËùÓлúÆ÷·µ»Ø½á¹ûºó½øÐкϲ¢£¬×îÖÕ·µ»Ø¸øÇ°¶ËÒ³Ãæ¡£½á¹¹ÈçÏÂͼ£º

ÃæÁÙÎÊÌâ
ÍøÕ¾ÉÏÏßÖ®³õ£¬ÓÉÓÚÊý¾ÝÖ»Óм¸°ÙÍò£¬ËùÒÔÊý¾Ý·þÎñÆ÷Ö»ÓÐ10¶ą̀¡£ÊÇÒ»¸ö¹æÄ£±È½ÏСµÄ·Ö²¼Ê½ÏµÍ³£¬µ±Ê±Ã»ÓÐ×ö·Ö²¼Ê½ÏµÍ³µÄе÷£¬Ò²ÄÜÕý³£¹¤×÷£¬Å¼¶û³öÎÊÌ⣬ÂíÉϽâ¾ö¡£µ«Êǵ½Á˽üÆÚ£¬»úÆ÷Ôö³¤µ½100̨£¬ÍøÕ¾¼¸ºõÿÌì¶¼»á³öÏÖÎÊÌ⣬µ¼ÖÂÕû¸ö·Ö²¼Ê½ÏµÍ³¹Òµô¡£ÎÊÌâÔÒòÈçÏ£º
Êý¾Ý·þÎñÆ÷֮ǰûÓÐ×ö·Ö²¼Ê½Ðµ÷¡£¶ÔÓÚ¼ìË÷·þÎñÆ÷À´Ëµ£¬²¢²»ÖªµÀÄÄЩÊý¾Ý·þÎñÆ÷»¹´æ»î£¬ËùÒÔ¼ìË÷·þÎñÆ÷ÿ´Î¼ìË÷£¬¶¼»áµÈ´ý100̨»úÆ÷·µ»Ø½á¹û¡£µ«¼ÙÈç100̨Êý¾Ý·þÎñÖÐijһ̨ËÀµôÁË£¬¼ìË÷·þÎñÆ÷Ò²»á³¤Ê±¼äµÈ´ýËûµÄ·µ»Ø¡£Õâµ¼ÖÂÁ˼ìË÷·þÎñÆ÷»ýÀÛÁË´óÁ¿µÄÇëÇó£¬×îÖÕ±»Ñ¹¿å¡£µ±ËùÓеļìË÷·þÎñÆ÷¶¼±»Ñ¹¿åʱ£¬ÄÇÃ´ÍøÕ¾Ò²¾Í³¹µ×²»¿ÉÓÃÁË¡£

ÎÊÌâµÄ±¾ÖÊΪ¼ìË÷·þÎñÆ÷ά»¤µÄÊý¾Ý·þÎñÆ÷ÁбíÊǾ²Ì¬²»±äµÄ£¬²»ÄܸÐÖªÊý¾Ý·þÎñÆ÷µÄÉÏÏÂÏß¡£

ÔÚ10̨Êý¾Ý·þÎñÆ÷µÄʱºò£¬Ä³Ò»Ì¨»úÆ÷³öÎÊÌâµÄ¸ÅÂʺÜС¡£µ«µ±Ôö³¤µ½100̨·þÎñÆ÷ʱ£¬³öÎÊÌâµÄ¸ÅÂʱä³ÉÁË10±¶¡£ËùÒԲŻᵼÖÂÍøÕ¾¼¸ºõÿÌì¶¼ÒªËÀµôÒ»´Î¡£
ÓÉÓÚһ̨»úÆ÷µÄÎÊÌ⣬µ¼ÖÂ100̨»úÆ÷µÄ·Ö²¼Ê½ÏµÍ³²»¿ÉÓã¬ÕâÊǼ«Æä²»ºÏÀí£¬Ò²ÊÇÎÞ·¨ÈÌÊܵġ£
֮ǰ´ËÏîÄ¿µÄÊý¾ÝºÍ¼ìË÷²»ÓÉÎÒ¸ºÔð¡£Á˽⵽´ËÎÊÌâµÄʱºò£¬ÎÒ¾õµÃÕâ¸öÎÊÌâµÃÁ¢¿Ì½â¾ö£¬·ñÔò²»µ«Óû§ÌåÑé²î£¬¶øÇÒ¿ª·¢ºÍÔËάҲҪÿÌìÆ£ÓÚϵͳά»¤£¬ÀË·ÑÁË´óÁ¿×ÊÔ´£¬µ«ÓÉÓÚ»¹ÓкܶàеÄÐèÇóÔÚ¿ª·¢£¬ÔÀ´µÄÍŶÓҲûʱ¼äÈ¥´¦Àí¡£½ñÄêÎÒÓлú»áÀ´½â¾öÕâ¸öÎÊÌ⣬µ±Ê±ÕýºÃ¸Õ¸ÕÑо¿Íêzookeeper£¬Á¢¿ÌÏëµ½ÕâÕýÊDzÉÓÃzookeeperµÄµäÐͳ¡¾°¡£
ÈçºÎ½â¾ö
ÎÒÖ±½Ó˵·½°¸£¬³ÌÐò·ÖΪÊý¾Ý·þÎñÆ÷ºÍ¼ìË÷·þÎñÆ÷Á½²¿·Ö¡£
Êý¾Ý·þÎñÆ÷£º
1¡¢Ã¿Ì¨Êý¾Ý·þÎñÆ÷Æô¶¯Ê±ºòÒÔÁÙʱ½ÚµãµÄÐÎʽ°Ñ×Ô¼º×¢²áµ½zookeeperµÄij½ÚµãÏ£¬Èç/data_servers¡£ÕâÑùµ±Ä³Êý¾Ý·þÎñÆ÷ËÀµôʱ£¬session¶Ï¿ªÁ´½Ó£¬¸Ã½Úµã±»É¾³ý¡£
¼ìË÷·þÎñÆ÷£º
1¡¢Æô¶¯Ê±£¬¼ÓÔØ/data_serversÏÂËùÓÐ×Ó½ÚµãÊý¾Ý£¬»ñÈ¡ÁËĿǰËùÓÐÄÜÌṩ·þÎñµÄÊý¾Ý·þÎñÆ÷ÁÐ±í£¬²¢ÇÒ¼ÓÔØµ½ÄÚ´æÖС£
2¡¢Æô¶¯Ê±£¬Í¬Ê±¼àÌý/data_servers½Úµã£¬µ±ÐµÄÊý¾ÝserverÉÏÏß»òÕßij¸öserverÏÂÏßʱ£¬»ñµÃ֪ͨ£¬È»ºóÖØÐ¼ÓÔØ/data_serversÏÂËùÓÐ×Ó½ÚµãÊý¾Ý£¬Ë¢ÐÂÄÚ´æÖÐÊý¾Ý·þÎñÆ÷ÁÐ±í¡£
ͨ¹ýÒÔÉÏ·½°¸£¬×öµ½Êý¾Ý·þÎñÆ÷ÉÏÏÂÏßʱ£¬¼ìË÷·þÎñÆ÷Äܹ»¶¯Ì¬¸ÐÖª¡£¼ìË÷·þÎñÆ÷ÔÚ¼ìË÷ǰ£¬´ÓÄÚ´æÖÐÈ¡µÃµÄÊý¾Ý·þÎñÆ÷ÁÐ±í½«ÊÇ×îеġ¢¿ÉÓõġ£¼´Ê¹ÔÚË¢ÐÂʱ¼ä²îÄÚÈ¡µ½Á˵ôÏßµÄÊý¾Ý·þÎñÆ÷Ҳû¹ØÏµ£¬×î¶àÓ°Ïì±¾´Î²éѯ£¬¶ø²»»áÍÏ¿åÕû¸ö¼¯Èº¡£¼ûÏÂͼ£º

´úÂë½²½â
ÞÛÇå˼·ºó£¬Æäʵ´úÂë¾Í±È½Ï¼òµ¥ÁË¡£Êý¾Ý·þÎñÆ÷Ö»ÐèÒªÆô¶¯µÄʱºòдzookeeperÁÙʱ½Úµã¾ÍºÃÁË£¬Í¬Ê±Ð´Èë×Ô¼º·þÎñÆ÷µÄÏà¹ØÐÅÏ¢£¬±ÈÈçip¡¢portÖ®Àà¡£¼ìË÷ÎÞ·þÎñÆ÷¶Ë»áÉÔ΢¸´Ôӵ㣬²»¹ý´Ë´¦³¡¾°ºÍzookeeper¹Ù·½¸øµÄÀý×ÓÊ®·Ö·ûºÏ£¬ËùÒÔÎÒÖ±½Ó²Î¿¼¹Ù·½Àý×Ó½øÐÐÐ޸ģ¬ÊµÏÖÆðÀ´Ò²ºÜ¼òµ¥¡£
Êý¾Ý·þÎñÆ÷
Êý¾Ý·þÎñÆ÷³ÌÐòÊ®·Ö¼òµ¥£¬Ö»»á×öÒ»¼þÊÂÇ飺Æô¶¯µÄʱºò£¬°Ñ×Ô¼ºÒÔÁÙʱ½ÚµãµÄÐÎʽע²áµ½zookeeper¡£Ò»µ©·þÎñÆ÷¹Òµô£¬zookeeper×Ô¶¯É¾³ýÁÙʱznode¡£
ÎÒÃÇ´´½¨ServiceRegister.javaʵÏÖRunnable£¬Êý¾Ý·þÎñÆô¶¯µÄʱºò£¬µ¥¶ÀÏß³ÌÔËÐд˴úÂ룬ʵÏÖ×¢²áµ½zookeeperÂß¼¡£Î¬ÏµºÍzookeeperµÄÁ´½Ó¡£
¼ìË÷·þÎñÆ÷
¼ìË÷·þÎñÆ÷£¬´úÂëÉè¼ÆÍêÈ«²ÉÓùٷ½°¸Àý£¬ËùÒÔÏêϸµÄ´úÂë½â¶ÁÇë²Î¿¼ÉÏÃæÌáµ½µÄÁ½ÆªÎÄÕ£¬ÕâÀïÖ»×öϼòÊö¡£
´úÂëÓÐÁ½¸öÀàDataMonitorºÍLoadSaidsExecutor¡£LoadSaidsExecutorÊÇÆô¶¯Èë¿Ú£¬ËûÀ´Æô¶¯DataMonitor¼à¿Øzookeeper½Úµã±ä»¯¡£DataMonitor¸ºÔð¼à¿Ø£¬³õ´ÎÆô¶¯ºÍ·¢Ïֱ仯ʱ£¬µ÷ÓÃLoadSaidsExecutorµÄ·½·¨À´¼ÓÔØ×îеÄÊý¾Ý·þÎñÆ÷ÁбíÐÅÏ¢¡£
DataMonitorºÍLoadSaidsExecutorµÄ¹¤×÷Á÷³ÌÈçÏ£º

Excutor°Ñ×Ô¼º×¢²áΪDataMonitorµÄ¼àÌý
DataMonitorʵÏÖwatcher½Ó¿Ú£¬²¢¼àÌýznode
znode±ä»¯Ê±£¬´¥·¢DataMonitorµÄ¼àÌý»Øµ÷
»Øµ÷ÖÐͨ¹ýZooKeeper.exist() ÔٴμàÌýznode
ÉÏÒ»²½existµÄ»Øµ÷·½·¨ÖУ¬µ÷ÓüàÌý×Ô¼ºµÄExecutor£¬Ö´ÐÐÒµÎñÂß¼6
ExecutorÆôеÄÏ̼߳ÓÔØÊý¾Ý·þÎñÆ÷ÐÅÏ¢µ½ÄÚ´æÖÐ
×¢Ò⣺ͼΪÒÔǰÎÄÕÂÅäͼ¡£Í¼ÀïÓ¦¸Ã°Ñ6£¬7²½¸ÄΪÎÄ×ÖÃèÊöµÄµÚ6²½¡£
¼ìË÷·þÎñÆô¶¯µÄʱºò£¬µ¥¶ÀÏß³ÌÔËÐÐLoadSaIdsExecutor¡£LoadSaIdsExecutor»á×èÈûỊ̈߳¬×ªÎªÊ¼þÇý¶¯¡£
×ܽá
ÎÒÃÇͨ¹ýÒ»¸öÀý×Ó£¬Õ¹Ê¾ÁËzookeeperÔÚʵ¼ÊϵͳÖеÄÓ¦Óã¬Í¨¹ýzookeeper½â¾öÁË·Ö²¼Ê½ÏµÍ³µÄÎÊÌâ¡£ÆäʵÒÔÉÏ´úÂ뻹ÓкܴóµÄÓÅ»¯¿Õ¼ä¡£ÎÒÄÜÏëµ½ÈçÏÂÁ½µã£º
1¡¢Êý¾Ý·þÎñÆ÷»á¼ÙËÀ»òÕß±äÂý£¬µ«ºÍzkÁ´½Ó»¹ÔÚ£¬²¢²»»á´ÓzkÖÐɾ³ý£¬µ«ÒѾÍÏÂýÁ˼¯ÈºµÄËÙ¶È¡£½â¾ö´ËÎÊÌ⣬ÎÒÃÇ¿ÉÒÔÔÚÊý¾Ý·þÎñÆ÷ÖмÓÈ붨ʱÈÎÎñ£¬Í¨¹ý¶¨Ê±ÅÜÕæÊµÒµÎñ²éѯ£¬¼à¿Ø·þÎñÆ÷״̬£¬Ò»µ©´ïµ½É趨µÄºìÏßãÐÖµ£¬Ç¿ÖÆÏÂÏߣ¬¶ø²»Êǵȵ½server³¹µ×ËÀµô¡£
2¡¢¼ìË÷·þÎñÆ÷ÿ¸öserver¶¼¼à¿Øzookeeperͬһ¸ö½Úµã£¬ÔÚ½Úµã±ä»¯Ê±»á³öÏÖÑòȺЧӦ¡£µ±È»£¬¼ìË÷·þÎñÆ÷Èç¹ûÊýÁ¿²»¶à»¹ºÃ¡£Æäʵ¼ìË÷·þÎñÆ÷Ó¦¸Ãͨ¹ýzookeeper×öÒ»¸öleaderÑ¡¾Ù£¬Ö»ÓÉleaderÈ¥¼à¿Øzookeeper½Úµã±ä»¯£¬¸üÐÂredisÖеÄÊý¾Ý·þÎñÆ÷ÁÐ±í»º´æ¼´¿É¡£
¸½£ºÍêÕû´úÂë
Êý¾Ý·þÎñ¶Ë´úÂë
public class
ServiceRegister implements Runnable{
private ZooKeeper zk;
private static final String ZNODE = "/sas";
private static final String SA_NODE_PREFIX = "sa_";
private String hostName="localhost:2181";
public void setHostName(String hostName) {
this.hostName = hostName;
}
public ServiceRegister() throws IOException {
zk = new ZooKeeper(hostName, 10000,null);
}
@Override
public void run() {
try {
createSaNode();
synchronized (this) {
wait();
}
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//²âÊÔÓÃ
public static void main(String[] args){
try {
new ServiceRegister().run();
} catch (IOException e) {
e.printStackTrace();
}
}
//´´½¨×Ó½Úµã
private String createSaNode() throws KeeperException,
InterruptedException {
// Èç¹û¸ù½Úµã²»´æÔÚ£¬Ôò´´½¨¸ù½Úµã
Stat stat = zk.exists(ZNODE, false);
if (stat == null) {
zk.create(ZNODE, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE,
CreateMode.PERSISTENT);
}
String hostName = System.getenv("HOSTNAME");
// ´´½¨EPHEMERAL_SEQUENTIALÀàÐͽڵã
String saPath = zk.create(ZNODE + "/"
+ SA_NODE_PREFIX,
hostName.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE,
CreateMode.EPHEMERAL_SEQUENTIAL);
return saPath;
}
} |
¼ìË÷·þÎñ¶Ë´úÂë
DataMonitor.java
public class
DataMonitor implements Watcher, AsyncCallback.ChildrenCallback
{
ZooKeeper zk;
String znode;
Watcher chainedWatcher;
boolean dead;
DataMonitorListener listener;
List<String> prevSaIds;
public DataMonitor(ZooKeeper zk, String znode,
Watcher chainedWatcher,
DataMonitorListener listener) {
this.zk = zk;
this.znode = znode;
this.chainedWatcher = chainedWatcher;
this.listener = listener;
// ÕâÊÇÕû¸ö¼à¿ØµÄÕæÕý¿ªÊ¼£¬Í¨¹ý»ñÈ¡children½Úµã¿ªÊ¼¡£ÉèÖÃÁ˱¾¶ÔÏóΪ¼à¿Ø¶ÔÏ󣬻ص÷¶ÔÏóÒ²ÊDZ¾¶ÔÏó¡£ÒÔºó¾ùÊÇʼþÇý¶¯¡£
zk.getChildren(znode, true, this, null);
}
/**
* ÆäËûºÍmonitor²úÉú½»»¥µÄÀ࣬ÐèҪʵÏÖ´Ëlistener
*/
public interface DataMonitorListener {
/**
* The existence status of the node has changed.
*/
void changed(List<String> saIds);
/**
* The ZooKeeper session is no longer valid.
*
* @param rc
* the ZooKeeper reason code
*/
void closing(int rc);
}
/*
*¼à¿Ø/saidsµÄ»Øµ÷º¯Êý¡£³ýÁË´¦ÀíÒì³£Íâ¡£
*Èç¹û·¢Éú±ä»¯£¬ºÍ¹¹Ô캯ÊýÖÐÒ»Ñù£¬Í¨¹ýgetChildren£¬ÔÙ´Î¼à¿Ø£¬²¢´¦Àíchildren½Úµã±ä»¯ºóµÄÒµÎñ
*/
public void process(WatchedEvent event) {
String path = event.getPath();
if (event.getType() == Event.EventType.None) {
// We are are being told that the state of the
// connection has changed
switch (event.getState()) {
case SyncConnected:
// In this particular example we don't need to
do anything
// here - watches are automatically re-registered
with
// server and any watches triggered while the
client was
// disconnected will be delivered (in order of
course)
break;
case Expired:
// It's all over
dead = true;
listener.closing(Code.SESSIONEXPIRED.intValue());
break;
}
} else {
if (path != null && path.equals(znode))
{
// Something has changed on the node, let's find
out
zk.getChildren(znode, true, this, null);
}
}
if (chainedWatcher != null) {
chainedWatcher.process(event);
}
}
//Äõ½Children½ÚµãºóµÄ»Øµ÷º¯Êý¡£
@Override
public void processResult(int rc, String path,
Object ctx, List<String> children) {
boolean exists;
switch (rc) {
case Code.Ok:
exists = true;
break;
case Code.NoNode:
exists = false;
break;
case Code.SessionExpired:
case Code.NoAuth:
dead = true;
listener.closing(rc);
return;
default:
// Retry errors
zk.getChildren(znode, true, this, null);
return;
}
List<String> saIds = null;
//Èç¹û´æÔÚ£¬Ôٴβéѯµ½×îÐÂchildren£¬´Ëʱ½ö²éѯ£¬²»ÒªÉèÖÃ¼à¿ØÁË
if (exists) {
try {
saIds = zk.getChildren(znode,null);
} catch (KeeperException e) {
// We don't need to worry about recovering now.
The watch
// callbacks will kick off any exception handling
e.printStackTrace();
} catch (InterruptedException e) {
return;
}
}
//Äõ½×îÐÂsaidsºó£¬Í¨¹ýlistener£¨executor£©£¬¼ÓÔØSaids¡£
if ((saIds == null && saIds != prevSaIds)
|| (saIds != null && !saIds.equals(prevSaIds)))
{
listener.changed(saIds);
prevSaIds = saIds;
}
}
} |
LoadSaIdsExecutor.java
public class LoadSaIdsExecutor
implements Watcher, Runnable, DataMonitor.DataMonitorListener
{
private DataMonitor dm;
private ZooKeeper zk;
private static final String znode = "/sas";
private String hostName="localhost:2181";
public void setHostName(String hostName) {
this.hostName = hostName;
}
/*
*³õʼ»¯zookeeper¼°DataMonitor
* ×Ô¼º×÷ΪzookeeperµÄ¼à¿ØÕߣ¬¼à¿ØºÍzookeeperÁ¬½ÓµÄ±ä»¯
* ×Ô¼º×÷ΪDataMonitorµÄlistener¡£µ±dm¼à¿Øµ½±ä»¯Ê±»áµ÷ÓÃexecutorÖ´ÐÐÒµÎñ²Ù×÷
*/
public LoadSaIdsExecutor() throws KeeperException,
IOException {
zk = new ZooKeeper(hostName, 300000, this);
dm = new DataMonitor(zk, znode, null, this);
}
/**
* Èë¿Ú·½·¨,²âÊÔÓá£
*/
public static void main(String[] args) {
try {
new LoadSaIdsExecutor().run();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* ×÷Ϊµ¥¶ÀÏß³ÌÔËÐÐ
*/
public void run() {
try {
synchronized (this) {
while (!dm.dead) {
wait();
}
}
} catch (InterruptedException e) {
}
}
/*
*×÷Ϊzookeeper¼à¿ØÕߵĻص÷£¬Ö±½Ó´«µÝʼþ¸ømonitorµÄ»Øµ÷º¯Êýͳһ´¦Àí
*/
@Override
public void process(WatchedEvent event) {
dm.process(event);
}
/*
*µ±¹Ø±Õʱ£¬ÈÃÏß³ÌÏß¼ÌÐø×ßÍê
*/
public void closing(int rc) {
synchronized (this) {
notifyAll();
}
}
/*
*¼à¿Øµ½/saids±ä»¯ºóµÄ´¦ÀíÀà
*/
static class SaIdsLoader extends Thread {
List<String> saIds = null;
//¹¹Ôì¶ÔÏóºóÖ±½ÓÆô¶¯Ïß³Ì
public SaIdsLoader(List<String> saIds){
this.saIds = saIds;
start();
}
public void run() {
System.out.println("------------¼ÓÔØ¿ªÊ¼------------");
//ÒµÎñ´¦ÀíµÄµØ·½
if(saIds!=null){
saIds.forEach(id->{
System.out.println(id);
});
}
System.out.println("------------¼ÓÔØ½áÊø------------");
}
}
/*
*×÷Ϊlistener¶ÔÍⱩ¶µÄ·½·¨£¬ÔÚ½Úµã/saids±ä»¯Ê±±»µ÷Óá£
*/
@Override
public void changed(List<String> data) {
new SaIdsLoader(data);
}
} |
|