Obtain WeChat access

Source: Internet
Author: User
Background: access_token is the globally unique ticket of the public account. access_token is used to call each interface of the public account. Developers need to properly store them. The storage of access_token must contain at least 512 characters. The validity period of access_token is currently 2 hours. You need to refresh the token regularly. Repeat the token to obtain the last access_token.

Background: access_token is the globally unique ticket of the public account. access_token is used to call each interface of the public account. Developers need to properly store them. The storage of access_token must contain at least 512 characters. The validity period of access_token is currently 2 hours. You need to refresh the token regularly. Repeat the token to obtain the last access_token.

Background:

Access_token is the globally unique ticket of the public account. access_token is required when the Public Account calls each interface. Developers need to properly store them. The storage of access_token must contain at least 512 characters. The validity period of access_token is currently 2 hours. You need to refresh it regularly and repeat it.ObtainWill cause the previousObtainThe access_token of is invalid.

1. To keep appsecrect confidential, a third party needs an access_token.ObtainAnd refresh the Central Control Server. The access_token used by other business logic servers comes from the Central Control Server and should not be refreshed separately. Otherwise, the access_token overwrites the service; 2. Currently, the validity period of the access_token is expressed by the returned expire_in. Currently, the value is within 7200 seconds. The central control server needs to refresh the new access_token in advance based on the validity period. During the refresh process, the Central Control Server still outputs the old access_token. At this time, the background of the public platform will ensure that the new and old access_token are available within a short period of time, this ensures the smooth transition of third-party services; 3. The validity period of access_token may be adjusted in the future. Therefore, the Central Control Server not only needs to actively refresh the service internally, you also need to provide an interface to passively refresh access_token, so that the Business Server can trigger the refresh process of access_token when the API call knows that access_token has timed out.

For simplicity, use a servlet started with the servlet container to implementObtainAccess_token function, specifically: Because the servlet starts with the web container, a thread is triggered in the init method of the servlet to obtain the access_token. This thread is a wireless loop thread, refresh the access_token every two hours. The related code is as follows:
1) servlet code:

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

2) thread code:

