最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringSecurity集成第三方登錄過程詳解(最新推薦)

 更新時間:2024年05月13日 11:41:14   作者:小???王八  
在ThirdAuthenticationFilter 類的attemptAuthentication()方法中,我們通過authType類型,然后創(chuàng)建對應(yīng)的Authentication實現(xiàn)來實現(xiàn)不同方式的登錄,下面給大家分享SpringSecurity集成第三方登錄過程,感興趣的朋友一起看看吧

SpringSecurity 集成第三方登錄

認證及自定義流程

首先我們提供一個實現(xiàn)了AbstractAuthenticationProcessingFilter抽象類的過濾器,用來代替UsernamePasswordAuthenticationFilter邏輯,然后提供一個AuthenticationProvider實現(xiàn)類代替AbstractUserDetailsAuthenticationProvider或DaoAuthenticationProvider,最后再提供一個UserDetailsService實現(xiàn)類。

1.驗證碼登錄

1.通用過濾器實現(xiàn)–ThirdAuthenticationFilter

這個ThirdAuthenticationFilter過濾器我們可以仿照UsernamePasswordAuthenticationFilter來實現(xiàn)(也實現(xiàn)了AbstractAuthenticationProcessingFilter抽象類),主要是重新定義了attemptAuthentication()方法,這里需要根據(jù)“authType”參數(shù)值的類別構(gòu)建不同的AbstractAuthenticationToken,具體實現(xiàn)如下:

    //驗證類型,比如Sms,uernamepassword等
    private String authTypeParameter = "authType";
    //對應(yīng)用戶名或手機號等
    private String principalParameter = "principal";
    //對應(yīng)密碼或驗證碼等
    private String credentialsParameter = "credentials";
    private boolean postOnly = true;
    public ThirdAuthenticationFilter() {
        super(new AntPathRequestMatcher("/login/doLogin", "POST"));
    }
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
        if (postOnly && !request.getMethod().equals("POST")) {
            throw new AuthenticationServiceException(
                    "Authentication method not supported: " + request.getMethod());
        }
        String authType = request.getParameter(authTypeParameter);
        if(StringUtils.isEmpty(authType)){
            authType = AuthTypeEnum.AUTH_TYPE_DEFAULT.getAuthType();
        }
        String principal = request.getParameter(principalParameter);
        String credentials = request.getParameter(credentialsParameter);
        AbstractAuthenticationToken authRequest = null;
        switch (authType){
            case "sms":
                authRequest = new SmsAuthenticationToken(principal, credentials);
                ((SmsAuthenticationToken)authRequest).setCode((String)request.getSession().getAttribute("code"));
                break;
            case "github":
                authRequest = new GithubAuthenticationToken(principal, credentials);
                break;
            case "default":
                authRequest = new UsernamePasswordAuthenticationToken(principal, credentials);
        }
        authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
        return this.getAuthenticationManager().authenticate(authRequest);
    }
}

定義了ThirdAuthenticationSecurityConfig 配置類,我們還需要在SpringSecurity配置類中應(yīng)用才能生效,具體實現(xiàn)如下:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests()
            .antMatchers("/error","/login/**","/login/goLogin","/login/doLogin","/login/code","/login/authorization_code").anonymous()
            .anyRequest().authenticated()
            .and()
            .formLogin()
            .loginPage("/login/goLogin")
            .loginProcessingUrl("/login/doLogin")
            .failureUrl("/login/error")
            .permitAll()
            .successHandler(new QriverAuthenticationSuccessHandler("/index/toIndex"));
	//這里我們省略了一些配置 ……
	//應(yīng)用前面定義的配置
    http.apply(thirdAuthenticationSecurityConfig);
}

至此,我們定義的通用第三方過濾器就完成了,并且也完成了在SpringSecurity中生效的配置。下面我們就開始分別實現(xiàn)不同類型登錄的具體過程。

在ThirdAuthenticationFilter 類的attemptAuthentication()方法中,我們通過authType類型,然后創(chuàng)建對應(yīng)的Authentication實現(xiàn)來實現(xiàn)不同方式的登錄,這里我們主要實現(xiàn)了如下三種方式,我們分別梳理一下。

