Spring Security生产环境下的安全配置最佳实践

 更新时间:2026年06月26日 08:32:14   作者:知远漫谈  
在当今高度互联的数字世界中,应用程序的安全性已成为开发团队不可忽视的核心议题,尤其是在使用像 Spring Security这样的主流框架构建企业级应用时,确保系统在生产环境中具备足够的防护能力至关重要,本文将深入探讨如何在生产环境下正确配置和使用Spring Security

引言

在当今高度互联的数字世界中,应用程序的安全性已成为开发团队不可忽视的核心议题。尤其是在使用像 Spring BootSpring Security 这样的主流框架构建企业级应用时,确保系统在生产环境中具备足够的防护能力至关重要。本文将深入探讨如何在生产环境下正确配置和使用 Spring Security,涵盖身份认证、授权控制、会话管理、CSRF 防护、CORS 策略、密码加密、OAuth2 集成等多个方面,并结合实际 Java 代码示例与架构图进行说明。

无论你是正在搭建一个全新的微服务系统,还是对现有系统的安全性进行加固,本文都将为你提供一套完整且可落地的最佳实践方案 。

为什么需要关注生产环境中的 Spring Security?

Spring Security 是一个功能强大且灵活的安全框架,它为基于 Spring 的应用程序提供了全面的身份验证(Authentication)和授权(Authorization)支持。然而,其灵活性也带来了复杂性 —— 如果配置不当,即使是看似“安全”的设置也可能暴露出严重的漏洞。

