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

SpringBoot配置數(shù)據(jù)庫密碼加密的實(shí)現(xiàn)

 更新時(shí)間:2021年03月05日 10:15:50   作者:Zack_tzh  
這篇文章主要介紹了SpringBoot配置數(shù)據(jù)庫密碼加密的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

你在使用 MyBatis 的過程中,是否有想過多個(gè)數(shù)據(jù)源應(yīng)該如何配置,如何去實(shí)現(xiàn)?出于這個(gè)好奇心,我在 Druid Wiki 的數(shù)據(jù)庫多數(shù)據(jù)源中知曉 Spring 提供了對(duì)多數(shù)據(jù)源的支持,基于 Spring 提供的 AbstractRoutingDataSource,可以自己實(shí)現(xiàn)數(shù)據(jù)源的切換。

一、配置動(dòng)態(tài)數(shù)據(jù)源

下面就如何配置動(dòng)態(tài)數(shù)據(jù)源提供一個(gè)簡單的實(shí)現(xiàn):

org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource,代碼如下:

public abstract class AbstractRoutingDataSource extends AbstractDataSource implements InitializingBean {

 @Nullable
 private Object defaultTargetDataSource;

 @Nullable
 private Map<Object, DataSource> resolvedDataSources;

 @Nullable
 private DataSource resolvedDefaultDataSource;

 @Override
 public Connection getConnection() throws SQLException {
 return determineTargetDataSource().getConnection();
 }

 @Override
 public Connection getConnection(String username, String password) throws SQLException {
 return determineTargetDataSource().getConnection(username, password);
 }

 protected DataSource determineTargetDataSource() {
 Assert.notNull(this.resolvedDataSources, "DataSource router not initialized");
  // 確定當(dāng)前要使用的數(shù)據(jù)源
 Object lookupKey = determineCurrentLookupKey();
 DataSource dataSource = this.resolvedDataSources.get(lookupKey);
 if (dataSource == null && (this.lenientFallback || lookupKey == null)) {
 dataSource = this.resolvedDefaultDataSource;
 }
 if (dataSource == null) {
 throw new IllegalStateException("Cannot determine target DataSource for lookup key [" + lookupKey + "]");
 }
 return dataSource;
 }

 /**
 * Determine the current lookup key. This will typically be implemented to check a thread-bound transaction context.
 * <p>
 * Allows for arbitrary keys. The returned key needs to match the stored lookup key type, as resolved by the
 * {@link #resolveSpecifiedLookupKey} method.
 */
 @Nullable
 protected abstract Object determineCurrentLookupKey();
 
 // 省略相關(guān)代碼...
}

 重寫 AbstractRoutingDataSource 的 determineCurrentLookupKey() 方法,可以實(shí)現(xiàn)對(duì)多數(shù)據(jù)源的支持

思路:

  • 重寫其 determineCurrentLookupKey() 方法,支持選擇不同的數(shù)據(jù)源
  • 初始化多個(gè) DataSource 數(shù)據(jù)源到 AbstractRoutingDataSource 的 resolvedDataSources 屬性中
  • 然后通過 Spring AOP, 以自定義注解作為切點(diǎn),根據(jù)不同的數(shù)據(jù)源的 Key 值,設(shè)置當(dāng)前線程使用的數(shù)據(jù)源

接下來的實(shí)現(xiàn)方式是 Spring Boot 結(jié)合 Druid 配置動(dòng)態(tài)數(shù)據(jù)源

(一)引入依賴

基于 3.繼承SpringBoot 中已添加的依賴再添加對(duì)AOP支持的依賴,如下:

<dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

(二)開始實(shí)現(xiàn)

1. DataSourceContextHolder

DataSourceContextHolder 使用 ThreadLocal 存儲(chǔ)當(dāng)前線程指定的數(shù)據(jù)源的 Key 值,代碼如下:

package cn.tzh.mybatis.config;

import lombok.extern.slf4j.Slf4j;

import java.util.HashSet;
import java.util.Set;