3、默認的登錄過程

  默認的登錄過程,即根據(jù)用戶名密碼進行登錄,需要使用到UsernamePasswordAuthenticationToken,當“authType”參數(shù)為"default"時,這里就會創(chuàng)建UsernamePasswordAuthenticationToken對象,然后后續(xù)通過ProviderManager的authenticate()方法,最后就會調(diào)用AbstractUserDetailsAuthenticationProvider(DaoAuthenticationProvider)的 authenticate()方法,最終又會調(diào)用定義的UserDetailsService實現(xiàn)類。這是默認的過程,這里就不再重復(fù)其中的邏輯,除了UserDetailsService實現(xiàn)類需要自己定義,其他都是SpringSecurity提供的實現(xiàn)類。

4、短信驗證碼登錄實現(xiàn)

  短信驗證碼登錄,是最貼近用戶名密碼登錄的一種方式,所以我們完全可以仿照用戶名密碼這種方式實現(xiàn)。我們這里先梳理一下短信驗證碼登錄的業(yè)務(wù)邏輯:首先,登錄界面輸入手機號碼,然后再點擊“獲取驗證碼”按鈕獲取短信驗證碼,然后輸入收到的短信驗證碼,最后點擊“登錄”按鈕進行登錄認證。和用戶名密碼登錄相比,短信驗證碼登錄多了一個獲取驗證碼的過程,其他其實都是一樣的,我們下面逐步實現(xiàn)短信驗證碼登錄:

@RestController
@RequestMapping("/login")
public class SmsValidateCodeController {
	//生成驗證碼的實例對象
    @Autowired
    private ValidateCodeGenerator smsCodeGenerator;
    //調(diào)用服務(wù)商接口,發(fā)送短信驗證碼的實例對象
    @Autowired
    private DefaultSmsCodeSender defaultSmsCodeSender;
    @RequestMapping("/code")
    public String createSmsCode(HttpServletRequest request, HttpServletResponse response) throws ServletRequestBindingException {
        ValidateCode smsCode = smsCodeGenerator.generate(new ServletWebRequest(request));
        String mobile = (String)request.getParameter("principal");
        request.getSession().setAttribute("code",smsCode.getCode());
        defaultSmsCodeSender.send(mobile, smsCode.getCode());
        System.out.println("驗證碼:" + smsCode.getCode());
        return "驗證碼發(fā)送成功!";
    }
}

在上述方法中,我們注入了smsCodeGenerator和defaultSmsCodeSender兩個實例對象,分別用來生成驗證碼和發(fā)送短信驗證碼,這個可以根據(jù)項目的實際情況進行定義和實現(xiàn),這里不再貼出其中的實現(xiàn)。同時在createSmsCode()方法中,還有一點需要注意的就是,我們發(fā)出去的短信驗證碼需要進行保存,方便后續(xù)登錄時進行驗證,這個也可以選擇很多方法,比如說會話、數(shù)據(jù)庫、緩存等,我這里為了簡單,直接存到了session會話中了。

然后,我們前面定義ThirdAuthenticationFilter過濾器時,根據(jù)登錄方式不同,需要對應(yīng)的Authentication對象,這里我們還需要創(chuàng)建短信驗證登錄需要的Authentication類,這里我們可以仿照UsernamePasswordAuthenticationToken類進行編寫,實現(xiàn)如下

public class SmsAuthenticationToken  extends AbstractAuthenticationToken {
    //對應(yīng)手機號碼
    private final Object principal;
    //對應(yīng)手機驗證碼
    private Object credentials;
    //后臺存儲的短信驗證碼,用于驗證前端傳過來的是否正確
    private String code;
    public SmsAuthenticationToken(String mobile, Object credentials){
        super(null);
        this.principal = mobile;
        this.credentials = credentials;
        this.code = code;
        setAuthenticated(false);
    }
    public SmsAuthenticationToken(Object principal, Collection<? extends GrantedAuthority> authorities, Object credentials){
        super(authorities);
        this.principal = principal;
        this.credentials = credentials;
        super.setAuthenticated(true);
    }
    @Override
    public Object getCredentials() {
        return this.credentials;
    }
    @Override
    public Object getPrincipal() {
        return this.principal;
    }
    public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
        if (isAuthenticated) {
            throw new IllegalArgumentException(
                    "Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead");
        }
        super.setAuthenticated(false);
    }
    public String getCode() {
        return code;
    }
    public void setCode(String code) {
        this.code = code;
    }
    @Override
    public void eraseCredentials() {
        super.eraseCredentials();
        credentials = null;
    }
}

