• <fieldset id="8imwq"><menu id="8imwq"></menu></fieldset>
  • <bdo id="8imwq"><input id="8imwq"></input></bdo>
    最新文章專題視頻專題問答1問答10問答100問答1000問答2000關鍵字專題1關鍵字專題50關鍵字專題500關鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關鍵字專題關鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
    問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
    當前位置: 首頁 - 科技 - 知識百科 - 正文

    由獲取微信access

    來源:懂視網 責編:小采 時間:2020-11-09 07:44:24
    文檔

    由獲取微信access

    由獲取微信access:背景 : access_token是公眾號的全局唯一票據,公眾號調用各接口時都需使用access_token。開發(fā)者需要進行妥善保存。access_token的存儲至少要保留512個字符空間。access_token的有效期目前為2個小時,需定時刷新,重復 獲取 將導致上次 獲取 的acces
    推薦度:
    導讀由獲取微信access:背景 : access_token是公眾號的全局唯一票據,公眾號調用各接口時都需使用access_token。開發(fā)者需要進行妥善保存。access_token的存儲至少要保留512個字符空間。access_token的有效期目前為2個小時,需定時刷新,重復 獲取 將導致上次 獲取 的acces

    背景 : access_token是公眾號的全局唯一票據,公眾號調用各接口時都需使用access_token。開發(fā)者需要進行妥善保存。access_token的存儲至少要保留512個字符空間。access_token的有效期目前為2個小時,需定時刷新,重復 獲取 將導致上次 獲取 的access_token

    背景:

    access_token是公眾號的全局唯一票據,公眾號調用各接口時都需使用access_token。開發(fā)者需要進行妥善保存。access_token的存儲至少要保留512個字符空間。access_token的有效期目前為2個小時,需定時刷新,重復獲取將導致上次獲取的access_token失效。

    1、為了保密appsecrect,第三方需要一個access_token獲取和刷新的中控服務器。而其他業(yè)務邏輯服務器所使用的access_token均來自于該中控服務器,不應該各自去刷新,否則會造成access_token覆蓋而影響業(yè)務;
    2、目前access_token的有效期通過返回的expire_in來傳達,目前是7200秒之內的值。中控服務器需要根據這個有效時間提前去刷新新access_token。在刷新過程中,中控服務器對外
    輸出的依然是老access_token,此時公眾平臺后臺會保證在刷新短時間內,新老access_token都可用,這保證了第三方業(yè)務的平滑過渡; 3、access_token的有效時間可能會在未來有調整,所以中控服務器不僅需要內部定時主動刷新,還需要提供被動刷新access_token的接口,這樣便于業(yè)務服務器在API調用獲知access_token已超時的情況下,可以觸發(fā)access_token的刷新流程。

    簡單起見,使用一個隨servlet容器一起啟動的servlet來實現獲取access_token的功能,具體為:因為該servlet隨著web容器而啟動,在該servlet的init方法中觸發(fā)一個線程來獲得access_token,該線程是一個無線循環(huán)的線程,每隔2個小時刷新一次access_token。相關代碼如下:
    1)servlet代碼:

    public class InitServlet extends HttpServlet 
    {
    	private static final long serialVersionUID = 1L;
    
    	public void init(ServletConfig config) throws ServletException 
    	{
    	new Thread(new AccessTokenThread()).start(); 
    	}
    
    }
    

    2)線程代碼:

    public class AccessTokenThread implements Runnable 
    {
    	public static AccessToken accessToken;
    	
    	@Override
    	public void run() 
    	{
    	while(true) 
    	{
    	try{
    	AccessToken token = AccessTokenUtil.freshAccessToken();	// 從微信服務器刷新access_token
    	if(token != null){
    	accessToken = token;
    	}else{
    	System.out.println("get access_token failed------------------------------");
    	}
    	}catch(IOException e){
    	e.printStackTrace();
    	}
    	
    	try{
    	if(null != accessToken){
    	Thread.sleep((accessToken.getExpire_in() - 200) * 1000);	// 休眠7000秒
    	}else{
    	Thread.sleep(60 * 1000);	// 如果access_token為null,60秒后再獲取
    	}
    	}catch(InterruptedException e){
    	try{
    	Thread.sleep(60 * 1000);
    	}catch(InterruptedException e1){
    	e1.printStackTrace();
    	}
    	}
    	}
    	}
    }
    

    3)AccessToken代碼:

    public class AccessToken 
    {
    	private String access_token;
    	private long expire_in;	// access_token有效時間,單位為妙
    	
    	public String getAccess_token() {
    	return access_token;
    	}
    	public void setAccess_token(String access_token) {
    	this.access_token = access_token;
    	}
    	public long getExpire_in() {
    	return expire_in;
    	}
    	public void setExpire_in(long expire_in) {
    	this.expire_in = expire_in;
    	}
    }
    

    4)servlet在web.xml中的配置

     
     initServlet
     com.sinaapp.wx.servlet.InitServlet
     0
     

    因為initServlet設置了load-on-startup=0,所以保證了在所有其它servlet之前啟動。

    其它servlet要使用access_token的只需要調用 AccessTokenThread.accessToken即可。

    引出多線程并發(fā)問題:

    1)上面的實現似乎沒有什么問題,但是仔細一想,AccessTokenThread類中的accessToken,它存在并發(fā)訪問的問題,它僅僅由AccessTokenThread每隔2小時更新一次,但是會有很多線程來讀取它,它是一個典型的讀多寫少的場景,而且只有一個線程寫。既然存在并發(fā)的讀寫,那么上面的代碼肯定是存在問題的。

    一般想到的最簡單的方法是使用synchronized來處理:

    public class AccessTokenThread implements Runnable 
    {
    	private static AccessToken accessToken;
    	
    	@Override
    	public void run() 
    	{
    	while(true) 
    	{
    	try{
    	AccessToken token = AccessTokenUtil.freshAccessToken();	// 從微信服務器刷新access_token
    	if(token != null){
    	AccessTokenThread.setAccessToken(token);
    	}else{
    	System.out.println("get access_token failed");
    	}
    	}catch(IOException e){
    	e.printStackTrace();
    	}
    	
    	try{
    	if(null != accessToken){
    	Thread.sleep((accessToken.getExpire_in() - 200) * 1000);	// 休眠7000秒
    	}else{
    	Thread.sleep(60 * 1000);	// 如果access_token為null,60秒后再獲取
    	}
    	}catch(InterruptedException e){
    	try{
    	Thread.sleep(60 * 1000);
    	}catch(InterruptedException e1){
    	e1.printStackTrace();
    	}
    	}
    	}
    	}
    
    	public synchronized static AccessToken getAccessToken() {
    	return accessToken;
    	}
    
    	private synchronized static void setAccessToken(AccessToken accessToken) {
    	AccessTokenThread2.accessToken = accessToken;
    	}
    }
    

    accessToken變成了private,setAccessToken也變成了private,增加了同步synchronized訪問accessToken的方法。

    那么到這里是不是就完美了呢?就沒有問題了呢?仔細想想,還是有問題,問題出在AccessToken類的定義上,它提供了public的set方法,那么所有的線程都在使用AccessTokenThread.getAccessToken()獲得了所有線程共享的accessToken之后,任何線程都可以修改它的屬性!!!!而這肯定是不對的,不應該的。

    2)解決方法一:

    我們讓AccessTokenThread.getAccessToken()方法返回一個accessToken對象的copy,副本,這樣其它的線程就無法修改AccessTokenThread類中的accessToken了。如下修改AccessTokenThread.getAccessToken()方法即可:

    	public synchronized static AccessToken getAccessToken() {
    	AccessToken at = new AccessToken();
    	at.setAccess_token(accessToken.getAccess_token());	
    	at.setExpire_in(accessToken.getExpire_in());
    	return at;
    	}
    

    也可以在AccessToken類中實現clone方法,原理都是一樣的。當然setAccessToken也變成了private。

    3)解決方法二:

    既然我們不應該讓AccessToken的對象被修改,那么我們?yōu)槭裁床粚ccessToken定義成一個“不可變對象”?相關修改如下:

    public class AccessToken 
    {
    	private final String access_token;
    	private final long expire_in;	// access_token有效時間,單位為妙
    	
    	public AccessToken(String access_token, long expire_in)
    	{
    	this.access_token = access_token;
    	this.expire_in = expire_in;
    	}
    	
    	public String getAccess_token() {
    	return access_token;
    	}
    	
    	public long getExpire_in() {
    	return expire_in;
    	}
    }
    

    如上所示,AccessToken所有的屬性都定義成了final類型了,只提供構造函數和get方法。這樣的話,其他的線程在獲得了AccessToken的對象之后,就無法修改了。改修改要求AccessTokenUtil.freshAccessToken()中返回的AccessToken的對象只能通過有參的構造函數來創(chuàng)建。同時AccessTokenThread的setAccessToken也要修改成private,getAccessToken無須返回一個副本了。

    注意不可變對象必須滿足下面的三個條件:

    a) 對象創(chuàng)建之后其狀態(tài)就不能修改;

    b) 對象的所有域都是final類型;

    c) 對象是正確創(chuàng)建的(即在對象的構造函數中,this引用沒有發(fā)生逸出);

    4)解決方法三:

    還有沒有其他更加好,更加完美,更加高效的方法呢?我們分析一下,在解決方法二中,AccessTokenUtil.freshAccessToken()返回的是一個不可變對象,然后調用private的AccessTokenThread.setAccessToken(AccessToken accessToken)方法來進行賦值。這個方法上的synchronized同步起到了什么作用呢?因為對象時不可變的,而且只有一個線程可以調用setAccessToken方法,那么這里的synchronized沒有起到"互斥"的作用(因為只有一個線程修改),而僅僅是起到了保證“可見性”的作用,讓修改對其它的線程可見,也就是讓其他線程訪問到的都是最新的accessToken對象。而保證“可見性”是可以使用volatile來進行的,所以這里的synchronized應該是沒有必要的,我們使用volatile來替代它。相關修改代碼如下:

    public class AccessTokenThread implements Runnable 
    {
    	private static volatile AccessToken accessToken;
    	
    	@Override
    	public void run() 
    	{
    	while(true) 
    	{
    	try{
    	AccessToken token = AccessTokenUtil.freshAccessToken();	// 從微信服務器刷新access_token
    	if(token != null){
    	AccessTokenThread2.setAccessToken(token);
    	}else{
    	System.out.println("get access_token failed");
    	}
    	}catch(IOException e){
    	e.printStackTrace();
    	}
    	
    	try{
    	if(null != accessToken){
    	Thread.sleep((accessToken.getExpire_in() - 200) * 1000);	// 休眠7000秒
    	}else{
    	Thread.sleep(60 * 1000);	// 如果access_token為null,60秒后再獲取
    	}
    	}catch(InterruptedException e){
    	try{
    	Thread.sleep(60 * 1000);
    	}catch(InterruptedException e1){
    	e1.printStackTrace();
    	}
    	}
    	}
    	}
    
    	private static void setAccessToken(AccessToken accessToken) {
    	AccessTokenThread2.accessToken = accessToken;
    	}
    public static AccessToken getAccessToken() {
    return accessToken;
    } }

    也可以這樣改:

    public class AccessTokenThread implements Runnable 
    {
    	private static volatile AccessToken accessToken;
    	
    	@Override
    	public void run() 
    	{
    	while(true) 
    	{
    	try{
    	AccessToken token = AccessTokenUtil.freshAccessToken();	// 從微信服務器刷新access_token
    	if(token != null){
    	accessToken = token;
    	}else{
    	System.out.println("get access_token failed");
    	}
    	}catch(IOException e){
    	e.printStackTrace();
    	}
    	
    	try{
    	if(null != accessToken){
    	Thread.sleep((accessToken.getExpire_in() - 200) * 1000);	// 休眠7000秒
    	}else{
    	Thread.sleep(60 * 1000);	// 如果access_token為null,60秒后再獲取
    	}
    	}catch(InterruptedException e){
    	try{
    	Thread.sleep(60 * 1000);
    	}catch(InterruptedException e1){
    	e1.printStackTrace();
    	}
    	}
    	}
    	}
    
    	public static AccessToken getAccessToken() {
    	return accessToken;
    	}
    }
    

    還可以這樣改:

    public class AccessTokenThread implements Runnable 
    {
     public static volatile AccessToken accessToken;
     
     @Override
     public void run() 
     {
     while(true) 
     {
     try{
     AccessToken token = AccessTokenUtil.freshAccessToken(); // 從微信服務器刷新access_token
     if(token != null){
     accessToken = token;
     }else{
     System.out.println("get access_token failed");
     }
     }catch(IOException e){
     e.printStackTrace();
     }
     
     try{
     if(null != accessToken){
     Thread.sleep((accessToken.getExpire_in() - 200) * 1000); // 休眠7000秒
     }else{
     Thread.sleep(60 * 1000); // 如果access_token為null,60秒后再獲取
     }
     }catch(InterruptedException e){
     try{
     Thread.sleep(60 * 1000);
     }catch(InterruptedException e1){
     e1.printStackTrace();
     }
     }
     }
     }
    }

    accesToken變成了public,可以直接是一個AccessTokenThread.accessToken來訪問。

    其實這個問題的關鍵是:在多線程并發(fā)訪問的環(huán)境中如何正確的發(fā)布一個共享對象。

    聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

    文檔

    由獲取微信access

    由獲取微信access:背景 : access_token是公眾號的全局唯一票據,公眾號調用各接口時都需使用access_token。開發(fā)者需要進行妥善保存。access_token的存儲至少要保留512個字符空間。access_token的有效期目前為2個小時,需定時刷新,重復 獲取 將導致上次 獲取 的acces
    推薦度:
    標簽: 微信 背景 獲取
    • 熱門焦點

    最新推薦

    猜你喜歡

    熱門推薦

    專題
    Top
    主站蜘蛛池模板: 精品欧美激情在线看| 亚洲AV无码乱码精品国产| 久久精品无码一区二区三区免费| 精品国产sm捆绑最大网免费站| 国产午夜精品一区二区三区小说| 久久精品国产亚洲AV无码娇色| 久久国产精品偷99| 国产精品福利网站导航| 亚洲精品~无码抽插| 免费短视频软件精品一区二区| 青青青青久久精品国产| 国产精品无码AV一区二区三区| 中文字幕日韩精品有码视频| 精品国产一区二区三区久久蜜臀| 久久免费精品视频| 国产精品久久久亚洲| 少妇人妻无码精品视频| 久久夜色精品国产亚洲av| 99亚洲精品视频| 久久亚洲精品中文字幕三区| 992tv精品视频tv在线观看| 亚洲国产美女精品久久久久∴ | 精品欧美一区二区在线观看| 九九精品成人免费国产片| 国产精品无码av在线播放| 久久久久女人精品毛片| 亚洲av永久无码精品秋霞电影影院 | 国产精品天干天干综合网| 亚洲AV午夜福利精品一区二区| 青春草无码精品视频在线观 | 国产精品热久久毛片| 国产成人高清精品免费观看| 一本一道久久精品综合| 91亚洲精品麻豆| 人精品影院| 精品国产热久久久福利| 在线观看91精品国产入口| 欧美亚洲精品在线| 国产精品美女久久久久网| 精品国产美女福利到在线不卡| 久久国产成人精品麻豆|