/**
 * @author tzh
 * @date 2021/1/4 11:42
 */
@Slf4j
public class DataSourceContextHolder {

 /**
  * 線程本地變量
  */
 private static final ThreadLocal<String> DATASOURCE_KEY = new ThreadLocal<>();

 /**
  * 配置的所有數(shù)據(jù)源的 Key 值
  */
 public static Set<Object> ALL_DATASOURCE_KEY = new HashSet<>();

 /**
  * 設(shè)置當(dāng)前線程的數(shù)據(jù)源的 Key
  *
  * @param dataSourceKey 數(shù)據(jù)源的 Key 值
  */
 public static void setDataSourceKey(String dataSourceKey) {
  if (ALL_DATASOURCE_KEY.contains(dataSourceKey)) {
   DATASOURCE_KEY.set(dataSourceKey);
  } else {
   log.warn("the datasource [{}] does not exist", dataSourceKey);
  }
 }

 /**
  * 獲取當(dāng)前線程的數(shù)據(jù)源的 Key 值
  *
  * @return 數(shù)據(jù)源的 Key 值
  */
 public static String getDataSourceKey() {
  return DATASOURCE_KEY.get();
 }

 /**
  * 移除當(dāng)前線程持有的數(shù)據(jù)源的 Key 值
  */
 public static void clear() {
  DATASOURCE_KEY.remove();
 }
}

2. MultipleDataSource

重寫其 AbstractRoutingDataSource 的 determineCurrentLookupKey() 方法,代碼如下:

package cn.tzh.mybatis.config;

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

/**
 * @author tzh
 * @date 2021/1/4 11:44
 */
public class MultipleDataSource extends AbstractRoutingDataSource {

 /**
  * 返回當(dāng)前線程是有的數(shù)據(jù)源的 Key
  *
  * @return dataSourceKey
  */
 @Override
 protected Object determineCurrentLookupKey() {
  return DataSourceContextHolder.getDataSourceKey();
 }
}

3. DataSourceAspect切面

使用 Spring AOP 功能,定義一個(gè)切面,用于設(shè)置當(dāng)前需要使用的數(shù)據(jù)源,代碼如下:

package cn.tzh.mybatis.config;

import lombok.extern.log4j.Log4j2;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * @author tzh
 * @date 2021/1/4 11:46
 */
@Aspect
@Component
@Log4j2
public class DataSourceAspect {

 @Before("@annotation(cn.tzh.mybatis.config.TargetDataSource)")
 public void before(JoinPoint joinPoint) {
  MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
  Method method = methodSignature.getMethod();
  if (method.isAnnotationPresent(TargetDataSource.class)) {
   TargetDataSource targetDataSource = method.getAnnotation(TargetDataSource.class);
   DataSourceContextHolder.setDataSourceKey(targetDataSource.value());
   log.info("set the datasource of the current thread to [{}]", targetDataSource.value());
  } else if (joinPoint.getTarget().getClass().isAnnotationPresent(TargetDataSource.class)) {
   TargetDataSource targetDataSource = joinPoint.getTarget().getClass().getAnnotation(TargetDataSource.class);
   DataSourceContextHolder.setDataSourceKey(targetDataSource.value());
   log.info("set the datasource of the current thread to [{}]", targetDataSource.value());
  }
 }

 @After("@annotation(cn.tzh.mybatis.config.TargetDataSource)")
 public void after() {
  DataSourceContextHolder.clear();
  log.info("clear the datasource of the current thread");
 }
}

4. DruidConfig

Druid 配置類,代碼如下:

package cn.tzh.mybatis.config;

import com.alibaba.druid.support.spring.stat.DruidStatInterceptor;
import org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author tzh
 * @date 2021/1/4 11:49
 */
@Configuration
public class DruidConfig {
 

 @Bean(value = "druid-stat-interceptor")
 public DruidStatInterceptor druidStatInterceptor() {
  return new DruidStatInterceptor();
 }