在SmsAuthenticationToken 類中,我們增加了一個code屬性,其實該屬性不是必須的,我這里是為了方便傳遞存儲在session會話中的驗證碼而添加的,如果使用緩存或數(shù)據(jù)庫進行存儲驗證碼,該屬性就可以省略。

在AuthenticationManager的authenticate()方法中,會根據(jù)Authentication類型選擇AuthenticationProvider對象,所以我們這里自定義短信驗證碼需要的AuthenticationProvider對象,實現(xiàn)如下:

@Component
public class SmsAuthenticationProvider implements AuthenticationProvider{
    @Autowired
    @Qualifier("smsUserDetailsService")
    private UserDetailsService userDetailsService;
    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        SmsAuthenticationToken token = (SmsAuthenticationToken) authentication;
        String mobile = (String)token.getPrincipal();
        //首先,驗證驗證碼是否正確
        String code = (String)token.getCredentials();
        String sCode = token.getCode();
        if(StringUtils.isEmpty(code) || !code.equalsIgnoreCase(sCode)){
            throw new BadCredentialsException("手機驗證碼錯誤(Bad credentials),請重試!");
        }
        //然后,查詢對應(yīng)用戶
        UserDetails user = userDetailsService.loadUserByUsername(mobile);
        if (Objects.isNull(user)) {
            throw new InternalAuthenticationServiceException("根據(jù)手機號:" + mobile + ",無法獲取對應(yīng)的用戶信息!");
        }
        SmsAuthenticationToken authenticationResult = new SmsAuthenticationToken(user.getUsername(), user.getAuthorities(), token.getCredentials());
        authenticationResult.setDetails(token.getDetails());
        return authenticationResult;
    }
    @Override
    public boolean supports(Class<?> authentication) {
        return SmsAuthenticationToken.class.isAssignableFrom(authentication);
    }
}

在SmsAuthenticationProvider 中,supports()方法決定了該實例對象僅支持SmsAuthenticationToken對象的驗證。同時,根據(jù)authenticate()方法傳遞參數(shù)authentication對象(包括了登錄信息:手機號和驗證碼,session存儲的驗證碼),我們這里session存儲的驗證碼,是因為我們采用了會話存儲的方式,如果使用數(shù)據(jù)庫,我們這里就可以通過手機號,去數(shù)據(jù)庫或緩存查詢對應(yīng)的驗證碼,然后和authentication對象傳遞過來的驗證碼進行比對,驗證成功,說明登錄認證成功,否則登錄認證失敗。登錄成功后,我們就可以調(diào)用userDetailsService對象的loadUserByUsername()方法獲取登錄用戶的其他相關(guān)信息(權(quán)限等),具體實現(xiàn)在自定義的SmsUserDetailsService類中實現(xiàn),具體如下:

@Component("smsUserDetailsService")
public class SmsUserDetailsService implements UserDetailsService {
    private Logger logger = LoggerFactory.getLogger(SmsUserDetailsService.class);
    @Autowired
    private SysUserService sysUserService;
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //1、查詢用戶信息
        SysUser user = new SysUser();
        user.setMobile(username);
        SysUser qUser = sysUserService.getOne(new QueryWrapper<>(user),true);
        if(qUser == null) {
            logger.info("手機號為”" + username + "“的用戶不存在?。。?);
            throw new UsernameNotFoundException("手機號為”" + username + "“的用戶不存在?。?!");
        }
        //2、封裝用戶角色
        UserRole userRole = sysUserService.getRoleByUserId(qUser.getId());
        Collection<GrantedAuthority> authorities = new ArrayList<>();
        authorities.add(new SimpleGrantedAuthority(String.valueOf(userRole.getRoleId())));
        return new LoginUser(qUser.getUsername(), qUser.getPassword(),authorities);
    } 
}

2.GitHub登錄

