精华内容
下载资源
问答
  • 互亿无线短信平台接口java实现

    千次阅读 2019-02-22 11:01:55
    //接口类型:互亿无线触发短信接口,支持发送验证码短信、订单通知短信等。 // 账户注册:请通过该地址开通账户http://user.ihuyi.com/register.html // 注意事项: //(1)调试期间,请使用用系统默认的短信内容:...
    //接口类型:互亿无线触发短信接口,支持发送验证码短信、订单通知短信等。
    // 账户注册:请通过该地址开通账户http://user.ihuyi.com/register.html
    // 注意事项:
    //(1)调试期间,请使用用系统默认的短信内容:您的验证码是:【变量】。请不要把验证码泄露给其他人。
    //(2)请使用 APIID 及 APIKEY来调用接口,可在会员中心获取;
    //(3)该代码仅供接入互亿无线短信接口参考使用,客户可根据实际需要自行编写;
    
    import java.io.IOException;
    
    import org.apache.commons.httpclient.HttpClient;
    import org.apache.commons.httpclient.HttpException;
    import org.apache.commons.httpclient.NameValuePair;
    import org.apache.commons.httpclient.methods.PostMethod;
    
    import org.dom4j.Document;   
    import org.dom4j.DocumentException;
    import org.dom4j.DocumentHelper;   
    import org.dom4j.Element;   
    
    import util.StringUtil;
    
    public class sendsms {
    	
    	private static String Url = "http://106.ihuyi.com/webservice/sms.php?method=Submit";
    	
    	public static void main(String [] args) {
    		
    		HttpClient client = new HttpClient(); 
    		PostMethod method = new PostMethod(Url);
    
    		client.getParams().setContentCharset("GBK");
    		method.setRequestHeader("ContentType","application/x-www-form-urlencoded;charset=GBK");
    
    		int mobile_code = (int)((Math.random()*9+1)*100000);
    
    	    String content = new String("您的验证码是:" + mobile_code + "。请不要把验证码泄露给其他人。");
    
    		NameValuePair[] data = {//提交短信
    			    new NameValuePair("account", "用户名"), //查看用户名 登录用户中心->验证码通知短信>产品总览->API接口信息->APIID
    			    new NameValuePair("password", "密码"), //查看密码 登录用户中心->验证码通知短信>产品总览->API接口信息->APIKEY
    			    //new NameValuePair("password", util.StringUtil.MD5Encode("密码")),
    			    new NameValuePair("mobile", "手机号码"), 
    			    new NameValuePair("content", content),
    		};
    		method.setRequestBody(data);
    
    		try {
    			client.executeMethod(method);
    			
    			String SubmitResult =method.getResponseBodyAsString();
    
    			//System.out.println(SubmitResult);
    
    			Document doc = DocumentHelper.parseText(SubmitResult);
    			Element root = doc.getRootElement();
    
    			String code = root.elementText("code");
    			String msg = root.elementText("msg");
    			String smsid = root.elementText("smsid");
    
    			System.out.println(code);
    			System.out.println(msg);
    			System.out.println(smsid);
    
    			 if("2".equals(code)){
    				System.out.println("短信提交成功");
    			}
    
    		} catch (HttpException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		} catch (IOException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		} catch (DocumentException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}	
    		
    	}
    	
    
    展开全文
  • Java模拟.NET的连接

    千次阅读 2006-09-20 22:21:00
    作者 : manboo 标题 : Java模拟.NET的连接池 关键字: Java;.NET;连接池 分类 : 开发经验
    作者 : manboo
    标题 : Java模拟.NET的连接池
    关键字: Java;.NET;连接池
    分类 : 开发经验
    密级 : 参赛
     

    (评分:★★★★ , 回复: 2, 阅读: 512)
    在之前:

       .NET的ADO.NET的本身包含连接池功能,而java是在第三方开发包中提高的连接池功能因此,需要去下载第三方的连接池包,但是java的连接池一般都是在EJB或者B/S系统中使用的(虽然也有C/S下的连接池如Borland 在Jbuilder中提供的),在一个服务性系统中使用起来不是很方便.再说使用第三方的开发包也不利于维护.因此决定自己写一个连接池的开发包.此连接池中主要解决的是提高数据库访问性能,并且尽可能减少连接数目.

    说明:

       此连接池有三个类和一个接口组成,三个类分别是:

    DBConnectionPool 数据库连接池,用户可以通过此类来使用连接池的功能.

    PoolConnection 一个实现了java.sql.Connection的warp类,用来和数据库进行通讯.

    theOnClose 实现了接口OnConnectionClose的一个类用还处理释放数据库连接的是动作决定是关闭数据库还是返回池中

    接口 :

     OnConnectionClose:此接口是一个声明,因为本人很不喜欢java的事件机制因此,我经常自己写一些接口来模拟时间,没有java的事件机制那么强大也没有那么复杂.但是效率要比java的事件机制要高那么一点点(笑:).

    本来要上传这几个小类的UML图的但是我一点IE就死,所以算了.就只上传代码.还望方家指正.

    代码:

    package DBTools;

    /**
    * <p>T数据库连接池工具 </p>
    * <p>模拟.NET的连接池,俺一直以为.NET比java优秀 </p>
    * <p>Copyright: 可以随便使用,如果有改进最好通知俺</p>
    * <p>Company:自己作品 </p>
    * @author董平雷
    * @version 1.0
    */
    import java.sql.*;
    import java.util.*;
    import java.io.*;

    interface OnConnectionClose {
     public void Action(PoolConnection sender);

    }

    public class DBConnectionPool {

     private static Vector pConnectionVector = new Vector();
     // private static int Count=0;
     private static int minCount = 1;
     private static String URL = "";
     private static String User = "";
     private static String Password = "";
     private static String DriverName="";
    synchronized public static void setMinCount(int Value) {
      minCount = Value;
     }

    synchronized public static int getMinCount() {
      return minCount;
     }

    synchronized public static int getCout() {
      return pConnectionVector.size();
     }

    synchronized public static Connection getConnection() throws SQLException {
      PoolConnection pConnection = null;
      // int aCount=pConnectionVector.size();

      for (int I = 0; I < pConnectionVector.size(); i++) {
       Object oCon = pConnectionVector.elementAt(i);
       if (oCon instanceof PoolConnection) {
        PoolConnection aCon = (PoolConnection) oCon;
        if (!aCon.isUsed()) {
         pConnection = aCon;
         break;
        }

       }

      }
      if (pConnection == null) {
       pConnection = getNewConnection();
       pConnectionVector.add(pConnection);
      }
      return pConnection;

     }

     private static PoolConnection getNewConnection() throws SQLException {
      try
      {
        Class.forName( DriverName);
      }catch(ClassNotFoundException ex)
      {
       ex.printStackTrace();
      }
      PoolConnection con = new PoolConnection(URL, User, Password);
      con.setOnClose(new theOnClose(pConnectionVector));
      return con;
     }

    synchronized public static void SetJDBC(String url, String user, String password) {
      URL = url;
      User = user;
      Password = password;

     }

    synchronized public static void setURL(String url) {
      URL = url;

     }

    synchronized public static String getUrl() {
      return URL;

     }
    synchronized public static void setUser(String user)
     {
       User=user;
     }
    synchronized public static String getUser()
     {
      return User;
     }
    synchronized public static void setPassword(String password)
     {
      Password=password;
     }
    synchronized public static String getPassword()
     {
      return Password;
     }

    synchronized public static void setDriverName(String dName)
    {
      DriverName=dName;

    }
    synchronized public static String getDriverName()
     {
      return DriverName;
     }
    }
    class theOnClose
      implements OnConnectionClose {
     private Vector v;
     public theOnClose(Vector vt) {
      v = vt;
     }

     public void Action(PoolConnection sender) {
      v.remove(sender);

     }
    }

    class PoolConnection
      implements Connection , Serializable{
     private Connection aCon = null;
     private boolean closed = false;
     private boolean inUse = false;
     private String DriverName;
     private OnConnectionClose onClose = null;
     private void writeObject(ObjectOutputStream oos) throws IOException {
       oos.defaultWriteObject();
     }
     private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
      ois.defaultReadObject();
     }
     protected PoolConnection() {
     }

     public PoolConnection(String Url, String User, String Password) throws
       SQLException {

      aCon = DriverManager.getConnection(Url, User, Password);
      closed = false;
      inUse=true;

     }

     public PoolConnection(String Url) throws Exception {
      aCon = DriverManager.getConnection(Url);
      closed = false;
      inUse=true;
     }

     public Statement createStatement() throws SQLException {
      /**@todo Implement this java.sql.Connection method*/
      //throw new java.lang.UnsupportedOperationException("Method createStatement() not yet implemented.");
      return aCon.createStatement();
     }

     public PreparedStatement prepareStatement(String sql) throws SQLException {
      /**@todo Implement this java.sql.Connection method*/
      //throw new java.lang.UnsupportedOperationException("Method prepareStatement() not yet implemented.");
      return aCon.prepareStatement(sql);
     }

     public CallableStatement prepareCall(String sql) throws SQLException {
      /**@todo Implement this java.sql.Connection method*/
      //throw new java.lang.UnsupportedOperationException("Method prepareCall() not yet implemented.");
      return aCon.prepareCall(sql);
     }

     public String nativeSQL(String sql) throws SQLException {
      /**@todo Implement this java.sql.Connection method*/
      // throw new java.lang.UnsupportedOperationException("Method nativeSQL() not yet implemented.");
      return aCon.nativeSQL(sql);
     }

     public void setAutoCommit(boolean autoCommit) throws SQLException {
      /**@todo Implement this java.sql.Connection method*/
      // throw new java.lang.UnsupportedOperationException("Method setAutoCommit() not yet implemented.");
      aCon.setAutoCommit(autoCommit);
     }

     public boolean getAutoCommit() throws SQLException {
      /**@todo Implement this java.sql.Connection method*/
      // throw new java.lang.UnsupportedOperationException("Method getAutoCommit() not yet implemented.");
      return aCon.getAutoCommit();
     }

     public void commit() throws SQLException {
      /**@todo Implement this java.sql.Connection method*/
      // throw new java.lang.UnsupportedOperationException("Method commit() not yet implemented.");
      aCon.commit();
     }

     public void rollback() throws SQLException {
      /**@todo Implement this java.sql.Connection method*/
      //throw new java.lang.UnsupportedOperationException("Method rollback() not yet implemented.");
      aCon.rollback();
     }

     public void close() throws SQLException {
      /**@todo Implement this java.sql.Connection method*/
      //throw new java.lang.UnsupportedOperationException("Method close() not yet implemented.");
      if(DBConnectionPool.getCout()<=DBConnectionPool.getMinCount())
      {
      inUse = false;
      }else
      {
      closeConnection();
      }


     }

     public boolean isClosed() throws SQLException {
      /**@todo Implement this java.sql.Connection method*/
      //throw new java.lang.UnsupportedOperationException("Method isClosed() not yet implemented.");
      return closed;
     }

     public DatabaseMetaData getMetaData() throws SQLException {
      /**@todo Implement this java.sql.Connection method*/
      // throw new java.lang.UnsupportedOperationException("Method getMetaData() not yet implemented.");
      return aCon.getMetaData();
     }

     public void setReadOnly(boolean readOnly) throws SQLException {
      /**@todo Implement this java.sql.Connection method*/
      // throw new java.lang.UnsupportedOperationException("Method setReadOnly() not yet implemented.");
      aCon.setReadOnly(readOnly);
     }

     public boolean isReadOnly() throws SQLException {
      /**@todo Implement this java.sql.Connection method*/
      // throw new java.lang.UnsupportedOperationException("Method isReadOnly() not yet implemented.");
      return isReadOnly();
     }

     public void setCatalog(String catalog) throws SQLException {
      /**@todo Implement this java.sql.Connection method*/
      // throw new java.lang.UnsupportedOperationException("Method setCatalog() not yet implemented.");
      aCon.setCatalog(catalog);
     }

     public String getCatalog() throws SQLException {
      /**@todo Implement this java.sql.Connection method*/
      //throw new java.lang.UnsupportedOperationException("Method getCatalog() not yet implemented.");
      return aCon.getCatalog();
     }

     public void setTransactionIsolation(int level) throws SQLException {
      /**@todo Implement this java.sql.Connection method*/
      // throw new java.lang.UnsupportedOperationException("Method setTransactionIsolation() not yet implemented.");
      aCon.setTransactionIsolation(level);
     }

     public int getTransactionIsolation() throws SQLException {
      /**@todo Implement this java.sql.Connection method*/
      // throw new java.lang.UnsupportedOperationException("Method getTransactionIsolation() not yet implemented.");
      return aCon.getTransactionIsolation();
     }

     public SQLWarning getWarnings() throws SQLException {
      /**@todo Implement this java.sql.Connection method*/
      // throw new java.lang.UnsupportedOperationException("Method getWarnings() not yet implemented.");
      return aCon.getWarnings();
     }

     public void clearWarnings() throws SQLException {
      /**@todo Implement this java.sql.Connection method*/
      //throw new java.lang.UnsupportedOperationException("Method clearWarnings() not yet implemented.");
      aCon.clearWarnings();
     }

     public Statement createStatement(int resultSetType, int resultSetConcurrency) throws
       SQLException {
      /**@todo Implement this java.sql.Connection method*/
      // throw new java.lang.UnsupportedOperationException("Method createStatement() not yet implemented.");
      return aCon.createStatement(resultSetType, resultSetConcurrency);
     }

     public PreparedStatement prepareStatement(String sql, int resultSetType,
                          int resultSetConcurrency) throws
       SQLException {
      /**@todo Implement this java.sql.Connection method*/
      // throw new java.lang.UnsupportedOperationException("Method prepareStatement() not yet implemented.");
      return aCon.prepareStatement(sql, resultSetType, resultSetConcurrency);
     }

     public CallableStatement prepareCall(String sql, int resultSetType,
                        int resultSetConcurrency) throws
       SQLException {
      /**@todo Implement this java.sql.Connection method*/
      //throw new java.lang.UnsupportedOperationException("Method prepareCall() not yet implemented.");
      return aCon.prepareCall(sql, resultSetType, resultSetConcurrency);
     }

     public Map getTypeMap() throws SQLException {
      /**@todo Implement this java.sql.Connection method*/
      //throw new java.lang.UnsupportedOperationException("Method getTypeMap() not yet implemented.");
      return aCon.getTypeMap();
     }

     public void setTypeMap(Map map) throws SQLException {
      /**@todo Implement this java.sql.Connection method*/
      //throw new java.lang.UnsupportedOperationException("Method setTypeMap() not yet implemented.");
      aCon.setTypeMap(map);
     }

     public void setHoldability(int holdability) throws SQLException {
      /**@todo Implement this java.sql.Connection method*/
      // throw new java.lang.UnsupportedOperationException("Method setHoldability() not yet implemented.");
      aCon.setHoldability(holdability);
     }

     public int getHoldability() throws SQLException {
      /**@todo Implement this java.sql.Connection method*/
      // throw new java.lang.UnsupportedOperationException("Method getHoldability() not yet implemented.");
      return aCon.getHoldability();
     }

     public Savepoint setSavepoint() throws SQLException {
      /**@todo Implement this java.sql.Connection method*/
      //throw new java.lang.UnsupportedOperationException("Method setSavepoint() not yet implemented.");
      return setSavepoint();
     }

     public Savepoint setSavepoint(String name) throws SQLException {
      /**@todo Implement this java.sql.Connection method*/
      // throw new java.lang.UnsupportedOperationException("Method setSavepoint() not yet implemented.");
      return setSavepoint(name);
     }

     public void rollback(Savepoint savepoint) throws SQLException {
      /**@todo Implement this java.sql.Connection method*/
      //throw new java.lang.UnsupportedOperationException("Method rollback() not yet implemented.");
      aCon.rollback(savepoint);
     }

     public void releaseSavepoint(Savepoint savepoint) throws SQLException {
      /**@todo Implement this java.sql.Connection method*/
      // throw new java.lang.UnsupportedOperationException("Method releaseSavepoint() not yet implemented.");
      aCon.releaseSavepoint(savepoint);
     }

     public Statement createStatement(int resultSetType, int resultSetConcurrency,
                      int resultSetHoldability) throws
       SQLException {
      /**@todo Implement this java.sql.Connection method*/
      //throw new java.lang.UnsupportedOperationException("Method createStatement() not yet implemented.");
      return aCon.createStatement(resultSetType, resultSetConcurrency,
                    resultSetHoldability);
     }

     public PreparedStatement prepareStatement(String sql, int resultSetType,
                          int resultSetConcurrency,
                          int resultSetHoldability) throws
       SQLException {
      /**@todo Implement this java.sql.Connection method*/
      // throw new java.lang.UnsupportedOperationException("Method prepareStatement() not yet implemented.");
      return aCon.prepareStatement(sql, resultSetType, resultSetConcurrency,
                     resultSetHoldability);
     }

     public CallableStatement prepareCall(String sql, int resultSetType,
                        int resultSetConcurrency,
                        int resultSetHoldability) throws
       SQLException {
      /**@todo Implement this java.sql.Connection method*/
      //throw new java.lang.UnsupportedOperationException("Method prepareCall() not yet implemented.");
      return aCon.prepareCall(sql, resultSetType, resultSetConcurrency,
                  resultSetHoldability);
     }

     public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws
       SQLException {
      /**@todo Implement this java.sql.Connection method*/
      //throw new java.lang.UnsupportedOperationException("Method prepareStatement() not yet implemented.");
      return aCon.prepareStatement(sql, autoGeneratedKeys);
     }

     public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws
       SQLException {
      /**@todo Implement this java.sql.Connection method*/
      // throw new java.lang.UnsupportedOperationException("Method prepareStatement() not yet implemented.");
      return aCon.prepareStatement(sql, columnIndexes);
     }

     public PreparedStatement prepareStatement(String sql, String[] columnNames) throws
       SQLException {
      /**@todo Implement this java.sql.Connection method*/
      //throw new java.lang.UnsupportedOperationException("Method prepareStatement() not yet implemented.");
      return aCon.prepareStatement(sql, columnNames);
     }

     public void closeConnection() throws SQLException {
      if (onClose != null) {
       onClose.Action(this);
      }
      aCon.close();

     }

     public boolean isUsed() {
      return inUse;

     }

     public void use() {
      inUse = true;
     }

     public void setOnClose(OnConnectionClose Action) {
      onClose = Action;

     }

    }

    以上就是我所写的连接池代码.

    使用方法:
    DBTools.DBConnectionPool.SetJDBC("jdbc:mysql://fireBird/trmg?useUnicode=true&characterEncoding=GB2312",
    "Administrator","");
       DBTools.DBConnectionPool.setDriverName("com.mysql.jdbc.Driver");

    java.sql.Connection con = DBTools.DBConnectionPool.getConnection();

    当使用完毕了别忘记将con关闭:).

    好像现在使用java的人不允许人说java的问题,java的内存回收存在大问题.内存泄漏的厉害,建议如非必要不要使用new来生成新的对象.这样可能可以让我们的系统可以活的更长久一些.还有linux下java性能惨不忍睹,在俺测试的平台中win32反而是最高的.郁闷郁闷不是罪.


    2003-9-16 11:06:00

     
    展开全文
  • JAVA实现短信接口的调用

    万次阅读 2018-11-20 10:15:22
    通过接通短信接口,这一点大家想必都明白,接下来大家来看下具体操作,如有不对,请轻喷 第一步、找个短信批发商注册个账号, 笔者这里选用的是荣联-云通讯平台,只需要注册一个账号,进入管理控制台自己查看信息...

    前言

       基本上在所有的APP或者网站上注册用户时大家都可以通过手机号进行注册,这是一个项目必备的功能之一,但是怎么实现的呢?通过接通短信接口,这一点大家想必都明白,接下来大家来看下具体操作,如有不对,请轻喷

    第一步、找个短信批发商注册个账号,

    笔者这里选用的是荣联-云通讯平台,只需要注册一个账号,进入管理控制台自己查看信息即可,创建APP会产生APPID

    二、配置文件

    我这使用的是SSM框架,进行如下配置(下面所有属性都在荣联里面找得到)

    三、编写service层代码

    package cn.yunfan.itrip.service.sms.impl;
    
    import cn.yunfan.utils.SystemConfig;
    import com.cloopen.rest.sdk.CCPRestSmsSDK;
    import cn.yunfan.itrip.service.sms.SmsService;
    import org.apache.log4j.Logger;
    import org.springframework.stereotype.Service;
    
    import javax.annotation.Resource;
    import java.util.HashMap;
    import java.util.Set;
    @Service
    public class SmsServiceImpl implements SmsService {
        Logger logger= Logger.getLogger(SmsServiceImpl.class);
        @Resource
        private SystemConfig systemConfig;
        @Override
        public void send(String to, String templateId, String[] datas) throws Exception {
            HashMap<String,Object>result =null;
            //初始化官方发送短信的工具类
            CCPRestSmsSDK restAPI = new CCPRestSmsSDK();
             //根据主机和端口,初始化:resultAPI.init("app.cloopen.com","8883");
            restAPI.init(systemConfig.getSmsServerIP(),systemConfig.getSmsServerPort());
            //*初始化主账号和主账号令牌,对应官网开发者主账号下的ACCOUNT SID 和 AUTH TOKEN
            //认证我的开发者账号
            restAPI.setAccount(systemConfig.getSmsAccountSid(),systemConfig.getSmsAuthToken());
            //爱旅行的应用Id
            restAPI.setAppId(systemConfig.getSmsAppID());
    
            result= restAPI.sendTemplateSMS(to,templateId,datas);
    
            logger.debug("SDKTestGetSubAccounts result="+result);
            if("000000".equals(result.get("statusCode"))){//000000表示发送成功
                //正常返回输出data包体信息(map)
                HashMap<String,Object> data = (HashMap<String,Object>)result.get("data");
                Set<String>keySet = data.keySet();
                for(String key:keySet){
                    Object object = data.get(key);
                    logger.debug(key+"="+object);
                }
            }else{
                //异常返回输出错误码和错误信息
                System.out.println("错误码="+result.get("statusCode")+"错误信息="+result.get("statusMsg"));
                logger.error("错误码="+result.get("statusCode")+"错误信息="+result.get("statusMsg"));
                throw new Exception("错误码="+result.get("statusCode")+"错误信息="+result.get("statusMsg"));
    
    
            }
        }
    }
    

    PS:由于笔者使用了redis作为缓存和一些工具类,这里我就在下面一一列出

    1、RedisAPI

    package cn.yunfan.utils;
    
    import redis.clients.jedis.Jedis;
    import redis.clients.jedis.JedisPool;
    
    /**
     * RedisAPI
     * @author bdqn_hl
     * @date 2014-3-15
     */
    public class RedisAPI {
    
       public JedisPool jedisPool;
    
       public JedisPool getJedisPool() {
          return jedisPool;
       }
       public void setJedisPool(JedisPool jedisPool) {
          this.jedisPool = jedisPool;
       }
       /**
        * set key and value to redis
        * @param key
        * @param value
        * @return
        */
       public boolean set(String key,String value){
          try{
             Jedis jedis = jedisPool.getResource();
             jedis.set(key, value);
             return true;
          }catch(Exception e){
             e.printStackTrace();
          }
          return false;
       }
    
       /**
        * set key and value to redis
        * @param key
        * @param seconds 有效期
        * @param value
        * @return
        */
       public boolean set(String key,int seconds,String value){
          try{
             Jedis jedis = jedisPool.getResource();
             jedis.setex(key, seconds, value);
             return true;
          }catch(Exception e){
             e.printStackTrace();
          }
          return false;
       }
    
       /**
        * 判断某个key是否存在
        * @param key
        * @return
        */
       public boolean exist(String key){
          try{
             Jedis jedis = jedisPool.getResource();
             return jedis.exists(key);
          }catch(Exception e){
             e.printStackTrace();
          }
          return false;
       }
    
       /**
        * 返还到连接池
        * @param pool
        * @param redis
        */
       public static void returnResource(JedisPool pool,Jedis redis){
          if(redis != null){
             pool.returnResource(redis);
          }
       }
    
       /**
        * 获取数据
        * @param key
        * @return
        */
       public String get(String key){
          String value = null;
          Jedis jedis = null;
          try{
             jedis = jedisPool.getResource();
             value = jedis.get(key);
          }catch(Exception e){
             e.printStackTrace();
          }finally{
             //返还到连接池
             returnResource(jedisPool, jedis);
          }
    
          return value;
       }
    
       /**
        * 查询key的有效期,当 key 不存在时,返回 -2 。 当 key 存在但没有设置剩余生存时间时,返回 -1 。 否则,以秒为单位,返回 key 的剩余生存时间。
        * 注意:在 Redis 2.8 以前,当 key 不存在,或者 key 没有设置剩余生存时间时,命令都返回 -1 。
        * @param key
        * @return 剩余多少秒
        */
       public Long ttl(String key){
          try{
             Jedis jedis = jedisPool.getResource();
             return jedis.ttl(key);
          }catch(Exception e){
             e.printStackTrace();
          }
          return (long) -2;
       }
    
       /**
        * 删除
        * @param key
        */
       public void delete(String key){
          try{
             Jedis jedis = jedisPool.getResource();
             jedis.del(key);
          }catch(Exception e){
             e.printStackTrace();
          }
       }
    }
    

    2、SystemCofing

    package cn.yunfan.utils;
    /**
     * SystemConfig
     * @author hanlu
     *
     */
    public class SystemConfig {
    
       /**
        * 文件上传路径,通过properties文件进行配置
        */
       private String fileUploadPathString;
       /**
        * 上传文件访问URL,通过properties文件进行配置
        */
       private String visitImgUrlString;
       /**
        * 生成订单的机器码,通过properties文件进行配置
        */
       private String machineCode;
    
       private String orderProcessOK;
    
       private String orderProcessCancel;
    
       /**
        * 云通信短信平台账户Account Sid
        */
       private String smsAccountSid;
       /**
        * 云通信短信平台账户Auth Toke
        */
       private String smsAuthToken;
       /**
        * 云通信短信平台账户App ID
        */
       private String smsAppID;
       /**
        * 云通信短信平台Server IP
        */
       private String smsServerIP;
       /**
        * 云通信短信平台Server Port
        */
       private String smsServerPort;
       
       /**
        * 在线支付交易完成通知后续处理接口的地址
        */
       private String tradeEndsUrl;   
    
       /**
        * 支付模块发送Get请求是否使用代理
        */
       private Boolean tradeUseProxy;
       /**
        * 代理主机
        */
       private String tradeProxyHost;
       /**
        * 代理端口
        */
       private Integer tradeProxyPort;
    
       public String getTradeEndsUrl() {
          return tradeEndsUrl;
       }
    
       public void setTradeEndsUrl(String tradeEndsUrl) {
          this.tradeEndsUrl = tradeEndsUrl;
       }
       public Boolean getTradeUseProxy() {
          return tradeUseProxy;
       }
    
       public void setTradeUseProxy(Boolean tradeUseProxy) {
          this.tradeUseProxy = tradeUseProxy;
       }
    
       public String getTradeProxyHost() {
          return tradeProxyHost;
       }
    
       public void setTradeProxyHost(String tradeProxyHost) {
          this.tradeProxyHost = tradeProxyHost;
       }
    
       public Integer getTradeProxyPort() {
          return tradeProxyPort;
       }
    
       public void setTradeProxyPort(Integer tradeProxyPort) {
          this.tradeProxyPort = tradeProxyPort;
       }
    
       public String getSmsAccountSid() {
          return smsAccountSid;
       }
    
       public void setSmsAccountSid(String smsAccountSid) {
          this.smsAccountSid = smsAccountSid;
       }
    
       public String getSmsAuthToken() {
          return smsAuthToken;
       }
    
       public void setSmsAuthToken(String smsAuthToken) {
          this.smsAuthToken = smsAuthToken;
       }
    
       public String getSmsAppID() {
          return smsAppID;
       }
    
       public void setSmsAppID(String smsAppID) {
          this.smsAppID = smsAppID;
       }
    
       public String getSmsServerIP() {
          return smsServerIP;
       }
    
       public void setSmsServerIP(String smsServerIP) {
          this.smsServerIP = smsServerIP;
       }
    
       public String getSmsServerPort() {
          return smsServerPort;
       }
    
       public void setSmsServerPort(String smsServerPort) {
          this.smsServerPort = smsServerPort;
       }
    
       public String getOrderProcessOK() {
          return orderProcessOK;
       }
    
       public void setOrderProcessOK(String orderProcessOK) {
          this.orderProcessOK = orderProcessOK;
       }
    
       public String getOrderProcessCancel() {
          return orderProcessCancel;
       }
    
       public void setOrderProcessCancel(String orderProcessCancel) {
          this.orderProcessCancel = orderProcessCancel;
       }
    
       public String getMachineCode() {
          return machineCode;
       }
    
       public void setMachineCode(String machineCode) {
          this.machineCode = machineCode;
       }
    
       public String getVisitImgUrlString() {
          return visitImgUrlString;
       }
    
       public void setVisitImgUrlString(String visitImgUrlString) {
          this.visitImgUrlString = visitImgUrlString;
       }
    
       public String getFileUploadPathString() {
          return fileUploadPathString;
       }
    
       public void setFileUploadPathString(String fileUploadPathString) {
          this.fileUploadPathString = fileUploadPathString;
       }
       
       
       
    }
    

    3、验证电话号码格式 ValiPhone

    package cn.yunfan.utils;
    
    import java.util.regex.Pattern;
    
    public class ValidPhone {
        public static boolean validata(String phoneNumber){
            String pattern = "(1[345678]\\d{9})";
            Pattern r = Pattern.compile(pattern);
            return r.matcher(phoneNumber).matches();
        }
    }
    

    4、MD5密码加密

    package cn.yunfan.utils;
    
    import java.security.MessageDigest;
    import java.security.NoSuchAlgorithmException;
    import java.util.Random;
    
    public class MD5 {
    
       public static String getMd5(String plainText,int length) {
          try {
             MessageDigest md = MessageDigest.getInstance("MD5");
             md.update(plainText.getBytes());
             byte b[] = md.digest();
    
             int i;
    
             StringBuffer buf = new StringBuffer("");
             for (int offset = 0; offset < b.length; offset++) {
                i = b[offset];
                if (i < 0)
                   i += 256;
                if (i < 16)
                   buf.append("0");
                buf.append(Integer.toHexString(i));
             }
             // 32位
             // return buf.toString();
             // 16位
             // return buf.toString().substring(0, 16);
             
             return buf.toString().substring(0, length);
          } catch (NoSuchAlgorithmException e) {
             e.printStackTrace();
             return null;
          }
    
       }
    
       public static int getRandomCode(){    
          int max=9999;
            int min=1111;
            Random random = new Random();
            return random.nextInt(max)%(max-min+1) + min;     
       }
       public static void main(String[] args) {
          System.out.println(MD5.getMd5("helloadsfdsffsf",6));
          System.out.println(getRandomCode());
       }
    
    }
    

    5、数据传输对象 Dto工具类

    package cn.yunfan.itrip.pojo.dto;
    
    /**
     * 数据传输对象(后端输出对象)
     * @param <T>
     * Created by hanlu on 2017/5/7.
     */
    public class Dto<T>{
       private String success; //判断系统是否出错做出相应的true或者false的返回,与业务无关,出现的各种异常
       private String errorCode;//该错误码为自定义,一般0表示无错
       private String msg;//对应的提示信息
       private T data;//具体返回数据内容(pojo、自定义VO、其他)
       
       public T getData() {
          return data;
       }
       public void setData(T data) {
          this.data = data;
       }
       public String getSuccess() {
          return success;
       }
       public void setSuccess(String success) {
          this.success = success;
       }
       public String getErrorCode() {
          return errorCode;
       }
       public void setErrorCode(String errorCode) {
          this.errorCode = errorCode;
       }
       public String getMsg() {
          return msg;
       }
       public void setMsg(String msg) {
          this.msg = msg;
       }
       
    }
    package cn.yunfan.itrip.pojo.dto;
    
    import io.swagger.annotations.ApiModelProperty;
    
    /**
     * 数据传输对象(输入对象)
     */
    public class InputDto {
    
       @ApiModelProperty(value="单一参数传入")
       private String paramString;
       @ApiModelProperty(value="多个参数传入")
       private String[] paramStrings;
       public String getParamString() {
          return paramString;
       }
       public void setParamString(String paramString) {
          this.paramString = paramString;
       }
       public String[] getParamStrings() {
          return paramStrings;
       }
       public void setParamStrings(String[] paramStrings) {
          this.paramStrings = paramStrings;
       }
       
       
       
    }
    

    6、EmptyUtils工具

    package cn.yunfan.utils;
    
    import java.util.Collection;
    import java.util.Map;
    
    /**
     * <p>判断是否是空的 工具类</p>
     * @author XX
     * @version v1.0
     * @since 2015/5/5
     */
    public class EmptyUtils {
        //判空
        public static boolean isEmpty(Object obj){
            if (obj == null)
                return true;
            if (obj instanceof CharSequence)
                return ((CharSequence) obj).length() == 0;
            if (obj instanceof Collection)
                return ((Collection) obj).isEmpty();
            if (obj instanceof Map)
                return ((Map) obj).isEmpty();
            if (obj instanceof Object[]) {
                Object[] object = (Object[]) obj;
                if (object.length == 0) {
                    return true;
                }
                boolean empty = true;
                for (int i = 0; i < object.length; i++) {
                    if (!isEmpty(object[i])) {
                        empty = false;
                        break;
                    }
                }
                return empty;
            }
            return false;
        }
        public static boolean isNotEmpty(Object obj){
            return !isEmpty(obj);
        }
    
    
    
        private boolean validPropertyEmpty(Object ...args) {
            for (int i = 0; i < args.length; i++) {
                if(EmptyUtils.isEmpty(args[i])){
                    return true;
                }
            }
            return false;
        }
    }
    

    第四步、编写Controller层

    package cn.yunfan.itrip.controller;
    import cn.yunfan.itrip.pojo.dto.Dto;
    import cn.yunfan.itrip.pojo.ItripUser;
    
    import cn.yunfan.itrip.service.user.UserService;
    import cn.yunfan.itrip.pojo.vo.userinfo.ItripUserVO;
    import cn.yunfan.utils.*;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.*;
    
    
    import javax.annotation.Resource;
    
    @Controller
    @RequestMapping("/api")
    public class UserController {
    
        @Resource
        UserService userService;
       //验证是否该注册名存在
        @RequestMapping(value = "/ckusr", method = RequestMethod.GET, produces = "application/json")
        @ResponseBody
        public Dto checkUser(@RequestParam String name) {
            try {
                //判断注册的用户名是否存在 -- 如果返回真则已存在 --否者可以使用
                if (userService.findUserByUserCode(name) != null) {
                    return DtoUtil.returnFail("用户已经存在", ErrorCode.AUTH_USER_ALREADY_EXISTS);
                }
            } catch (Exception ex) {
                ex.printStackTrace();
                return DtoUtil.returnFail("服务器正忙,请稍后再试", ErrorCode.AUTH_UNKNOWN);
            }
            return DtoUtil.returnSuccess("用户名可用");
        }
      
        //手机注册
        @RequestMapping(value = "registerbyphone",method = RequestMethod.POST)
        public @ResponseBody Dto registerByPhone(@RequestBody ItripUser userVo){
            if(!ValidPhone.validata(userVo.getUserCode())){
                return DtoUtil.returnFail("手机号码格式不正确",ErrorCode.AUTH_ILLEGAL_USERCODE);
            }
            try{
                //  调用发送短信、插入用户数据
                userVo.setActivated(0);
                userVo.setUserType(0); //自己注册的账号
                userVo.setUserPassword(MD5.getMd5(userVo.getUserPassword(),32));
                userService.itripexCreateUserByPhone(userVo);
                return  DtoUtil.returnSuccess("手机注册成功");//返回一个成功的Json对象
            }catch (Exception ex){
                ex.printStackTrace();
            }
            return DtoUtil.returnFail("手机注册失败!",ErrorCode.AUTH_UNKNOWN);
        }
       //激活手机账号
        @RequestMapping("/validatephone")
        public @ResponseBody Dto activeByPhone(@RequestParam String user ,@RequestParam String code){
            if(!ValidPhone.validata(user)){ //验证手机号是否正确
                return DtoUtil.returnFail("手机号码格式不正确",ErrorCode.AUTH_ILLEGAL_USERCODE);
            }
            try {//调用激活
                boolean isActived = userService.activateByPhone(user,code);
                if(isActived){
                    return DtoUtil.returnSuccess("激活成功!");
                }
            }catch (Exception ex){
                ex.printStackTrace();
            }
            return DtoUtil.returnFail("手机激活失败!",ErrorCode.AUTH_ACTIVATE_FAILED);
        }
    }
    

    第五步、运行代码,测试成功

    展开全文
  • JPDA(Java Platform Debugger Architecture) 是 Java 平台调试体系结构的缩写,通过 JPDA 提供的 API,开发人员可以方便灵活的搭建 Java 调试应用程序。JPDA 主要由三个部分组成:Java 虚拟机工具接口(JVMTI),...

    JPDA(Java Platform Debugger Architecture) 是 Java 平台调试体系结构的缩写,通过 JPDA 提供的 API,开发人员可以方便灵活的搭建 Java 调试应用程序。JPDA 主要由三个部分组成:Java 虚拟机工具接口(JVMTI),Java 调试线协议(JDWP),以及 Java 调试接口(JDI),本系列将会详细介绍这三个模块的内部细节、通过实例为读者揭开 JPDA 的面纱。本文是该系列的最后一篇,将会着重介绍 Java 调试接口 - JDI,以及如何使用 JDI 编写用户自定义的 Java 调试程序。

    JDI 简介

    JDI(Java Debug Interface)是 JPDA 三层模块中最高层的接口,定义了调试器(Debugger)所需要的一些调试接口。基于这些接口,调试器可以及时地了解目标虚拟机的状态,例如查看目标虚拟机上有哪些类和实例等。另外,调试者还可以控制目标虚拟机的执行,例如挂起和恢复目标虚拟机上的线程,设置断点等。

    目前,大多数的 JDI 实现都是通过 Java 语言编写的。比如,Java 开发者再熟悉不过的 Eclipse IDE,它的调试工具相信大家都使用过。它的两个插件 org.eclipse.jdt.debug.ui 和 org.eclipse.jdt.debug 与其强大的调试功能密切相关,其中 org.eclipse.jdt.debug.ui 是 Eclipse 调试工具界面的实现,而 org.eclipse.jdt.debug 则是 JDI 的一个完整实现。

    JDI 工作方式

    首先,调试器(Debuuger)通过 Bootstrap 获取唯一的虚拟机管理器,见 清单 1。

    清单 1. 获取虚拟机管理器(VirtualMachineManager)

    VirtualMachineManager virtualMachineManager 
        = Bootstrap.virtualMachineManager();

    虚拟机管理器将在第一次被调用时初始化可用的链接器。一般地,调试器会默认地采用启动型链接器进行链接,见 清单 2。

    清单 2. 获取默认的链接器(Connector)

    LaunchingConnector defaultConnector = virtualMachineManager.defaultConnector();

    然后,调试器调用链接器的 launch () 来启动目标程序,并完成调试器与目标虚拟机的链接,见 清单 3。

    清单 3. 启动目标程序,连接调试器(Debuuger)与目标虚拟机(VirtualMachine)

    VirtualMachine targetVM = defaultConnector.launch(arguments);

    当链接完成后,调试器与目标虚拟机便可以进行双向通信了。调试器将用户的操作转化为调试命令,命令通过链接被发送到前端运行目标程序的虚拟机上;然后,目标虚拟机根据接受的命令做出相应的操作,将调试的结果发回给后端的调试器;最后,调试器可视化数据信息反馈给用户。

    从功能上,可以将 JDI 分成三个部分:数据模块,链接模块,以及事件请求与处理模块。数据模块负责调试器和目标虚拟机上的数据建模,链接模块建立调试器与目标虚拟机的沟通渠道,事件请求与处理模块提供调试器与目标虚拟机交互方式,下面将逐一地介绍它们。

    JDI 数据模块

    Mirror

    Mirror 接口是 JDI 最底层的接口,JDI 中几乎所有其他接口都继承于它。镜像机制是将目标虚拟机上的所有数据、类型、域、方法、事件、状态和资源,以及调试器发向目标虚拟机的事件请求等都映射成 Mirror 对象。例如,在目标虚拟机上,已装载的类被映射成 ReferenceType 镜像,对象实例被映射成 ObjectReference 镜像,基本类型的值(如 float 等)被映射成 PrimitiveValue(如 FloatValue 等)。被调试的目标程序的运行状态信息被映射到 StackFrame 镜像中,在调试过程中所触发的事件被映射成 Event 镜像(如 StepEvent 等),调试器发出的事件请求被映射成 EventRequest 镜像(如 StepRequest 等),被调试的目标虚拟机则被映射成 VirtualMachine 镜像。但是,JDI 并不保证目标虚拟机上的每份信息和资源都只有唯一的镜像与之对应,这是由 JDI 的具体实现所决定的。例如,目标虚拟机上的某个事件有可能存在多个 Event 镜像与之对应,例如 BreakpointEvent 等。

    Mirror 实例或是由调试器创建,或是由目标虚拟机创建,调用 Mirror 实例 virtualMachine() 可以获取其虚拟机信息,如下所示。

    清单 4. 获取 Mirror 对象实例的虚拟机

    VirtualMachine virtualMachine = mirror.virtualMachine();

    返回的目标虚拟机对象实现了 VirtualMachine 接口,该接口提供了一套方法,可以用来直接或间接地获取目标虚拟机上所有的数据和状态信息,也可以挂起、恢复、终止目标虚拟机,详情见 图 1。

    这里写图片描述

    这样,调试器便可以获取目标虚拟机上的信息,维持与目标虚拟机间的通信,并且检查,修改和控制目标虚拟机上资源等。

    Value 和 Type

    Value 和 Type 接口分别代表着目标虚拟机中对象、实例变量和方法变量的值和类型。通过 Value 接口的 type(),可以获取该值对应的类型。JDI 中定义了两种基本的数据类型:原始类型(PrimitiveType)和引用类型(ReferenceType)。与其对应的数值类型分别是原始值(PrimtiveValue)和对象引用(ObjectReference)。Value 和 Type 的具体对应关系,请参见 表 1。

    表 1. JDI 中 Value-Type 的对照表

    (Value, Type) 说明
    (PrimtiveValue, PrimtiveType) (ByteValue, ByteType) 表示一个字节
    (CharValue, CharType) 表示一个字符
    (ShortValue, ShortType) 表示一个短整型数据
    (IntegerValue, IntegerType) 表示一个整型数据
    (LongValue, LongType) 表示一个长整型数据
    (FloatValue, FloatType) 表示一个浮点型数据
    (DoubleValue, DoubleType) 表示一个双精度浮点型数据
    (BooleanValue, BooleanType) 表示一个布尔型数据
    (ObjectReference, ReferenceType) (ObjectReference, ReferenceType) 表示目标虚拟机上的一个对象
    (ArrayReference, ArrayType) 表示目标虚拟机上的一个数组
    (StringReference, ClassType) 表示目标虚拟机上的一个字符串对象
    (ThreadReference, ClassType) 表示目标虚拟机上的一个线程对象,有一套方法可以获得当前设置的断点,堆栈,也能挂起和恢复该线程等
    (ThreadGroupReference, ClassType) 表示目标虚拟机上的一个线程组对象
    (ClassObjectReference, ClassType) 表示目标虚拟机上的一个类的 java.lang.Class 实例
    (ClassLoaderReference, ClassType) 表示目标虚拟机上的一个 ClassLoader 对象
    (VoidValue, VoidType) 表示 void 类型

    PrimitiveType 包括 Java 的 8 种基本类型,ReferenceType 包括目标虚拟机中装载的类,接口和数组的类型(数组也是一种对象,有自己的对象类型)。ReferenceType 有三种子接口:ClassType 对应于加载的类,InterfaceType 对应于接口,ArrayType 对应于数组。另外,ReferenceType 还提供了一组方法,可以用来获取该类型中声明的所有变量、方法、静态变量的取值、内嵌类、运行实例、行号等信息。

    PrimtiveValue 封装了 PrimitiveType 的值,它提供一组方法可将 PrimtiveValue 转化为 Java 原始数据。例如,IntegerValue 的 value () 将返回一个 int 型数据。对应地,VirtualMachine 也提供了一组方法,用以将 Java 原始数据转化为 PrimtiveValue 型数据。例如 mirrorOf(float value) 将给定的 float 数据转化为 FloatValue 型数据。

    ObjectReference 封装了目标虚拟机中的对象,通过 getValue() 和 setValue() 方法可以访问和修改对象中变量的值,通过 invokeMethod() 可以调用该对象中的指定方法,通过 referringObjects() 可以获得直接引用该对象的其他对象,通过 enableCollection() 和 disableCollection() 可以允许和禁止 GC 回收该对象。

    TypeComponent

    TypeComponent 接口表示 Class 或者 Interface 所声明的实体(Entity),它是 Field 和 Method 接口的基类。Field 表示一个类或者实例的变量,调用其 type() 可返回域的类型。Method 表示一个方法。TypeComponent 通过方法 declaredType() 获得声明该变量或方法的类或接口,通过 name() 获得该变量或者方法的名字(对于 Field 返回域名,对于一般方法返回方法名,对于类构造函数返回 ,对于静态初始化构造函数返回 )。

    JDI 的链接模块

    链接是调试器与目标虚拟机之间交互的渠道,一次链接可以由调试器发起,也可以由被调试的目标虚拟机发起。一个调试器可以链接多个目标虚拟机,但一个目标虚拟机最多只能链接一个调试器。链接是由链接器(Connector)生成的,不同的链接器封装着不同的链接方式。JDI 中定义三种链接器接口,分别是依附型链接器(AttachingConnector)、监听型链接器(ListeningConnector)和启动型链接器(LaunchingConnector)。在调试过程中,实际使用的链接器必须实现其中一种接口。

    根据调试器在链接过程中扮演的角色,可以将链接方式划分为主动链接和被动链接。主动链接是较常见一种链接方式,表示调试器主动地向目标虚拟机发起链接。下面将举两个主动链接的例子:

    由调试器启动目标虚拟机的链接方式:这是最常见、最简单的一种链接方式。

    • 调试器调用 VirtualMachineManager 的 launchingConnectors() 方法获取所有的启动型链接器实例;
    • 根据传输方式或其他特征选择一个启动型链接器,调用其 launch() 方法启动和链接目标虚拟机;
    • 启动后,返回目标虚拟机的实例。

    更高级的,当目标虚拟机已处于运行状态时,可以采用调试器 attach 到目标虚拟机的链接方式:

    • 目标虚拟机必须以 -agentlib:jdwp=transport=xxx,server=y 参数启动,并根据传输方式生成监听地址;(其中,xxx 是传输方式,可以是 dt_socket 和 share_memory)
    • 调试器启动,调用 VirtualMachineManager 的 attachingConnectors() 方法获取所有的依附型链接器实例;
    • 根据目标虚拟机采用的传输方式选择一个依附型链接器,调用其 attach() 方法依附到目标虚拟机上;
    • 完成链接后,返回目标虚拟机的实例。

    被动链接表示调试器将被动地等待或者监听由目标虚拟机发起的链接,同样也举两个被动链接的例子:

    目标虚拟机 attach 到已运行的调试器上的链接方式:

    • 调试器通过 VirtualMachineManager 的 listeningConnectors() 方法获取所有的监听型链接器实例;
    • 为每种传输类型分别选定一个链接器,然后调用链接器的 startListening() 方法让链接器进入监听状态;
    • 通过 accept() 方法通知链接器开始等待正确的入站链接,该方法将返回调试器正在监听的地址描述符;
    • 终端用户以 -agentlib:jdwp=transport=xxx,address=yyy 参数启动目标虚拟机(其中,yyy 是调试器的监听地址);
    • 目标虚拟机会自动地 attach 到调试器上建立链接,然后返回目标虚拟机的实例。

    即时(Just-In-Time)链接方式:

    • 以 -agentlib:jdwp=launch=cmdline,onuncaught=y,transport=xxx,server=y 参数启动目标虚拟机;
    • 虚拟机将抛出一个未捕获的异常,同时生成特定于 xxx 传输方式的监听地址,用于确立一次链接;
    • 目标虚拟机启动调试器,并告知调试器传输方式和监听地址;
    • 启动后,调试器调用 VirtualMachineManager 的 attachingConnectors() 方法获取所有依附型链接器实例;
    • 根据指定的 xxx 传输方式,选择一个链接器;
    • 调用链接器的 attach 方法依附到对应地址的目标虚拟机上;
    • 完成链接后,返回目标虚拟机的实例。

    Connector.Argument 是 Connector 的内嵌接口,表示链接器的一个参数,不同类型的链接器支持不同的链接器参数,LaunchingConnector 支持 home,main,suspend 等,AttachingConnector 和 ListeningConnector 支持 timeout,hostname,port 等参数,见 表 2。

    表 2. 常见的链接器参数

    Connector 类型 参数名称 说明
    LaunchingConnector home 表示 java.home 的值,指向 JRE
    main 表示所要执行的 Java 类的类名
    options 表示使用的 Java 命令行参数
    suspend 表示是否在启动目标虚拟机后挂起虚拟机
    AttachingConnector ListeningConnector hostname 表示被链接一端的地址
    port 表示被链接一端的端口
    timeout 表示等待链接的时间

    下面将举一个简单例子,描述如何设置 main 链接参数,并启动目标虚拟机。首先,调用链接器的 defaultArguments() 获取该链接器所支持的一组默认参数,见 清单 5。

    清单 5. 获取链接器的默认参数

    Map<String,Connector.Argument> defaultArguments 
        = connector.defaultArguments();

    默认参数存储在一个 Key-Value 对的 Map 中,Key 是该链接器参数的唯一标识符(对终端用户不可见),Value 是对应的 Connector.Argument 实例(包括具体参数的信息和默认值)。返回的 Map 不能再新增或者删除元素,只能修改已有元素的值。

    然后,从返回的 Map 中获取标识符为 main 的链接器参数,如 清单 6。

    清单 6. 返回链接器的 main 参数

    Connector.Argument mainArgument = defaultArguments.get(“main”);

    最后,将 main 参数值设置为 com.ibm.jdi.test.HelloWorld,以修改后的参数启动目标虚拟机,见 清单 7。

    清单 7. 设置 main 参数的值并启动虚拟机

    mainArgument.setValue(“com.ibm.jdi.test.HelloWorld”);
    VirtualMachine targetVM = connector.launch(defaultArguments);

    JDI 事件请求和处理模块

    JDI 事件分类

    JDI 的 com.sun.jdi.event 包定义了 18 种事件类型,如 表 3 所示。其中,与 Class 相关的有 ClassPrepareEvent 和 ClassUnloadEvent;与 Method 相关的有 MethodEntryEvent 和 MethodExitEvent;与 Field 相关的有 AccessWatchpointEvent 和 ModificationWatchpointEvent;与虚拟机相关的有 VMDeathEvent,VMDisconnectEvent 和 VMStartEvent 等。

    表 3. JDI 中的事件类型

    事件类型 描述
    ClassPrepareEvent 装载某个指定的类所引发的事件
    ClassUnloadEvent 卸载某个指定的类所引发的事件
    BreakingpointEvent 设置断点所引发的事件
    ExceptionEvent 目标虚拟机运行中抛出指定异常所引发的事件
    MethodEntryEvent 进入某个指定方法体时引发的事件
    MethodExitEvent 某个指定方法执行完成后引发的事件
    MonitorContendedEnteredEvent 线程已经进入某个指定 Monitor 资源所引发的事件
    MonitorContendedEnterEvent 线程将要进入某个指定 Monitor 资源所引发的事件
    MonitorWaitedEvent 线程完成对某个指定 Monitor 资源等待所引发的事件
    MonitorWaitEvent 线程开始等待对某个指定 Monitor 资源所引发的事件
    StepEvent 目标应用程序执行下一条指令或者代码行所引发的事件
    AccessWatchpointEvent 查看类的某个指定 Field 所引发的事件
    ModificationWatchpointEvent 修改类的某个指定 Field 值所引发的事件
    ThreadDeathEvent 某个指定线程运行完成所引发的事件
    ThreadStartEvent 某个指定线程开始运行所引发的事件
    VMDeathEvent 目标虚拟机停止运行所以的事件
    VMDisconnectEvent 目标虚拟机与调试器断开链接所引发的事件
    VMStartEvent 目标虚拟机初始化时所引发的事件

    不同的事件需要被分类地添加到不同的事件集合(EventSet)中,事件集是事件发送的最小单位。事件集一旦创建出来,便不可再被修改。JDI 定义了一些规则,用以规定应该如何将事件分别加入到不同的事件集中:

    • 每个 VMStartEvent 事件应该分别加入到单独的一个事件集中;
    • 每个 VMDisconnectEvent 事件应该分别加入到单独的一个事件集中;
    • 所有的 VMDeathEvent 事件应该加入到同一个事件集中;
    • 同一线程的 ThreadStartEvent 事件应该加入到同一事件集中;
    • 同一线程的 ThreadDeathEvent 事件应该加入到同一事件集中;
    • 同一类型的 ClassPrepareEvent 事件应该加入到同一个事件集中;
    • 同一类型的 ClassUnloadEvent 事件应该加入到同一个事件集中;
    • 同一 Field 的 AccessWatchpointEvent 事件应该加入到同一个事件集中;
    • 同一 Field 的 ModificationWatchpointEvent 事件应该加入到同一个事件集中;
    • 同一异常的 ExceptionEvent 事件应该加入到同一个事件集中;
    • 同一方法的 MethodExitEvents 事件应该加入到同一个事件集中;
    • 同一 Monitor 的 MonitorContendedEnterEvent 事件应该加入到用一个事件集中;
    • 同一 Monitor 的 MonitorContendedEnteredEvent 事件应该加入到用一个事件集中;
    • 同一 Monitor 的 MonitorWaitEvent 事件应该加入到同一个事件集中
    • 同一 Monitor 上的 MonitorWaitedEvent 事件应该加入到同一个事件集中
    • 在同一线程执行过程中,具有相同行号信息的 BreakpointEvent、StepEvent 和 MethodEntryEvent 事件应该加入到同一个事件集合中。

    生成的事件集将被依次地加入到目标虚拟机的事件队列(EventQueue)中。然后,EventQueue 将这些事件集以“先进先出”策略依次地发送到调试器端。EventQueue 负责管理来自目标虚拟机的事件,一个被调试的目标虚拟机上有且仅有一个 EventQueue 实例。特别地,随着一次事件集的发送,目标虚拟机上可能会有一部分的线程因此而被挂起。如果一直不恢复这些线程,有可能会导致目标虚拟机挂机。因此,在处理好一个事件集中的事件后,建议调用事件集的 resume() 方法,恢复所有可能被挂起的线程。

    JDI 事件请求

    Event 是 JDI 中所有事件接口的父接口,它只定义了一个 request() 方法,用以返回由调试器发出的针对该事件的事件请求(EventRequest)。事件请求是由调试器向目标虚拟机发出的,目的是请求目标虚拟机在发生指定的事件后通知调试器。只有当调试器发出的请求与目标虚拟机上发生的事件契合时,这些事件才会被分发到各个事件集,进而等待发送至调试器端。在 JDI 中,每一种事件类型都对应着一种事件请求类型。一次事件请求可能对应有多个事件实例,但不是每个事件实例都存在与之对应的事件请求。例如,对于某些事件(如 VMDeathEvent,VMDisconnectEvent 等),即使没有对应的事件请求,这些事件也必定会被发送给调试器端。

    另外,事件请求还支持过滤功能。通过给 EventRequest 实例添加过滤器(Filter),可以进一步筛选出调试器真正感兴趣的事件实例。事件请求支持多重过滤,通过 EventRequest 的 add*Filter() 方法可以添加多个过滤器。多个过滤器将共同作用,最终只有满足所有过滤条件的事件实例才会被发给调试器。常用的过滤器有:

    • 线程过滤器:用以过滤出指定线程中发生的事件;
    • 类型过滤器:用以过滤出指定类型中发生的事件;
    • 实例过滤器:用以过滤出指定实例中发生的事件;
    • 计数过滤器:用以过滤出发生一定次数的事件;

    过滤器提供了一些附加的限制条件,减少了最终加入到事件队列的事件数量,从而提高了调试性能。除了过滤功能,还可以通过它的 setSuspendPolicy(int) 设置是否需要在事件发生后挂起目标虚拟机。

    事件请求是由事件请求管理器(EventRequestManager)进行统一管理的,包括对请求的创建和删除。一个目标虚拟机中有且仅有一个 EventRequestManager 实例。通常,一个事件请求实例有两种状态:激活态和非激活态。非激活态的事件请求将不起任何作用,即使目标虚拟机上有满足此请求的事件发生,目标虚拟机将不做停留,继续执行下一条指令。由 EventRequestManager 新建的事件请求都是非激活的,需要调用 setEnable(true) 方法激活该请求,而通过 setEnable(false) 则可废除该请求,使其转化为非激活态。

    JDI 事件处理

    下面将介绍 JDI 中调试器与目标虚拟机事件交互的方式。首先,调试器调用目标虚拟机的 eventQueue() 和 eventRequestManager() 分别获取唯一的 EventQueue 实例和 EventRequestManager 实例。然后,通过 EventRequestManager 的 createXxxRequest() 创建需要的事件请求,并添加过滤器和设置挂起策略。接着,调试器将从 EventQueue 获取来自目标虚拟机的事件实例。

    一个事件实例中包含着事件发生时目标虚拟机的一些状态信息。以 BreakpointEvent 为例:

    调用 BreakpointEvent 的 thread() 可以获取产生事件的线程镜像(ThreadReference),调用 ThreadReference 的 frame(int) 可获得当前代码行所在的堆栈(StackFrame),调用 StackFrame 的 visibleVariables() 可获取当前堆栈中的所有本地变量(LocaleVariable)。通过调用 BreakpointEvent 的 location() 可获得断点所在的代码行号(Location),调用 Location 的 method() 可获得当前代码行所归属的方法。通过以上调用,调试器便可获得了目标虚拟机上线程、对象、变量等镜像信息。

    另外,根据从事件实例中获取的以上信息,调试器还可以进一步控制目标虚拟机。例如,可以调用 ObjectReference 的 getValue() 和 setValue() 访问和修改对象中封装的 Field 或者 LocalVariable 等,进而影响虚拟机的行为。更多的 JDI 的事件处理的详情,请参见图 2。
    这里写图片描述

    一个 JDI 的简单实例

    下面给出一个简单例子,说明如何实现 JDI 的部分接口来提供一个简易的调试客户端。首先是被调试的 Java 类,这里给出一个简单的 Hello World 程序,main 方法第一行声明一个“Hello World!”的字符串变量,第二行打印出这个字符串的内容,见 清单 8。

    清单 8. HelloWorld 类文件

    package com.ibm.jdi.test;
    
    public class HelloWorld {
        public static void main(String[] args) {
            String str = "Hello world!";
            System.out.println(str);
        }
    }

    接着是一个简单的调试器实现 SimpleDebugger,清单 9 列出了实现该调试器所需要导入的类库和变量。简单起见,所有的变量都声明为静态全局变量。这些变量分别代表了目标虚拟机镜像,目标虚拟机所在的进程,目标虚拟机的事件请求管理器和事件对列。变量 vmExit 标志目标虚拟机是否中止。

    清单 9. SimpleDebugger 导入的类和声明的全局变量

    package com.ibm.jdi.test;
    
    import java.util.List;
    import java.util.Map;
    import com.sun.jdi.Bootstrap;
    import com.sun.jdi.LocalVariable;
    import com.sun.jdi.Location;
    import com.sun.jdi.ReferenceType;
    import com.sun.jdi.StackFrame;
    import com.sun.jdi.StringReference;
    import com.sun.jdi.ThreadReference;
    import com.sun.jdi.Value;
    import com.sun.jdi.VirtualMachine;
    import com.sun.jdi.connect.Connector;
    import com.sun.jdi.connect.LaunchingConnector;
    import com.sun.jdi.connect.Connector.Argument;
    import com.sun.jdi.event.BreakpointEvent;
    import com.sun.jdi.event.ClassPrepareEvent;
    import com.sun.jdi.event.Event;
    import com.sun.jdi.event.EventIterator;
    import com.sun.jdi.event.EventQueue;
    import com.sun.jdi.event.EventSet;
    import com.sun.jdi.event.VMDisconnectEvent;
    import com.sun.jdi.event.VMStartEvent;
    import com.sun.jdi.request.BreakpointRequest;
    import com.sun.jdi.request.ClassPrepareRequest;
    import com.sun.jdi.request.EventRequest;
    import com.sun.jdi.request.EventRequestManager;
    
    public class SimpleDebugger {
        static VirtualMachine vm;
        static Process process;
        static EventRequestManager eventRequestManager;
        static EventQueue eventQueue;
        static EventSet eventSet;
        static boolean vmExit = false;

    随后是 SimpleDebugger 的 main() 方法,见 清单 10。首先从 VirtualMachineManager 获取默认的 LaunchingConnector,然后从该 Connector 取得默认的参数。接着,设置 main 和 suspend 参数,使得目标虚拟机运行 com.ibm.jdi.test.HelloWorld 类,并随后进入挂起状态。下一步,调用 LaunchingConnector.launch() 启动目标虚拟机,返回目标虚拟机的镜像实例,并且获取运行目标虚拟机的进程( Process)。

    然后,创建一个 ClassPrepareRequest 事件请求。当 com.ibm.jdi.test.HelloWorld 被装载时,目标虚拟机将发送对应的 ClassPrepareEvent 事件。事件处理完成后,通过 process 的 destroy() 方法销毁目标虚拟机进程,结束调试工作。

    清单 10. SimpleDebugger 的 main() 方法

    public static void main(String[] args) throws Exception{
        LaunchingConnector launchingConnector 
            = Bootstrap.virtualMachineManager().defaultConnector();
    
        // Get arguments of the launching connector
        Map<String, Connector.Argument> defaultArguments 
            = launchingConnector.defaultArguments();
        Connector.Argument mainArg = defaultArguments.get("main");
        Connector.Argument suspendArg = defaultArguments.get("suspend");
        // Set class of main method
        mainArg.setValue("com.ibm.jdi.test.HelloWorld");
        suspendArg.setValue("true");
        vm = launchingConnector.launch(defaultArguments);
    
        process = vm.process()
    
        // Register ClassPrepareRequest
        eventRequestManager = vm.eventRequestManager();
        ClassPrepareRequest classPrepareRequest 
            = eventRequestManager.createClassPrepareRequest();
        classPrepareRequest.addClassFilter("com.ibm.jdi.test.HelloWorld");
        classPrepareRequest.addCountFilter(1);
        classPrepareRequest.setSuspendPolicy(EventRequest.SUSPEND_ALL);
        classPrepareRequest.enable();
    
        // Enter event loop 
        eventLoop();
    
        process.destroy();
    }

    下面是 eventLoop() 函数的实现:首先获取目标虚拟机的事件队列,然后依次处理队列中的每个事件。当 vmExit(初始值为 false)标志为 true 时,结束循环。

    清单 11. SimpleDebugger 的 eventLoop() 的实现

    private static void eventLoop() throws Exception {
        eventQueue = vm.eventQueue();
        while (true) {
            if (vmExit == true) {
                break;
            }
            eventSet = eventQueue.remove();
            EventIterator eventIterator = eventSet.eventIterator();
            while (eventIterator.hasNext()) {
                Event event = (Event) eventIterator.next();
                execute(event);
            }
        }
    }

    具体事件的处理是由 execute(Event) 实现的,这里主要列举出 ClassPreparEvent 和 BreakpointEvent 事件的处理用法,请参见 清单 12。

    清单 12. SimpleDebugger 的 execute () 方法

    private static void execute(Event event) throws Exception {
        if (event instanceof VMStartEvent) {
            System.out.println("VM started");
            eventSet.resume();
        } else if (event instanceof ClassPrepareEvent) {
            ClassPrepareEvent classPrepareEvent = (ClassPrepareEvent) event;
            String mainClassName = classPrepareEvent.referenceType().name();
            if (mainClassName.equals("com.ibm.jdi.test.HelloWorld")) {
                System.out.println("Class " + mainClassName
                        + " is already prepared");
            }
            if (true) {
                // Get location
                ReferenceType referenceType = prepareEvent.referenceType();
                List locations = referenceType.locationsOfLine(10);
                Location location = (Location) locations.get(0);
    
                // Create BreakpointEvent
                BreakpointRequest breakpointRequest = eventRequestManager
                        .createBreakpointRequest(location);
                breakpointRequest.setSuspendPolicy(EventRequest.SUSPEND_ALL);
                breakpointRequest.enable();
            }
            eventSet.resume();
        } else if (event instanceof BreakpointEvent) {
            System.out.println("Reach line 10 of com.ibm.jdi.test.HelloWorld");
            BreakpointEvent breakpointEvent = (BreakpointEvent) event;
            ThreadReference threadReference = breakpointEvent.thread();
            StackFrame stackFrame = threadReference.frame(0);
            LocalVariable localVariable = stackFrame
                    .visibleVariableByName("str");
            Value value = stackFrame.getValue(localVariable);
            String str = ((StringReference) value).value();
            System.out.println("The local variable str at line 10 is " + str
                    + " of " + value.type().name());
            eventSet.resume();
        } else if (event instanceof VMDisconnectEvent) {
            vmExit = true;
        } else {
            eventSet.resume();
        }
    }

    最后列出了以上程序的运行结果,见 清单 13。

    清单 13. 运行结果

    VM started
    Class com.ibm.jdi.test.HelloWorld is already prepared
    Reach line 10 of com.ibm.jdi.test.HelloWorld
    The local variable str at line 10 is Hello world! of java.lang.String

    结束语

    本文介绍了 Java 调试接口(JDI)的体系结构和工作方式,JDI 是 JPDA 体系结构的调试器后端接口,开发人员通过使用它所提供的接口与 JDWP(Java 调试线协议)前端 Agent 通信,以这种方式访问和控制被调试的目标虚拟机。最后,本文希望能够帮助开发人员在无须掌握 JPDA 的技术细节的情况下,能够编写出实用、高效的 Java 调试器程序。

    展开全文
  • Java连接MySQL数据库

    千次阅读 2011-09-13 18:36:40
    在PHP中连接MySQL是最简单的,PHP的发行包里通常带有MySQL驱动模块,只要简单修改一下PHP配置文件就可以加载MySQL驱动,而且PHP提供了很多专用于操作...在Java、Ruby和Perl中连接MySQL也是比较简单的,这些语言都提
  • java对接钉钉发送消息通知

    千次阅读 热门讨论 2020-11-24 10:14:45
    现在,许多的消息会议,工作任务...博主也在工作中给老师安排了一道,结果呢,百度上面呢,只有机器人,没有工作通知(老师就要通知),博主大大就拿着钉钉的开发平台文档,捣鼓了两天,终于是发出去一个比较OK的通知
  • JPDA:Java平台调试架构

    千次阅读 2011-12-20 16:02:52
    Java Platform Debugger Architecture(JPDA:Java平台调试架构) 由Java虚拟机后端和调试平台前端组成   1.Java虚拟机提供了Java调试的功能   2.调试平台通过调试交互协议向Java虚拟机请求服务以对在虚拟机中...
  • Java基础知识面试题(2020最新版)

    万次阅读 多人点赞 2020-02-19 12:11:27
    文章目录Java概述何为编程什么是Javajdk1.5之后的三大版本JVM、JRE和JDK的关系什么是跨平台性?原理是什么Java语言有哪些特点什么是字节码?采用字节码的最大好处是什么什么是Java程序的主类?应用程序和小程序的...
  • 工商银行接口开发-java

    千次阅读 2017-12-12 15:28:16
    2)根据demo的字段看看银行发的的开发接口文档; 3)将需要的字段可以创建到Modle中 package ytd.zhlv.util.pay; public class ICBCModel { //必输:1,选输:2    //  //private String orderPostUrl...
  • JAVA_API1.6文档(中文)

    万次下载 热门讨论 2010-04-12 13:31:34
    java.util.logging 提供 JavaTM 2 平台核心日志工具的类和接口java.util.prefs 此包允许应用程序存储并获取用户和系统首选项和配置数据。 java.util.regex 用于匹配字符序列与正则表达式指定模式的类。 java....
  • Java微信APP支付-支付结果通知

    千次阅读 2018-08-28 10:36:56
    上一章讲了微信APP支付统一下单接口的开发,这一章我们讲支付结果通知接口的开发,这一接口是微信异步调用我们的接口,告之我们支付已经成功了,然后我们补录门店、电商订单,更新APP订单支付信息等业务逻辑。...
  • Java微信APP支付-退款结果通知

    千次阅读 2018-08-31 17:41:51
    前面已经讲过微信APP支付的统一下单、支付结果通知、申请退款的接口开发,现在我们讲述一下退款结果通知的流程开发。 官方的API地址:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_16&amp;...
  • Java平台的企业版

    千次阅读 2011-12-12 19:33:52
    J2EE: Java平台的企业版 J2SE: 标准版 J2ME:微型版(Micro) J2EE课程内容: Servlet JSP(Java Server Page) JDBC JavaBean 设计模型,有两种 Struts1 Struts2 Hibernate Spring SSH(Struts + ...
  • APP绑定微信商户平台获取商户id(mchID)、证书(商户后台下载)、支付签名密钥(商户后台设置api密钥)、退款签名密钥(商户后台设置api密钥ipv3)等 1.导入微信支付SDK <!--微信支付SDK--> <...
  • Java调用微信客服消息接口

    千次阅读 2018-08-29 16:05:18
    package com.yhxc.utils.wechat; import ... import java.io.*; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLConnection; /** * @Author: 赵贺飞 * @Date:...
  • 牛逼!Java 从入门到精通,超全汇总版

    万次阅读 多人点赞 2021-05-06 19:40:33
    文章目录Java 基础Head First JavaJava 核心技术卷一Java 编程思想设计模式Head First 设计模式图解设计模式设计模式重学 Java 设计模式Java 进阶Java 并发编程实战Java 并发编程艺术Java 并发编程之美图解Java多...
  • java技术--电话语音通知

    千次阅读 2019-10-19 15:37:12
    1.由于短信,邮箱都没人看,导致出现服务器出现异常很长时间才看到,因此电话语音服务因运而生 2.目前支持语音识别的第三方API如下: ...支持Android,iOS,Windows,Java,Linux 3.把语音(≤60秒)转换成对应的文字...
  • java

    千次阅读 2020-07-17 16:35:33
    jvm:jre的一部分,他是整个java实现跨平台的最核心部分,负责解释执行Java字节码文件,是运行java字节码文件的虚拟计算机,java平台的原因:Java源文件被虚拟机编译成字节码文件后,生成的是与平台无关的字节码,...
  • 最新Kafka教程(包含kafka部署与基本操作、java连接kafka、spring连接kafka以及使用springboot) 欢迎转载,转载请注明网址:https://blog.csdn.net/qq_41910280 简介:一篇全面Kafka教程。 文章目录最新Kafka教程...
  • java ssl连接(no cipher suites in common)

    万次阅读 2015-05-07 22:19:57
    并通过一个简单的样例程序实现,来展示如何在 Java 平台上正确建立安全通讯。  人类建立了通信系统之后,如何保证通信的安全始终是一个重要的问题。伴随着现代化通信系统的建立,人们利用数学 理论找到了一些
  • Java 本地接口规范》- 调用 API

    千次阅读 2011-10-19 09:43:50
    调用 API 调用 API 允许软件厂商将 Java ...厂商可以交付支持 Java 的应用程序,而不必链接 Java 虚拟机源代码。 本章首先概述了调用 API。然后是所有调用 API 函数的引用页。 若要增强 Java 虚拟机的嵌
  • Java命名和目录接口(JNDI)

    千次阅读 2008-03-26 14:07:00
    JNDI(Java 命名和目录接口) 分布式计算环境通常使用命名和目录服务来获取共享的组件和资源.命名和目录服务将名称与位置,服务,信息和资源关联起来. 命名服务提供名称—对象的映射.目录服务提供有关对象的信息,并提供...
  • 因图片较多,需要图片请到资源中下载,不需要资源分。 OpenJWeb(1.8) Java Web应用快速开发平台 产品白皮书 编者:OpenJWeb技术团队编写时间:2009-10-02Email:baozhengw@163.comQQ:29803446Msn:baozhengw9
  • 四款JAVA快速开发平台推荐

    万次阅读 2020-02-10 09:46:45
    JBoss Seam,算得上是Java开源框架里面最优秀的快速开发框架之一。 Seam框架非常出色,尤其是他的组件机制设计的很有匠心,真不愧是Gavin King精心打造的框架了,虽然看起来还是有些缺陷,但是做企业应用项目的话,...
  • 由于公司App开发的支付需求,需要后台用Java来完成银联支付接入接口。首先你要先进入银联开发登录地址open.unionpay.com找到手机控件支付模块,完成相应的入网步骤准备工作做完之后银联会对你发放相应的技术文档这里...
  • Java

    千次阅读 2020-08-01 09:56:23
    Java具有简单性、面向对象、分布式、健壮性、安全性、平台独立与可移植性、多线程、动态性、开源等特点 。Java可以编写桌面应用程序、Web应用程序、分布式系统和嵌入式系统应用程序等 。 2、java
  • 本文描述了J2ME运行平台在MTK系统下的设计和实现。首先,简要介绍了J2ME运行环境和MTK平台。...关键词 嵌入式系统 J2ME MTK Java虚拟机 移植接口引 言现在Java技术十分流行,发展势头强劲,而且在SUN公司
  • Java基础问题整理

    万次阅读 多人点赞 2020-04-07 11:44:14
    volatile作用(必考) 背景知识了解 Java的线程抽象内存模型 Java的线程抽象内存模型中定义了每个线程都有一份自己的私有内存,里面存放自己私有的数据,其他线程不能直接访问,而一些共享数据则存在主内存中,供...
  • java服务端监控平台设计

    千次阅读 2018-05-07 23:35:46
    如果监控结果满足配置的报警条件,会自动通知相关的负责人进行处理 监控系统模块 1、Client 主要职责是提供便利的方式让用户添加监控项。包括如下几个模块: Metrics 监控项:counter, timer, etc. AOP拦截配置或者...
  • java源码包---java 源码 大量 实例

    千次下载 热门讨论 2013-04-18 23:15:26
     Java实现的FTP连接与数据浏览程序,实现实例化可操作的窗口。  部分源代码摘录:  ftpClient = new FtpClient(); //实例化FtpClient对象  String serverAddr=jtfServer.getText(); //得到服务器地址  ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 49,348
精华内容 19,739
关键字:

java通知平台接口连接

java 订阅