 @Bean
 public BeanNameAutoProxyCreator beanNameAutoProxyCreator() {
  BeanNameAutoProxyCreator beanNameAutoProxyCreator = new BeanNameAutoProxyCreator();
  beanNameAutoProxyCreator.setProxyTargetClass(true);
  // 設(shè)置要監(jiān)控的bean的id
  beanNameAutoProxyCreator.setInterceptorNames("druid-stat-interceptor");
  return beanNameAutoProxyCreator;
 }
}

5. MultipleDataSourceConfig

MyBatis 的配置類,配置了 2 個(gè)數(shù)據(jù)源,代碼如下:

package cn.tzh.mybatis.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import org.apache.ibatis.mapping.DatabaseIdProvider;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.scripting.LanguageDriver;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.type.TypeHandler;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.boot.autoconfigure.ConfigurationCustomizer;
import org.mybatis.spring.boot.autoconfigure.MybatisProperties;
import org.mybatis.spring.boot.autoconfigure.SpringBootVFS;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ResourceLoader;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import javax.sql.DataSource;
import java.beans.FeatureDescriptor;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author tzh
 * @projectName code-demo
 * @title MultipleDataSourceConfig
 * @description
 * @date 2021/1/4 13:43
 */
@Configuration
@EnableConfigurationProperties({MybatisProperties.class})
public class MultipleDataSourceConfig {


 private final MybatisProperties properties;
 private final Interceptor[] interceptors;
 private final TypeHandler[] typeHandlers;
 private final LanguageDriver[] languageDrivers;
 private final ResourceLoader resourceLoader;
 private final DatabaseIdProvider databaseIdProvider;
 private final List<ConfigurationCustomizer> configurationCustomizers;

 public MultipleDataSourceConfig(MybatisProperties properties, ObjectProvider<Interceptor[]> interceptorsProvider, ObjectProvider<TypeHandler[]> typeHandlersProvider, ObjectProvider<LanguageDriver[]> languageDriversProvider, ResourceLoader resourceLoader, ObjectProvider<DatabaseIdProvider> databaseIdProvider, ObjectProvider<List<ConfigurationCustomizer>> configurationCustomizersProvider) {
  this.properties = properties;
  this.interceptors = (Interceptor[]) interceptorsProvider.getIfAvailable();
  this.typeHandlers = (TypeHandler[]) typeHandlersProvider.getIfAvailable();
  this.languageDrivers = (LanguageDriver[]) languageDriversProvider.getIfAvailable();
  this.resourceLoader = resourceLoader;
  this.databaseIdProvider = (DatabaseIdProvider) databaseIdProvider.getIfAvailable();
  this.configurationCustomizers = (List) configurationCustomizersProvider.getIfAvailable();
 }


 @Bean(name = "master", initMethod = "init", destroyMethod = "close")
 @ConfigurationProperties(prefix = "spring.datasource.druid.master")
 public DruidDataSource master() {
  return DruidDataSourceBuilder.create().build();
 }

 @Bean(name = "slave", initMethod = "init", destroyMethod = "close")
 @ConfigurationProperties(prefix = "spring.datasource.druid.slave")
 public DruidDataSource slave() {
  return DruidDataSourceBuilder.create().build();
 }

 @Bean(name = "dynamicDataSource")
 public DataSource dynamicDataSource() {
  MultipleDataSource dynamicRoutingDataSource = new MultipleDataSource();

  Map<Object, Object> dataSources = new HashMap<>();
  dataSources.put("master", master());
  dataSources.put("slave", slave());

  dynamicRoutingDataSource.setDefaultTargetDataSource(master());
  dynamicRoutingDataSource.setTargetDataSources(dataSources);

  DataSourceContextHolder.ALL_DATASOURCE_KEY.addAll(dataSources.keySet());

  return dynamicRoutingDataSource;
 }