和短信驗證碼登錄認證相比,Github登錄又會有自己的特殊性,我們這里先梳理一下基于Github進行登錄驗證的大致邏輯:首先,點擊Github登錄認證按鈕,然后會跳轉(zhuǎn)到github登錄界面,輸入github系統(tǒng)的用戶名密碼,登錄成功,就會跳轉(zhuǎn)到我們自己的系統(tǒng)中的首頁。和基于用戶名密碼的登錄方式相比,Github登錄不需要類似用戶名和密碼這樣的輸入(在自己的系統(tǒng)中),同時又需要根據(jù)獲取到的github用戶信息,換取在自己系統(tǒng)對應(yīng)的用戶信息。具體實現(xiàn)步驟如下:

在github的配置省略

@Controller
@RequestMapping("/login")
public class GithubValidateController {
    @Autowired
    private GithubClientService githubClientService;
    @RequestMapping("/authorization_code")
    public void authorization_code(HttpServletRequest request, HttpServletResponse response, String code) throws ServletRequestBindingException, IOException {
        //github登錄驗證,并獲取access_token
        Map<String,String> resp = githubClientService.queryAccessToken(code);
        //跳轉(zhuǎn)本系統(tǒng)的登錄流程,獲取用戶信息,實現(xiàn)兩個系統(tǒng)用戶的對接
        String url = "http://localhost:8888/qriver-admin/login/doLogin";
        this.sendByPost(response, url,resp.get("access_token"),"github");
        //this.sendByPost(response, url,"access_token","github");
    }
    public void sendByPost(HttpServletResponse response,String url, String principal, String authType) throws IOException {
        response.setContentType("text/html");
        PrintWriter out = response.getWriter();
        out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");
        out.println("<HTML>");
        out.println(" <HEAD><TITLE>Post 方法</TITLE></HEAD>");
        out.println(" <BODY>");
        out.println("<form name=\"submitForm\" action=\"" + url + "\" method=\"post\">");
        out.println("<input type=\"hidden\" name=\"principal\" value=\"" + principal + "\"/>");
        out.println("<input type=\"hidden\" name=\"authType\" value=\"" + authType + "\"/>");
        out.println("</from>");
        out.println("<script>window.document.submitForm.submit();</script> ");
        out.println(" </BODY>");
        out.println("</HTML>");
        out.flush();
        out.close();
    }
}

“/login/authorization_code”接口對應(yīng)了我們在Github中配置的回調(diào)函數(shù),即在Github登錄驗證成功后,就會回調(diào)該接口,我們就是就在回調(diào)方法中,模擬了用戶名密碼登錄的方式,調(diào)用了SpringSecurity登錄認證需要的“/login/doLogin”接口。這里,我們通過queryAccessToken()方法根據(jù)回調(diào)傳遞的code獲取對應(yīng)的accessToken,然后把accessToken作為登錄使用的principal 參數(shù)值,之而立不需要傳遞密碼,因為我們經(jīng)過Github授權(quán),就可以認為完成了登錄認證的判斷過程了。

其中GithubClientService類,提供了獲取accessToken和用戶信息的兩個方法,具體實現(xiàn)方式如下:

@Service
public class GithubClientService {
	//前面在github中配置時產(chǎn)生的
    private String clientId = "######";
    private String clientSecret = "######";
    private String state = "123";
    private String redirectUri = "http://localhost:8888/qriver-admin/login/authorization_code";
    @Autowired
    private RestTemplate restTemplate;
    @Nullable
    private WebApplicationContext webApplicationContext;
	//獲取accessToken
    public Map<String, String> queryAccessToken(String code ){
        Map<String, String> map = new HashMap<>();
        map.put("client_id", clientId);
        map.put("client_secret", clientSecret);
        map.put("state", state);
        map.put("code", code);
        map.put("redirect_uri", redirectUri);
        Map<String,String> resp = restTemplate.postForObject("https://github.com/login/oauth/access_token", map, Map.class);
        return resp;
    }
	//獲取用戶信息
    public Map<String, Object> queryUser(String accessToken){
        HttpHeaders httpheaders = new HttpHeaders();
        httpheaders.add("Authorization", "token " + accessToken);
        HttpEntity<?> httpEntity = new HttpEntity<>(httpheaders);
        ResponseEntity<Map> exchange = restTemplate.exchange("https://api.github.com/user", HttpMethod.GET, httpEntity, Map.class);
        System.out.println("exchange.getBody() = " + exchange.getBody());
        return exchange == null ? null : exchange.getBody();
    }
}