Public class AccessTokenThread implements Runnable {public static AccessToken accessToken; @ Overridepublic void run () {while (true) {try {AccessToken token = AccessTokenUtil. freshAccessToken (); // refresh access_tokenif (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); // sleep for 7000 seconds} else {Thread. sleep (60*1000); // If access_token is null, wait 60 seconds beforeObtain} Catch (InterruptedException e) {try {Thread. sleep (60*1000);} catch (InterruptedException e1) {e1.printStackTrace ();}}}}}

3) AccessToken code:

Public class AccessToken {private String access_token; private long expire_in; // access_token validity period, in the unit of 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 configuration in web. xml

  
     
  
   initServlet
      
  
   com.sinaapp.wx.servlet.InitServlet
      
  
   0
    
 

Because initServlet sets load-on-startup = 0, it ensures that all other servlets are started before.

To use access_token for other Servlets, you only need to call AccessTokenThread. accessToken.

Multi-thread concurrency:

1) there seems to be no problem with the above implementation, but after careful consideration, the accessToken in the AccessTokenThread class has the problem of concurrent access. It is updated only once every two hours by AccessTokenThread, however, there will be a lot of threads to read it. It is a typical scenario of reading more and writing less, and there is only one thread to write. Since concurrent reads and writes exist, the above Code must be faulty.

The simplest method is to use synchronized for processing:

Public class AccessTokenThread implements Runnable {private static AccessToken accessToken; @ Overridepublic void run () {while (true) {try {AccessToken token = AccessTokenUtil. freshAccessToken (); // refresh access_tokenif (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); // sleep for 7000 seconds} else {Thread. sleep (60*1000); // If access_token is null, wait 60 seconds beforeObtain} 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 ;}}

The accessToken is changed to private, and the setAccessToken is also changed to private. The synchronized access to accessToken is added.

So here is perfect? Is there no problem? Think about the problem. The problem lies in the definition of the AccessToken class. It provides the public set method, so all threads are using AccessTokenThread. after getAccessToken () obtains the accessToken shared by all threads, any thread can modify its attributes !!!! This is definitely not correct. It should not.

2) solution 1:

Let's let the AccessTokenThread. getAccessToken () method return the copy and copy of an accessToken object, so that other threads cannot modify the AccessTokenThread class's accessToken. Modify the AccessTokenThread. getAccessToken () method as follows:

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

You can also implement the clone method in the AccessToken class. The principles are the same. Of course, the setAccessToken is also private.

3) solution 2:

Since we should not modify the AccessToken object, why not define the accessToken as an "immutable object "? The related modifications are as follows:

Public class AccessToken {private final String access_token; private final long expire_in; // access_token effective time, in the unit of 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 ;}}

As shown above, all the attributes of AccessToken are defined as the final type. Only constructors and get methods are provided. In this case, other threads cannot modify the AccessToken object. The modification requires that the AccessTokenUtil. freshAccessToken () object returned by AccessTokenUtil can only be created through a constructor with parameters. At the same time, the setAccessToken of the AccessTokenThread must be changed to private. The getAccessToken does not need to return a copy.

Note that the immutable object must meet the following three conditions:

A) After an object is created, its status cannot be modified;

B) all fields of the object are of the final type;

C) the object is correctly created (that is, in the object constructor, this reference does not escape );

4) solution 3:

Are there other better, more perfect, and more efficient methods? In solution 2, AccessTokenUtil. freshAccessToken () returns an immutable object, and then calls the private AccessTokenThread. setAccessToken (AccessToken accessToken) method to assign values. What is the role of synchronized synchronization in this method? Because the object is immutable and only one thread can call the setAccessToken method, synchronized does not play a "mutex" role (because only one thread modifies the content ), it only plays a role of ensuring "visibility", allowing modifications to be visible to other threads, that is, allowing other threads to access the latest accessToken object. To ensure "visibility", you can use volatile. Therefore, synchronized here is unnecessary. We should use volatile to replace it. The related modification code is as follows:

Public class AccessTokenThread implements Runnable {private static volatile accesile en accesen en; @ Overridepublic void run () {while (true) {try {AccessToken token = AccessTokenUtil. freshAccessToken (); // refresh access_tokenif (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); // sleep for 7000 seconds} else {Thread. sleep (60*1000); // If access_token is null, wait 60 seconds beforeObtain} 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;
}}

You can also change it as follows:

Public class AccessTokenThread implements Runnable {private static volatile accesile en accesen en; @ Overridepublic void run () {while (true) {try {AccessToken token = AccessTokenUtil. freshAccessToken (); // refresh access_tokenif (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); // sleep for 7000 seconds} else {Thread. sleep (60*1000); // If access_token is null, wait 60 seconds beforeObtain} Catch (InterruptedException e) {try {Thread. sleep (60*1000);} catch (InterruptedException e1) {e1.printStackTrace () ;}}} public static AccessToken getAccessToken () {return accessToken ;}}

You can also change it as follows:

Public class AccessTokenThread implements Runnable {public static volatile accesile en accesen en; @ Override public void run () {while (true) {try {AccessToken token = AccessTokenUtil. freshAccessToken (); // refresh access_token from the server 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); // sleep for 7000 seconds} else {Thread. sleep (60*1000); // If access_token is null, wait 60 seconds beforeObtain} Catch (InterruptedException e) {try {Thread. sleep (60*1000);} catch (InterruptedException e1) {e1.printStackTrace ();}}}}}

The accesToken is changed to public, which can be accessed directly by an AccessTokenThread. accessToken.

In fact, the key to this problem is: how to correctly publish a shared object in the multi-thread concurrent access environment.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.