 @Bean
 public SqlSessionFactory sqlSessionFactory() throws Exception {
  SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
  factory.setDataSource(dynamicDataSource());
  factory.setVfs(SpringBootVFS.class);
  if (StringUtils.hasText(this.properties.getConfigLocation())) {
   factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation()));
  }

  this.applyConfiguration(factory);
  if (this.properties.getConfigurationProperties() != null) {
   factory.setConfigurationProperties(this.properties.getConfigurationProperties());
  }

  if (!ObjectUtils.isEmpty(this.interceptors)) {
   factory.setPlugins(this.interceptors);
  }

  if (this.databaseIdProvider != null) {
   factory.setDatabaseIdProvider(this.databaseIdProvider);
  }

  if (StringUtils.hasLength(this.properties.getTypeAliasesPackage())) {
   factory.setTypeAliasesPackage(this.properties.getTypeAliasesPackage());
  }

  if (this.properties.getTypeAliasesSuperType() != null) {
   factory.setTypeAliasesSuperType(this.properties.getTypeAliasesSuperType());
  }

  if (StringUtils.hasLength(this.properties.getTypeHandlersPackage())) {
   factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage());
  }

  if (!ObjectUtils.isEmpty(this.typeHandlers)) {
   factory.setTypeHandlers(this.typeHandlers);
  }

  if (!ObjectUtils.isEmpty(this.properties.resolveMapperLocations())) {
   factory.setMapperLocations(this.properties.resolveMapperLocations());
  }

  Set<String> factoryPropertyNames = (Set) Stream.of((new BeanWrapperImpl(SqlSessionFactoryBean.class)).getPropertyDescriptors()).map(FeatureDescriptor::getName).collect(Collectors.toSet());
  Class<? extends LanguageDriver> defaultLanguageDriver = this.properties.getDefaultScriptingLanguageDriver();
  if (factoryPropertyNames.contains("scriptingLanguageDrivers") && !ObjectUtils.isEmpty(this.languageDrivers)) {
   factory.setScriptingLanguageDrivers(this.languageDrivers);
   if (defaultLanguageDriver == null && this.languageDrivers.length == 1) {
    defaultLanguageDriver = this.languageDrivers[0].getClass();
   }
  }

  if (factoryPropertyNames.contains("defaultScriptingLanguageDriver")) {
   factory.setDefaultScriptingLanguageDriver(defaultLanguageDriver);
  }

  return factory.getObject();
 }

 private void applyConfiguration(SqlSessionFactoryBean factory) {
  org.apache.ibatis.session.Configuration configuration = this.properties.getConfiguration();
  if (configuration == null && !StringUtils.hasText(this.properties.getConfigLocation())) {
   configuration = new org.apache.ibatis.session.Configuration();
  }

  if (configuration != null && !CollectionUtils.isEmpty(this.configurationCustomizers)) {
   Iterator var3 = this.configurationCustomizers.iterator();

   while (var3.hasNext()) {
    ConfigurationCustomizer customizer = (ConfigurationCustomizer) var3.next();
    customizer.customize(configuration);
   }
  }

  factory.setConfiguration(configuration);
 }

 @Bean
 public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
  ExecutorType executorType = this.properties.getExecutorType();
  return executorType != null ? new SqlSessionTemplate(sqlSessionFactory, executorType) : new SqlSessionTemplate(sqlSessionFactory);
 }

 @Bean
 public PlatformTransactionManager masterTransactionManager() {
  // 配置事務(wù)管理器
  return new DataSourceTransactionManager(dynamicDataSource());
 }
}

6. 添加配置

server:
 port: 9092
 servlet:
 context-path: /mybatis-springboot-demo
 tomcat:
 accept-count: 200
 min-spare-threads: 200