其實,完成了上述的配置和方式后,后續(xù)的方式就和短信驗證碼的邏輯一樣了,這里我們簡要的再梳理一下。

首先,我們也需要定義一個基于Github登錄需要的Authentication實現(xiàn)類,具體實現(xiàn)和前面的SmsAuthenticationToken類似,這里不再重復(fù)貼代碼了。

然后,我們再定義一個AuthenticationProvider實現(xiàn)類GithubAuthenticationProvider,具體實現(xiàn)如下:

@Component
public class GithubAuthenticationProvider implements AuthenticationProvider{
    @Autowired
    @Qualifier("githubUserDetailsService")
    private UserDetailsService userDetailsService;
    @Autowired
    private GithubClientService githubClientService;
    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        GithubAuthenticationToken token = (GithubAuthenticationToken) authentication;
        String accessToken = (String)token.getPrincipal();
        //根據(jù)accessToken 獲取github用戶信息
        Map<String, Object> userInfo = githubClientService.queryUser(accessToken);
        //然后,根據(jù)github用戶,查詢對應(yīng)系統(tǒng)用戶信息
        UserDetails user = userDetailsService.loadUserByUsername((String)userInfo.get("login"));
        if (Objects.isNull(user)) {
            throw new InternalAuthenticationServiceException("根據(jù)accessToken:" + accessToken + ",無法獲取對應(yīng)的用戶信息!");
        }
        GithubAuthenticationToken authenticationResult = new GithubAuthenticationToken(user.getUsername(), user.getAuthorities(), token.getCredentials());
        authenticationResult.setDetails(token.getDetails());
        return authenticationResult;
    }
    @Override
    public boolean supports(Class<?> authentication) {
        return GithubAuthenticationToken.class.isAssignableFrom(authentication);
    }
}

在GithubAuthenticationProvider 類的authenticate()方法中,參數(shù)authentication中對應(yīng)的是Github授權(quán)后傳遞的accessToken值,我們這里需要根據(jù)accessToken值換取Github用戶信息,這里通過queryUser()方法實現(xiàn),然后根據(jù)github用戶名去獲取對應(yīng)的系統(tǒng)用戶信息。如果根據(jù)github用戶名用戶獲取的系統(tǒng)用戶為空,我們可以根據(jù)自己的需求,自動生成一個用戶或者跳轉(zhuǎn)到注冊頁面,讓用戶注冊一個頁面,這里為了簡單,我們直接拋出了一個異常。

關(guān)于自定義UserDetailsService實現(xiàn)類,主要需要實現(xiàn)根據(jù)github用戶名查詢對應(yīng)系統(tǒng)用戶的功能

當認證完成后要返回token可以實現(xiàn)AuthenticationSuccessHandler

import org.springframework.security.core.Authentication;  
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;  
import javax.servlet.http.HttpServletRequest;  
import javax.servlet.http.HttpServletResponse;  
import java.io.IOException;  
public class CustomAuthenticationSuccessHandler implements AuthenticationSuccessHandler {  
    private final JwtTokenProvider jwtTokenProvider; // 假設(shè)你有一個JwtTokenProvider類來生成JWT  
    public CustomAuthenticationSuccessHandler(JwtTokenProvider jwtTokenProvider) {  
        this.jwtTokenProvider = jwtTokenProvider;  
    }  
    @Override  
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException {  
        // 生成JWT  
        String token = jwtTokenProvider.generateToken(authentication);  
        // 將JWT添加到響應(yīng)頭中  
        response.setHeader("Authorization", "Bearer " + token);  
        // 或者將JWT添加到響應(yīng)體中(取決于你的API設(shè)計)  
        // response.getWriter().write(token);  
        response.setStatus(HttpServletResponse.SC_OK);  
    }  
}

并在securityconfig中設(shè)置