在开发环境中,我们可能允许匿名访问、关闭 CSRF 保护、使用简单的内存用户存储等,但在生产环境中,这些做法都可能成为攻击者的突破口:

  • 暴露敏感端点(如 /actuator/**
  • 使用弱密码策略或明文存储凭证
  • 缺乏会话固定攻击(Session Fixation)防护
  • 忽视跨站请求伪造(CSRF)
  • 不合理的 CORS 配置导致信息泄露

因此,我们必须以“最小权限原则”和“纵深防御”(Defense in Depth)为核心思想来设计我们的安全架构。

Spring Security 架构概览

在深入配置之前,先让我们从整体上理解 Spring Security 的工作流程。下面是一个典型的请求处理链路:

这个流程展示了 Spring Security 如何通过一系列过滤器拦截请求并执行安全检查。每一个环节都可以被定制化扩展,但同时也要求开发者对其行为有清晰的理解。

启用 Spring Security:基础依赖配置

首先,在你的 pom.xml 中添加必要的依赖项:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- 可选:用于 JWT 支持 -->
    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt-api</artifactId>
        <version>0.11.5</version>
    </dependency>
    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt-impl</artifactId>
        <version>0.11.5</version>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt-jackson</artifactId>
        <version>0.11.5</version>
        <scope>runtime</scope>
    </dependency>
</dependencies>

一旦引入了 spring-boot-starter-security,Spring Boot 就会自动启用默认的安全配置:所有路径都需要认证,使用内置的登录页或 HTTP Basic 认证。

但这只是起点。我们需要根据生产需求进行精细化配置。

配置 WebSecurityConfigurerAdapter(现代方式使用 SecurityFilterChain)

⚠️ 注意:自 Spring Security 5.7 起,WebSecurityConfigurerAdapter 已被标记为过时(deprecated)。推荐使用基于组件的配置方式,即直接声明 SecurityFilterChain Bean。

以下是生产环境中推荐的 SecurityFilterChain 配置模板:

@Configuration
@EnableWebSecurity
public class ProductionSecurityConfig {

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder(13); // 推荐强度为 13
    }

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .csrf(csrf -> csrf
                .ignoringRequestMatchers("/h2-console/**") // 仅限调试时临时忽略
                .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
            )
            .headers(headers -> headers
                .frameOptions().sameOrigin() // 允许同源嵌套 iframe(如 H2 控制台)
                .contentSecurityPolicy(csp -> csp
                    .policyDirectives("default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:")
                )
            )
            .authorizeHttpRequests(authz -> authz
                .requestMatchers("/public/**", "/register", "/login").permitAll()
                .requestMatchers("/actuator/health", "/actuator/info").permitAll()
                .requestMatchers("/actuator/**").hasRole("ADMIN")
                .requestMatchers("/api/admin/**").hasAnyRole("ADMIN")
                .requestMatchers("/api/user/**").hasAnyRole("USER", "ADMIN")
                .anyRequest().authenticated()
            )
            .formLogin(form -> form
                .loginPage("/login") // 自定义登录页面
                .failureUrl("/login?error")
                .defaultSuccessUrl("/dashboard", true)
                .permitAll()
            )
            .logout(logout -> logout
                .logoutUrl("/logout")
                .logoutSuccessUrl("/login?logout")
                .invalidateHttpSession(true)
                .deleteCookies("JSESSIONID", "XSRF-TOKEN")
                .permitAll()
            )
            .sessionManagement(session -> session
                .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
                .maximumSessions(1)
                .maxSessionsPreventsLogin(false)
                .expiredUrl("/login?expired")
            );

        // 允许 H2 控制台显示(仅限测试环境!)
        if ("dev".equals(System.getProperty("env"))) {
            http.headers().frameOptions().sameOrigin();
        }

        return http.build();
    }
}

关键配置解析:

配置项说明
csrf()启用 CSRF 防护,默认开启,防止跨站请求伪造攻击
headers()设置安全响应头,提升前端安全性
authorizeHttpRequests()定义 URL 级别的访问控制策略
formLogin()自定义表单登录行为
logout()清理会话和 Cookie
sessionManagement()控制并发会话数量,防止会话劫持

用户认证:安全地管理用户凭据

在生产系统中,用户的认证数据必须得到妥善保护。以下是几个关键实践:

1. 使用强哈希算法加密密码

永远不要以明文形式存储密码。Spring Security 提供了多种 PasswordEncoder 实现,推荐使用 BCrypt

@Bean
public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder(13);
}

BCrypt 是一种自适应哈希函数,包含盐值(salt),能有效抵御彩虹表攻击。轮数(log rounds)设为 10–14 是合理范围,过高会影响性能。

你可以手动编码测试:

@Service
public class UserService {

    @Autowired
    private PasswordEncoder encoder;

    public String hashPassword(String rawPassword) {
        return encoder.encode(rawPassword);
    }

    public boolean verifyPassword(String rawPassword, String hashedPassword) {
        return encoder.matches(rawPassword, hashedPassword);
    }
}

2. 用户存储建议:数据库 vs LDAP vs OAuth2

存储方式适用场景安全性评估
数据库(JPA/JDBC)内部系统、注册用户较多✅ 推荐配合 BCrypt
LDAP/Active Directory企业内网统一身份认证✅ 高安全性,集中管理
OAuth2 / OpenID Connect第三方登录、SaaS 平台✅ 强大但需谨慎集成

例如,连接 LDAP 的配置如下:

@Configuration
public class LdapSecurityConfig {

    @Bean
    public SecurityFilterChain ldapFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(authz -> authz
                .anyRequest().authenticated()
            )
            .formLogin()
            .and()
            .ldapAuthentication()
                .userDnPatterns("uid={0},ou=people")
                .groupSearchBase("ou=groups")
                .contextSource()
                .url("ldap://localhost:389/dc=springframework,dc=org")
                .and()
            .passwordCompare()
                .passwordEncoder(new BCryptPasswordEncoder())
                .passwordAttribute("userPassword");

        return http.build();
    }
}

基于角色的访问控制(RBAC)与方法级安全

除了 URL 层面的权限控制,我们还应在业务逻辑层实施细粒度的访问控制。

启用方法级安全

添加注解驱动的方法安全控制:

@Configuration
@EnableMethodSecurity(securedEnabled = true, jsr250Enabled = true)
public class MethodSecurityConfig {
    // 方法安全已启用
}

现在可以在服务类中使用注解:

@Service
public class BankAccountService {

    @Secured("ROLE_ADMIN")
    public void deleteAccount(Long accountId) {
        System.out.println("账户已删除:" + accountId);
    }

    @RolesAllowed("USER")
    public BigDecimal getBalance(Long userId) {
        return queryBalanceFromDatabase(userId);
    }

    @PreAuthorize("hasRole('ADMIN') or #userId == authentication.principal.id")
    public void transferMoney(@P("userId") Long userId, BigDecimal amount) {
        // 只有管理员或本人可以操作
    }
}

使用表达式语言(SpEL)实现动态授权

Spring Security 支持 SpEL 表达式,可用于复杂的条件判断:

@PreAuthorize("@accountService.isOwner(#accountId, authentication)")
public Account getAccount(@PathVariable Long accountId) {
    return accountRepository.findById(accountId).orElseThrow();
}

// AccountService.java
@Component("accountService")
public class AccountService {
    public boolean isOwner(Long accountId, Authentication auth) {
        String currentUsername = auth.getName();
        User user = userRepository.findByUsername(currentUsername);
        return accountRepository.existsByIdAndOwner(accountId, user);
    }
}

这种方式实现了真正的“基于资源的所有权”控制,是 RBAC 的有力补充。

会话管理:防范会话劫持与固定攻击

会话是 Web 应用中最常见的攻击目标之一。以下是一些关键措施:

1. 防止会话固定攻击(Session Fixation)

Spring Security 默认会在成功认证后创建新的会话,防止攻击者预先设置会话 ID:

.sessionManagement(session -> session
    .sessionFixation().newSession() // 默认行为,强烈建议保留
    .maximumSessions(1)
    .expiredUrl("/login?expired")
)

2. 限制并发会话数量

防止单个用户同时在多个设备登录:

.maximumSessions(1)
.maxSessionsPreventsLogin(false) // 已登录时新登录会使旧会话失效

你也可以监听会话事件:

@Component
public class SessionRegistryImpl extends org.springframework.security.core.session.SessionRegistryImpl {

    @EventListener
    public void handleSessionStarted(SessionStartedEvent event) {
        log.info("用户 {} 开始新会话", event.getPrincipal());
    }

    @EventListener
    public void handleSessionDestroyed(SessionDestroyedEvent event) {
        log.warn("会话结束,原因:{}", event.getReason());
    }
}

3. 安全的 Cookie 设置

确保会话 Cookie 具备以下属性:

  • HttpOnly: 防止 XSS 读取
  • Secure: 仅通过 HTTPS 传输
  • SameSite=Strict/Lax: 防止 CSRF

可以通过配置实现:

@Bean
public CookieSerializer cookieSerializer() {
    DefaultCookieSerializer serializer = new DefaultCookieSerializer();
    serializer.setCookieName("JSESSIONID");
    serializer.setCookiePath("/");
    serializer.setDomainNamePattern("^.+?\\.(\\w+\\.[a-z]+)$");
    serializer.setHttpOnly(true);
    serializer.setSecure(true); // 生产环境必须为 true
    serializer.setSameSite("Strict"); // 或 Lax
    return serializer;
}

CSRF 与 CORS:平衡安全与可用性

什么是 CSRF?如何防范?

跨站请求伪造(Cross-Site Request Forgery)是指攻击者诱导用户在已登录状态下发起非预期的操作。

Spring Security 默认启用 CSRF 防护,适用于基于 Cookie/Session 的认证机制。

启用 CSRF Token

前端需要获取 _csrf token 并在每个 POST 请求中携带:

<form action="/transfer" method="post">
    <input type="hidden" name="_csrf" value="${_csrf.token}"/>
    <input type="text" name="amount"/>
    <button type="submit">转账</button>
</form>

或者使用 JavaScript 提取:

const csrfToken = document.querySelector('[name=_csrf]').value;
fetch('/api/data', {
    method: 'POST',
    headers: {
        'X-XSRF-TOKEN': csrfToken,
        'Content-Type': 'application/json'
    },
    body: JSON.stringify(data)
});

注意:如果你使用 JWT 或 OAuth2 Bearer Token,通常不需要 CSRF 保护,因为不依赖 Cookie。

CSRF Token 存储策略

推荐使用 CookieCsrfTokenRepository,将 token 写入名为 XSRF-TOKEN 的 cookie:

.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())

这样前端 JavaScript 才能读取该 token 并放入请求头。

CORS 配置:只允许可信来源

跨域资源共享(CORS)如果不当配置,可能导致敏感数据泄露。

@Bean
public CorsConfigurationSource corsConfigurationSource() {
    CorsConfiguration config = new CorsConfiguration();
    config.setAllowedOriginPatterns(List.of("https://yourapp.com")); // 不要使用 "*"
    config.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE"));
    config.setAllowedHeaders(Arrays.asList("*"));
    config.setAllowCredentials(true); // 若需传递 Cookie,则必须为 true
    config.setMaxAge(3600L);

    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/api/**", config);
    return source;
}

然后在 SecurityFilterChain 中启用:

http.cors(cors -> cors.configurationSource(corsConfigurationSource()))

最佳实践总结:

项目推荐做法
Allowed Origins明确指定域名,避免通配符 *
Credentials如需携带 Cookie,设置 withCredentials=true
Max-Age设置缓存时间减少预检请求
Preflight Requests确保 OPTIONS 请求无需认证

使用 JWT 实现无状态认证(适合微服务)

在前后端分离或微服务架构中,传统的 Session 认证存在扩展性问题。此时推荐使用 JWT(JSON Web Token) 实现无状态认证。

JWT 结构示意

典型结构:xxxxx.yyyyy.zzzzz

创建 JWT 工具类

@Component
public class JwtUtil {

    private final String SECRET_KEY = "your-strong-secret-key-must-be-at-least-256-bits-long";
    private final long EXPIRATION_TIME = 86400000; // 24 hours

    public String generateToken(UserDetails userDetails) {
        Map<String, Object> claims = new HashMap<>();
        return Jwts.builder()
                .setClaims(claims)
                .setSubject(userDetails.getUsername())
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
                .signWith(SignatureAlgorithm.HS512, SECRET_KEY)
                .compact();
    }

    public Boolean validateToken(String token, UserDetails userDetails) {
        final String username = getUsernameFromToken(token);
        return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
    }

    public String getUsernameFromToken(String token) {
        return Jwts.parser()
                .setSigningKey(SECRET_KEY)
                .parseClaimsJws(token)
                .getBody()
                .getSubject();
    }

    private Boolean isTokenExpired(String token) {
        return Jwts.parser()
                .setSigningKey(SECRET_KEY)
                .parseClaimsJws(token)
                .getBody()
                .getExpiration()
                .before(new Date());
    }
}

自定义 JWT 认证过滤器

@Component
@RequiredArgsConstructor
public class JwtRequestFilter extends OncePerRequestFilter {

    private final UserDetailsService userDetailsService;
    private final JwtUtil jwtUtil;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws ServletException, IOException {

        final String authorizationHeader = request.getHeader("Authorization");

        String username = null;
        String jwt = null;

        if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
            jwt = authorizationHeader.substring(7);
            try {
                username = jwtUtil.getUsernameFromToken(jwt);
            } catch (Exception e) {
                logger.warn("无法解析 JWT Token", e);
            }
        }

        if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
            UserDetails userDetails = userDetailsService.loadUserByUsername(username);
            if (jwtUtil.validateToken(jwt, userDetails)) {
                UsernamePasswordAuthenticationToken authToken =
                        new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
                authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                SecurityContextHolder.getContext().setAuthentication(authToken);
            }
        }
        chain.doFilter(request, response);
    }
}

配置无状态安全链

@Bean
public SecurityFilterChain jwtFilterChain(HttpSecurity http) throws Exception {
    http
        .csrf(csrf -> csrf.disable()) // JWT 无需 CSRF
        .cors(cors -> cors.configurationSource(corsConfigurationSource()))
        .sessionManagement(session -> session
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
        )
        .authorizeHttpRequests(authz -> authz
            .requestMatchers("/authenticate", "/register").permitAll()
            .requestMatchers("/admin/**").hasRole("ADMIN")
            .anyRequest().authenticated()
        )
        .addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);

    return http.build();
}

💡 提示:JWT 不应包含敏感信息,且应设置合理的过期时间。考虑使用 Refresh Token 机制延长登录状态。

安全监控与审计日志

安全不仅在于预防,更在于发现异常后的快速响应。

启用 Spring Security 审计事件

Spring Security 提供了丰富的事件机制:

@Component
public class SecurityAuditListener {

    private static final Logger log = LoggerFactory.getLogger(SecurityAuditListener.class);

    @EventListener
    public void onSuccess(AuthenticationSuccessEvent success) {
        String username = ((UserDetails) success.getAuthentication().getPrincipal()).getUsername();
        log.info("登录成功: 用户={}", username);
    }

    @EventListener
    public void onFailure(AbstractAuthenticationFailureEvent failure) {
        String username = failure.getAuthentication().getName();
        log.warn("登录失败: 用户={}, 原因={}", username, failure.getException().getMessage());
    }

    @EventListener
    public void onLogout(LogoutSuccessEvent logout) {
        log.info("用户登出: {}", logout.getAuthentication().getName());
    }
}

这些日志可用于后续分析、告警甚至对接 SIEM 系统(如 Splunk、ELK)。

敏感操作日志记录

对于关键业务操作(如转账、删除账户),建议额外记录审计日志:

@Service
public class AccountService {

    private final AuditLogRepository auditLogRepository;

    @Autowired
    private AuthenticationFacade authFacade; // 获取当前用户

    @Transactional
    public void closeAccount(Long accountId) {
        User currentUser = authFacade.getCurrentUser();

        // 执行业务逻辑...
        accountRepository.deleteById(accountId);

        // 记录审计日志
        AuditLog log = new AuditLog(
            currentUser.getId(),
            "CLOSE_ACCOUNT",
            "用户关闭账户: " + accountId,
            new Date()
        );
        auditLogRepository.save(log);
    }
}

测试你的安全配置

再完美的配置也需要验证。以下是几种有效的测试手段:

1. 使用 TestSecurityContext

@SpringBootTest
@AutoConfigureTestDatabase
class SecureControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @Test
    @WithMockUser(username = "test@example.com", roles = {"USER"})
    void shouldAccessUserProfile() throws Exception {
        mockMvc.perform(get("/api/user/profile"))
               .andExpect(status().isOk());
    }

    @Test
    void shouldRedirectToLoginWhenNotAuthenticated() throws Exception {
        mockMvc.perform(get("/api/admin/settings"))
               .andExpect(status().isFound())
               .andExpect(header().string("Location", "/login"));
    }

    @Test
    @WithMockUser(username = "hacker", roles = "USER")
    void shouldDenyAccessToAdminEndpoint() throws Exception {
        mockMvc.perform(get("/api/admin/secrets"))
               .andExpect(status().isForbidden());
    }
}

2. 使用 OWASP ZAP 进行自动化扫描

OWASP Zed Attack Proxy (ZAP) 是一款开源的渗透测试工具,可自动检测 CSRF、XSS、SQL 注入等常见漏洞。

启动 ZAP → 输入目标 URL → 开始主动扫描 → 查看报告并修复问题。

第三方集成:OAuth2 与 OpenID Connect

对于需要支持第三方登录(如 Google、GitHub、微信)的应用,推荐使用 OAuth2 Login

配置 Google 登录

spring:
  security:
    oauth2:
      client:
        registration:
          google:
            client-id: your-client-id
            client-secret: your-client-secret
            scope: email,profile

然后启用 OAuth2 登录:

@Bean
public SecurityFilterChain oauth2FilterChain(HttpSecurity http) throws Exception {
    http
        .authorizeHttpRequests(authz -> authz
            .requestMatchers("/").permitAll()
            .anyRequest().authenticated()
        )
        .oauth2Login(oauth2 -> oauth2
            .defaultSuccessUrl("/dashboard", true)
        )
        .logout(logout -> logout
            .logoutSuccessUrl("/")
        );

    return http.build();
}

用户点击 <a href="/oauth2/authorization/google">使用 Google 登录</a> 即可完成授权。

更多提供商配置见 Spring Security OAuth2 Client Guide

安全清理:移除危险端点与默认行为

许多安全隐患来自未注意到的“便利功能”。

禁用敏感 Actuator 端点

management:
  endpoints:
    web:
      exposure:
        include: health,info
  endpoint:
    shutdown:
      enabled: false
    env:
      enabled: false
    beans:
      enabled: false
    mappings:
      enabled: false

只暴露必要的健康检查接口,其余全部关闭。

移除默认错误页面泄露信息

@Controller
public class ErrorController implements org.springframework.boot.web.servlet.error.ErrorController {

    @RequestMapping("/error")
    public ResponseEntity<Map<String, Object>> handleError() {
        Map<String, Object> body = new HashMap<>();
        body.put("error", "发生错误");
        body.put("timestamp", LocalDateTime.now());
        return ResponseEntity.status(500).body(body);
    }
}

避免返回堆栈跟踪等敏感信息。

总结:构建坚不可摧的安全防线

Spring Security 是一把双刃剑 —— 它赋予开发者强大的能力,但也要求极高的责任心。在生产环境中,我们必须始终坚持以下原则:

  • 永远不要信任输入
  • 最小权限原则
  • 纵深防御
  • 持续监控与更新

通过本文介绍的配置实践,你应该已经掌握了如何在真实项目中安全地使用 Spring Security。记住,安全不是一次性的任务,而是一个持续的过程。定期审查代码、更新依赖、进行渗透测试,才能真正守护用户的数据与信任。

安全是责任,更是承诺。

愿你的系统始终稳健运行,远离威胁!

以上就是Spring Security生产环境下的安全配置最佳实践的详细内容,更多关于Spring Security安全配置实践的资料请关注脚本之家其它相关文章!

相关文章

  • IDEA设置Tab选项卡快速的操作

    IDEA设置Tab选项卡快速的操作

    这篇文章主要介绍了IDEA设置Tab选项卡快速的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-02-02
  • 深入探讨Java内存区域

    深入探讨Java内存区域

    本篇文章对Java内存区域的使用进行了详细的介绍,内容很全面,需要的朋友可以参考下
    2015-07-07
  • JavaWeb导出Excel文件并弹出下载框

    JavaWeb导出Excel文件并弹出下载框

    这篇文章主要为大家详细介绍了JavaWeb导出Excel文件并弹出下载框的相关资料,感兴趣的小伙伴们可以参考一下
    2016-06-06
  • JVM致命错误日志详解(最新推荐)

    JVM致命错误日志详解(最新推荐)

    这篇文章主要介绍了JVM致命错误日志详解,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-06-06
  • Java 为什么要避免使用finalizer和Cleaner

    Java 为什么要避免使用finalizer和Cleaner

    这篇文章主要介绍了Java 为什么要避免使用finalizer和Cleaner,帮助大家更好的理解和学习使用Java,感兴趣的朋友可以了解下
    2021-03-03
  • Spring Cloud下OAUTH2注销的实现示例

    Spring Cloud下OAUTH2注销的实现示例

    本篇文章主要介绍了Spring Cloud下OAUTH2注销的实现示例,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-03-03
  • Spring MVC+FastJson+Swagger集成的完整实例教程

    Spring MVC+FastJson+Swagger集成的完整实例教程

    这篇文章主要给大家分享介绍了关于Spring MVC+FastJson+Swagger集成的完整实例教程,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧。
    2018-04-04
  • Java可变个数形参的方法实例代码

    Java可变个数形参的方法实例代码

    这篇文章主要给大家介绍了关于Java可变个数形参的相关资料,文中通过图文以及实例代码介绍的非常详细,对大家学习或者使用java具有一定的参考学习价值,需要的朋友可以参考下
    2022-02-02
  • Myeclipse链接Oracle等数据库时lo exception: The Network Adapter could not establish the connection

    Myeclipse链接Oracle等数据库时lo exception: The Network Adapter coul

    今天小编就为大家分享一篇关于Myeclipse链接Oracle等数据库时lo exception: The Network Adapter could not establish the connection,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-03-03
  • Java实现UTF-8转Unicode的代码详解

    Java实现UTF-8转Unicode的代码详解

    在现代计算机处理中,字符编码问题始终是一个基础而又重要的环节,随着国际化进程不断加快,UTF-8已成为互联网传输中最常见的字符编码之一,然而,在某些场景下需要将UTF-8编码格式的字符串转换为Unicode转义序列,所以本文介绍了Java实现UTF-8转Unicode的方法
    2025-06-06

最新评论