spring:
 application:
 name: mybatis-springboot-demo
 profiles:
 active: test
 servlet:
 multipart:
  max-file-size: 100MB
  max-request-size: 100MB
 datasource:
 type: com.alibaba.druid.pool.DruidDataSource
 druid:
  master:
  driver-class-name: com.mysql.cj.jdbc.Driver
  url: jdbc:mysql://127.0.0.1:3306/mybatis-demo
  username: root
  password: root
  initial-size: 5 # 初始化時(shí)建立物理連接的個(gè)數(shù)
  min-idle: 20 # 最小連接池?cái)?shù)量
  max-active: 20 # 最大連接池?cái)?shù)量
  slave:
  driver-class-name: com.mysql.cj.jdbc.Driver
  url: jdbc:mysql://127.0.0.1:3306/mybatis-demo1
  username: root
  password: root
  initial-size: 5 # 初始化時(shí)建立物理連接的個(gè)數(shù)
  min-idle: 20 # 最小連接池?cái)?shù)量
  max-active: 20 # 最大連接池?cái)?shù)量
mybatis:
 type-aliases-package: cn.tzh.mybatis.entity
 mapper-locations: classpath:cn/tzh/mybatis/mapper/*.xml
 config-location: classpath:mybatis-config.xml
pagehelper:
 helper-dialect: mysql
 reasonable: true # 分頁合理化參數(shù)
 offset-as-page-num: true # 將 RowBounds 中的 offset 參數(shù)當(dāng)成 pageNum 使用
 supportMethodsArguments: true # 支持通過 Mapper 接口參數(shù)來傳遞分頁參數(shù)

其中分別定義了 master 和 slave 數(shù)據(jù)源的相關(guān)配置

這樣一來,在 DataSourceAspect 切面中根據(jù)自定義注解,設(shè)置 DataSourceContextHolder 當(dāng)前線程所使用的數(shù)據(jù)源的 Key 值,MultipleDataSource 動(dòng)態(tài)數(shù)據(jù)源則會(huì)根據(jù)該值設(shè)置需要使用的數(shù)據(jù)源,完成了動(dòng)態(tài)數(shù)據(jù)源的切換

7. 使用示例

在 Mapper 接口上面添加自定義注解 @TargetDataSource,如下:

package cn.tzh.mybatis.mapper;

import cn.tzh.mybatis.config.TargetDataSource;
import cn.tzh.mybatis.entity.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

/**
 * @author tzh
 * @date 2020/12/28 14:29
 */
@Mapper
public interface UserMapper {

 User selectUserOne(@Param("id") Long id);

 @TargetDataSource("slave")
 User selectUserTwo(@Param("id") Long id);
}

 總結(jié)

上面就如何配置動(dòng)態(tài)數(shù)據(jù)源的實(shí)現(xiàn)方式僅提供一種思路,其中關(guān)于多事務(wù)方面并沒有實(shí)現(xiàn),采用 Spring 提供的事務(wù)管理器,如果同一個(gè)方法中使用了多個(gè)數(shù)據(jù)源,并不支持多事務(wù)的,需要自己去實(shí)現(xiàn)(筆者能力有限),可以整合JAT組件,參考:SpringBoot2 整合JTA組件多數(shù)據(jù)源事務(wù)管理

分布式事務(wù)解決方案推薦使用 Seata 分布式服務(wù)框架