到此這篇關(guān)于SpringSecurity集成第三方登錄的文章就介紹到這了,更多相關(guān)SpringSecurity登錄內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 基于spring@aspect注解的aop實現(xiàn)過程代碼實例

    基于spring@aspect注解的aop實現(xiàn)過程代碼實例

    這篇文章主要介紹了基于spring@aspect注解的aop實現(xiàn)過程代碼實例,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-03-03
  • Java中的延遲隊列DelayQueue詳細解析

    Java中的延遲隊列DelayQueue詳細解析

    這篇文章主要介紹了Java中的延遲隊列DelayQueue詳細解析,JDK自身支持延遲隊列的數(shù)據(jù)結(jié)構(gòu),其實類:java.util.concurrent.DelayQueue,<BR>我們通過閱讀源碼的方式理解該延遲隊列類的實現(xiàn)過程,需要的朋友可以參考下
    2023-12-12
  • 完美解決java.lang.OutOfMemoryError處理錯誤的問題

    完美解決java.lang.OutOfMemoryError處理錯誤的問題

    下面小編就為大家?guī)硪黄昝澜鉀Qjava.lang.OutOfMemoryError處理錯誤的問題。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-01-01
  • springboot項目連接多種數(shù)據(jù)庫該如何操作詳析

    springboot項目連接多種數(shù)據(jù)庫該如何操作詳析

    在Spring Boot應(yīng)用中連接多個數(shù)據(jù)庫或數(shù)據(jù)源可以使用多種方式,下面這篇文章主要給大家介紹了關(guān)于springboot項目連接多種數(shù)據(jù)庫該如何操作的相關(guān)資料,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2024-08-08
  • Spring?Security登錄表單配置示例詳解

    Spring?Security登錄表單配置示例詳解

    這篇文章主要介紹了Spring?Security登錄表單配置,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-06-06
  • java-jwt通過公鑰字符串驗證解析token方式

    java-jwt通過公鑰字符串驗證解析token方式

    本文示例如何將公鑰字符串轉(zhuǎn)換為RSAPublicKey對象以校驗JWT token,解決了Java-JWT庫中公鑰格式不匹配的問題,并提供代碼測試方法
    2025-08-08
  • 解決無法刪除VMware虛擬機文件的問題及分析

    解決無法刪除VMware虛擬機文件的問題及分析

    用戶遇到無法刪除VMware文件夾的問題,因系統(tǒng)顯示文件夾正在運行,通過任務(wù)管理器終止所有含“vmware”的進程后成功刪除,總結(jié)為:強制結(jié)束VMware相關(guān)進程可解決文件夾刪除失敗問題,建議后續(xù)遇到類似情況采用此方法
    2025-07-07
  • 利用Java簡單實現(xiàn)一個代碼行數(shù)統(tǒng)計器方法實例

    利用Java簡單實現(xiàn)一個代碼行數(shù)統(tǒng)計器方法實例

    這篇文章主要給大家介紹了關(guān)于如何利用Java簡單實現(xiàn)一個代碼行數(shù)統(tǒng)計器的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11
  • GraalVm的反射配置輔助工具agentlib配置及使用

    GraalVm的反射配置輔助工具agentlib配置及使用

    這篇文章主要為大家介紹了GraalVm的反射配置輔助工具agentlib的配置文件及使用說明,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步
    2022-02-02
  • 一篇文章總結(jié)Java虛擬機內(nèi)存區(qū)域模型

    一篇文章總結(jié)Java虛擬機內(nèi)存區(qū)域模型

    這篇文章主要介紹了一篇文章總結(jié)Java虛擬機內(nèi)存區(qū)域模型,本篇文章主要來總結(jié)一下Java虛擬機內(nèi)存的各個區(qū)域,以及這些區(qū)域的作用、服務(wù)對象以及其中可能產(chǎn)生的問題,作為大家的面試寶典。,需要的朋友可以參考下
    2019-06-06

最新評論

昌邑市| 泗洪县| 仁布县| 札达县| 商水县| 新巴尔虎右旗| 怀柔区| 长寿区| 承德县| 枣庄市| 藁城市| 左权县| 新干县| 怀化市| 荔波县| 深泽县| 吴旗县| 昌吉市| 涞源县| 区。| 沧州市| 裕民县| 乌苏市| 西乡县| 靖安县| 扶绥县| 太和县| 马鞍山市| 汉寿县| 罗源县| 深州市| 辉县市| 淮北市| 五华县| 巴南区| 柘城县| 清徐县| 靖安县| 济南市| 临颍县| 开平市|