到此這篇關(guān)于SpringBoot配置數(shù)據(jù)庫密碼加密的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)SpringBoot 數(shù)據(jù)庫密碼加密內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Spring MVC+MyBatis+MySQL實(shí)現(xiàn)分頁功能實(shí)例

    Spring MVC+MyBatis+MySQL實(shí)現(xiàn)分頁功能實(shí)例

    分頁功能是我們?nèi)粘i_發(fā)中經(jīng)常會(huì)遇到的,下面這篇文章主要給大家介紹了Spring MVC+MyBatis+MySQL實(shí)現(xiàn)分頁功能的相關(guān)資料,文中介紹的非常詳細(xì),對(duì)大家具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起看看吧。
    2017-06-06
  • 最簡單的MyBatis Plus的多表聯(lián)接、分頁查詢實(shí)現(xiàn)方法

    最簡單的MyBatis Plus的多表聯(lián)接、分頁查詢實(shí)現(xiàn)方法

    這篇文章主要介紹了最簡單的MyBatis Plus的多表聯(lián)接、分頁查詢實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11
  • idea編譯器工程out目錄修改方法步驟

    idea編譯器工程out目錄修改方法步驟

    多個(gè)工程在一個(gè)文件夾下,有時(shí)會(huì)變?yōu)樗械墓こ讨挥靡粋€(gè)out文件夾,這時(shí)運(yùn)行會(huì)出錯(cuò),所以本文就來介紹一下out目錄修改,具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-09-09
  • 解決java.lang.ClassCastException的java類型轉(zhuǎn)換異常的問題

    解決java.lang.ClassCastException的java類型轉(zhuǎn)換異常的問題

    這篇文章主要介紹了解決java.lang.ClassCastException的java類型轉(zhuǎn)換異常的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-09-09
  • spring boot的maven配置依賴詳解

    spring boot的maven配置依賴詳解

    本篇文章主要介紹了spring boot的maven配置依賴詳解,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-11-11
  • IntelliJ?IDEA?2024.2?發(fā)布新功能介紹Spring?Data?JPA即時(shí)查詢、自動(dòng)補(bǔ)全cron表達(dá)式

    IntelliJ?IDEA?2024.2?發(fā)布新功能介紹Spring?Data?JPA即時(shí)查詢、自動(dòng)補(bǔ)全cro

    在2024.2?Ultimate版本中,對(duì)?Spring?Data?JPA?的支持做了增強(qiáng),新功能允許您在不運(yùn)行應(yīng)用程序和分析日志文件的情況下查看方法將生成的查詢,下面就來一起看看這個(gè)版本中推出的幾個(gè)強(qiáng)大新特性
    2024-08-08
  • Java Set集合及其子類HashSet與LinkedHashSet詳解

    Java Set集合及其子類HashSet與LinkedHashSet詳解

    這篇文章主要介紹了Java Set集合及其子類HashSet與LinkedHashSet詳解,文章通過Set集合存儲(chǔ)原理展開文章主題相關(guān)介紹,感興趣的小伙伴可以參考一下
    2022-06-06
  • 淺談JDK9的特性之JVM的xlog

    淺談JDK9的特性之JVM的xlog

    在java程序中,我們通過日志來定位和發(fā)現(xiàn)項(xiàng)目中可能出現(xiàn)的問題。在現(xiàn)代java項(xiàng)目中,我們使用log4j或者slf4j,Logback等日志記錄框架來處理日志問題。本文將介紹JDK9的特性之JVM的xlog。
    2021-06-06
  • java中把漢字轉(zhuǎn)換成簡拼的實(shí)現(xiàn)代碼

    java中把漢字轉(zhuǎn)換成簡拼的實(shí)現(xiàn)代碼

    本篇文章是對(duì)在java中把漢字轉(zhuǎn)換成簡拼的實(shí)現(xiàn)方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05
  • Java實(shí)現(xiàn)synchronized鎖同步機(jī)制

    Java實(shí)現(xiàn)synchronized鎖同步機(jī)制

    synchronized是java內(nèi)置的同步鎖實(shí)現(xiàn),本文就詳細(xì)的介紹一下Java實(shí)現(xiàn)synchronized鎖同步機(jī)制,具有一定的參考價(jià)值,感興趣的可以了解一下
    2021-11-11

最新評(píng)論

横峰县| 澎湖县| 鹤庆县| 安达市| 高州市| 纳雍县| 澄迈县| 蓬莱市| 化德县| 陇南市| 那曲县| 营山县| 肥城市| 沁阳市| 晋江市| 石柱| 伊春市| 平利县| 武陟县| 历史| 石林| 玛曲县| 章丘市| 庆阳市| 德安县| 遵义县| 阿尔山市| 黄龙县| 沈阳市| 大埔县| 平湖市| 琼海市| 乌鲁木齐市| 惠州市| 张掖市| 泰和县| 修文县| 中宁县| 台北市| 朔州市| 苏州市|