ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

springboot2.1.3+spring-session2.1.4分库处理

2019-06-25 23:01:11  阅读:221  来源: 互联网

标签:分库 springboot2.1 spring private session springframework org import String


使用spring session框架来统一管理session,该框架支持jdbc、redis存储,使用非常简单,可以去官网查看文档一步步接入即可,
官网文档如下:https://docs.spring.io/spring-session/docs/current/reference/html5/,

不过,我使用的场景官网没有提供方法给予解决,最后,本人只能重写了它的部分源码,来实现分库管理session,好了,上代码。

 

pom.xml

<dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session-core</artifactId>
    <version>2.1.4.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session-jdbc</artifactId>
    <version>2.1.4.RELEASE</version>
</dependency>
<!-- 
<dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session-redis</artifactId>
    <version>2.1.4.RELEASE</version>
</dependency>
-->
<dependency>
    <groupId>com.zaxxer</groupId>
    <artifactId>HikariCP</artifactId>
    <version>3.2.0</version>
</dependency>

 

application.properties

# spring-session setting, timeout: 2 years
spring.session.timeout.setting=63072000

# sharding number, CONFIG_SHARDING_NUM 环境变量名
mydb.server.sharding.num=${CONFIG_SHARDING_NUM:4}

# global setting dbs parameter
mysql.global.pools.MinimumIdle=1
mysql.global.pools.MaximumPoolSize=20
mysql.global.pools.IdleTimeout=600000
mysql.global.pools.MaxLifetime=1800000

# 这里配置分库信息,这里只是demo,本人配置了4个主库,至于分库分表不在本博客中体现。
# master0
sharding.jdbc.datasource.mainshard0.type=com.zaxxer.hikari.HikariDataSource
sharding.jdbc.datasource.mainshard0.driver-class-name=org.mariadb.jdbc.Driver
sharding.jdbc.datasource.mainshard0.jdbc-url=jdbc:mysql://127.0.0.1:3306/demo?useUnicode=true&characterEncoding-utf8&allowMutiQueries=true
sharding.jdbc.datasource.mainshard0.username=xxxx
sharding.jdbc.datasource.mainshard0.password=xxxxxx

# master1
sharding.jdbc.datasource.mainshard1.type=com.zaxxer.hikari.HikariDataSource
sharding.jdbc.datasource.mainshard1.driver-class-name=org.mariadb.jdbc.Driver
sharding.jdbc.datasource.mainshard1.jdbc-url=jdbc:mysql://127.0.0.1:3307/demo?useUnicode=true&characterEncoding-utf8&allowMutiQueries=true
sharding.jdbc.datasource.mainshard1.username=xxxx
sharding.jdbc.datasource.mainshard1.password=xxxxxx

# master2
sharding.jdbc.datasource.mainshard2.type=com.zaxxer.hikari.HikariDataSource
sharding.jdbc.datasource.mainshard2.driver-class-name=org.mariadb.jdbc.Driver
sharding.jdbc.datasource.mainshard2.jdbc-url=jdbc:mysql://127.0.0.1:3308/demo?useUnicode=true&characterEncoding-utf8&allowMutiQueries=true
sharding.jdbc.datasource.mainshard2.username=xxxx
sharding.jdbc.datasource.mainshard2.password=xxxxxx

# master3
sharding.jdbc.datasource.mainshard3.type=com.zaxxer.hikari.HikariDataSource
sharding.jdbc.datasource.mainshard3.driver-class-name=org.mariadb.jdbc.Driver
sharding.jdbc.datasource.mainshard3.jdbc-url=jdbc:mysql://127.0.0.1:3309/demo?useUnicode=true&characterEncoding-utf8&allowMutiQueries=true
sharding.jdbc.datasource.mainshard3.username=xxxx
sharding.jdbc.datasource.mainshard3.password=xxxxxx

 

重写第一个类(源码文件是JdbcHttpSessionConfiguration.java,可以去官网下载),本人重写如下:

package com.szl.demo.spring.session.common.datasource.sessionConfig;

import java.util.HashMap;
import java.util.Map;
import javax.sql.DataSource;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.EmbeddedValueResolverAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportAware;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.support.GenericConversionService;
import org.springframework.core.serializer.support.DeserializingConverter;
import org.springframework.core.serializer.support.SerializingConverter;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.support.JdbcUtils;
import org.springframework.jdbc.support.MetaDataAccessException;
import org.springframework.jdbc.support.lob.DefaultLobHandler;
import org.springframework.jdbc.support.lob.LobHandler;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.session.MapSession;
import org.springframework.session.config.annotation.web.http.SpringHttpSessionConfiguration;
import org.springframework.session.jdbc.JdbcOperationsSessionRepository;
import org.springframework.session.jdbc.config.annotation.SpringSessionDataSource;
import org.springframework.session.web.http.SessionRepositoryFilter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.util.StringUtils;
import org.springframework.util.StringValueResolver;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;

/**
 *  @author Jimmy Shan
 *  @date 2019-06-25
 *  @desc 重写jdbc session配置类
 */
@Configuration
@EnableScheduling
public class CustomizedJdbcHttpSessionConfiguration extends SpringHttpSessionConfiguration
        implements BeanClassLoaderAware, EmbeddedValueResolverAware, ImportAware,
        SchedulingConfigurer {

  static final String DEFAULT_CLEANUP_CRON = "0 0 0/1 * * *";
  private String tableName = JdbcOperationsSessionRepository.DEFAULT_TABLE_NAME;
  private String cleanupCron = DEFAULT_CLEANUP_CRON;
  private LobHandler lobHandler;
  private ConversionService springSessionConversionService;
  private ConversionService conversionService;
  private ClassLoader classLoader;
  private StringValueResolver embeddedValueResolver;
  
  //--------------Modify by Jimmy Shan, the date is 2019-06-25 start------//
  @Value("${mydb.server.sharding.num}")
  private String shardingNum;
  @Autowired
  private Environment env;
  private Map<Integer, JdbcTemplate> myJdbcTemplateMap = new HashMap<>();
  private Map<Integer, PlatformTransactionManager> myDataSourceTransactionMap = new HashMap<>();
  private DataSource dataSource;
  // 时间设置,间隔时间为30秒
  private Integer maxInactiveIntervalInSeconds;
  //--------------Modify by Jimmy Shan, the date is 2019-06-25 end-------//
    
    
    /**
     * @desc 创建数据源,手动创建,为了后面的分库分表
     */
    private DataSource convertDataSource(int num) {
        HikariConfig hkConfig = new HikariConfig();
        hkConfig.setDriverClassName("org.mariadb,jdbc.Driver");
        hkConfig.setMinimumIdle(env.getProperty("mysql.global.pools.MinimumIdle") == null ? 5 : env.getProperty("mysql.global.pools.MinimumIdle")));
        hkConfig.setMaximumPoolSize(env.getProperty("mysql.global.pools.MaximumPoolSize") == null ? 20 : env.getProperty("mysql.global.pools.MaximumPoolSize")));
        hkConfig.setIdleTimeout(env.getProperty("mysql.global.pools.IdleTimeout") == null ? 600000 : Integer.parseInt(env.getProperty("mysql.global.pools.IdleTimeout")));
        hkConfig.setMaxLifetime(env.getProperty("mysql.global.pools.MaxLifetime") == null ? 1800000 : Integer.parseInt(env.getProperty("mysql.global.pools.MaxLifetime")));
        hkConfig.setJdbcUrl(env.getProperty("sharding.jdbc.datasource.mainshard" + num + ".jdbc-url"));
        hkConfig.setUsername(env.getProperty("sharding.jdbc.datasource.mainshard" + num + ".username"));
        hkConfig.setPassword(env.getProperty("sharding.jdbc.datasource.mainshard" + num + ".password"));
        HikariDataSource ds = new HikariDataSource(hkConfig);
        return ds;
    }
    
  /**
   * @desc 重写了部分逻辑
   */
    @Bean
    public CustomizedJdbcOperationsSessionRepository sessionRepository() {
      for (int i = 0; i < Integer.parseInt(shardingNum); i++) {
          DataSource ds = convertDataSource(i);
          myJdbcTemplateMap.put(i, new JdbcTemplate(ds));
          myDataSourceTransactionMap.put(i, new DataSourceTransactionManager(ds));
      }
      
      this.dataSource = myJdbcTemplateMap.get(0).getDataSource();
        CustomizedJdbcOperationsSessionRepository sessionRepository = 
            new JdbcOperationsSessionRepository(myJdbcTemplateMap, myDataSourceTransactionMap);
        if (StringUtils.hasText(this.tableName)) {
            sessionRepository.setTableName(this.tableName);
        }
        
        this.setMaxInactiveIntervalInSeconds(Integer.parseInt(env.getProperty("spring.session.timeout.setting")));
        sessionRepository.setDefaultMaxInactiveInterval(this.maxInactiveIntervalInSeconds);
        if (this.lobHandler != null) {
             sessionRepository.setLobHandler(this.lobHandler);
        }    else if (requiresTemporaryLob(this.dataSource)) {
             DefaultLobHandler lobHandler = new DefaultLobHandler();
             lobHandler.setCreateTemporaryLob(true);
             sessionRepository.setLobHandler(lobHandler);
        }
        if (this.springSessionConversionService != null) {
             sessionRepository.setConversionService(this.springSessionConversionService);
        }    else if (this.conversionService != null) {
             sessionRepository.setConversionService(this.conversionService);
        }    else {
             sessionRepository.setConversionService(createConversionServiceWithBeanClassLoader());
        }
        return sessionRepository;
    }

    private static boolean requiresTemporaryLob(DataSource dataSource) {
        try {
            String productName = JdbcUtils.extractDatabaseMetaData(dataSource,
                    "getDatabaseProductName");
            return "Oracle".equalsIgnoreCase(JdbcUtils.commonDatabaseName(productName));
        }
        catch (MetaDataAccessException ex) {
            return false;
        }
    }

    public void setMaxInactiveIntervalInSeconds(Integer maxInactiveIntervalInSeconds) {
        this.maxInactiveIntervalInSeconds = maxInactiveIntervalInSeconds;
    }

    public void setTableName(String tableName) {
        this.tableName = tableName;
    }

    public void setCleanupCron(String cleanupCron) {
        this.cleanupCron = cleanupCron;
    }

    @Autowired(required = false)
    @Qualifier("springSessionLobHandler")
    public void setLobHandler(LobHandler lobHandler) {
        this.lobHandler = lobHandler;
    }

    @Autowired(required = false)
    @Qualifier("springSessionConversionService")
    public void setSpringSessionConversionService(ConversionService conversionService) {
        this.springSessionConversionService = conversionService;
    }

    @Autowired(required = false)
    @Qualifier("conversionService")
    public void setConversionService(ConversionService conversionService) {
        this.conversionService = conversionService;
    }

    @Override
    public void setBeanClassLoader(ClassLoader classLoader) {
        this.classLoader = classLoader;
    }

    @Override
    public void setEmbeddedValueResolver(StringValueResolver resolver) {
        this.embeddedValueResolver = resolver;
    }

    @Override
    public void setImportMetadata(AnnotationMetadata importMetadata) {
        Map<String, Object> attributeMap = importMetadata
                .getAnnotationAttributes(EnableJdbcHttpSession.class.getName());
        AnnotationAttributes attributes = AnnotationAttributes.fromMap(attributeMap);
        this.maxInactiveIntervalInSeconds = attributes
                .getNumber("maxInactiveIntervalInSeconds");
        String tableNameValue = attributes.getString("tableName");
        if (StringUtils.hasText(tableNameValue)) {
            this.tableName = this.embeddedValueResolver
                    .resolveStringValue(tableNameValue);
        }
        String cleanupCron = attributes.getString("cleanupCron");
        if (StringUtils.hasText(cleanupCron)) {
            this.cleanupCron = cleanupCron;
        }
    }

    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        taskRegistrar.addCronTask(() -> sessionRepository().cleanUpExpiredSessions(),
                this.cleanupCron);
    }

    private GenericConversionService createConversionServiceWithBeanClassLoader() {
        GenericConversionService conversionService = new GenericConversionService();
        conversionService.addConverter(Object.class, byte[].class,
                new SerializingConverter());
        conversionService.addConverter(byte[].class, Object.class,
                new DeserializingConverter(this.classLoader));
        return conversionService;
    }
}

 

 

重写第二个类(源码文件是JdbcOperationsSessionRepository.java,可以去官网下载),本人重写如下:

package com.szl.demo.spring.session.common.datasource.sessionConfig;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.support.GenericConversionService;
import org.springframework.core.serializer.support.DeserializingConverter;
import org.springframework.core.serializer.support.SerializingConverter;
import org.springframework.dao.DataAccessException;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
import org.springframework.jdbc.core.JdbcOperations;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.ResultSetExtractor;
import org.springframework.jdbc.support.lob.DefaultLobHandler;
import org.springframework.jdbc.support.lob.LobHandler;
import org.springframework.session.FindByIndexNameSessionRepository;
import org.springframework.session.MapSession;
import org.springframework.session.Session;
import org.springframework.session.jdbc.JdbcOperationsSessionRepository;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionException;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionOperations;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

/**
 * @author Jimmy Shan
 * @date 2019-06-25
 * @desc 重写jdbc session类
 */
public class CustomizedJdbcOperationsSessionRepository implements
        FindByIndexNameSessionRepository<JdbcOperationsSessionRepository.JdbcSession> {
        
    public static final String DEFAULT_TABLE_NAME = "SPRING_SESSION";
    private static final String SPRING_SECURITY_CONTEXT = "SPRING_SECURITY_CONTEXT";
    private static final String CREATE_SESSION_QUERY =
            "INSERT INTO %TABLE_NAME%(PRIMARY_ID, SESSION_ID, CREATION_TIME, LAST_ACCESS_TIME, MAX_INACTIVE_INTERVAL, EXPIRY_TIME, PRINCIPAL_NAME) " +
                    "VALUES (?, ?, ?, ?, ?, ?, ?)";
    private static final String CREATE_SESSION_ATTRIBUTE_QUERY =
            "INSERT INTO %TABLE_NAME%_ATTRIBUTES(SESSION_PRIMARY_ID, ATTRIBUTE_NAME, ATTRIBUTE_BYTES) " +
                    "SELECT PRIMARY_ID, ?, ? " +
                    "FROM %TABLE_NAME% " +
                    "WHERE SESSION_ID = ?";
    private static final String GET_SESSION_QUERY =
            "SELECT S.PRIMARY_ID, S.SESSION_ID, S.CREATION_TIME, S.LAST_ACCESS_TIME, S.MAX_INACTIVE_INTERVAL, SA.ATTRIBUTE_NAME, SA.ATTRIBUTE_BYTES " +
                    "FROM %TABLE_NAME% S " +
                    "LEFT OUTER JOIN %TABLE_NAME%_ATTRIBUTES SA ON S.PRIMARY_ID = SA.SESSION_PRIMARY_ID " +
                    "WHERE S.SESSION_ID = ?";
    private static final String UPDATE_SESSION_QUERY =
            "UPDATE %TABLE_NAME% SET SESSION_ID = ?, LAST_ACCESS_TIME = ?, MAX_INACTIVE_INTERVAL = ?, EXPIRY_TIME = ?, PRINCIPAL_NAME = ? " +
                    "WHERE PRIMARY_ID = ?";
    private static final String UPDATE_SESSION_ATTRIBUTE_QUERY =
            "UPDATE %TABLE_NAME%_ATTRIBUTES SET ATTRIBUTE_BYTES = ? " +
                    "WHERE SESSION_PRIMARY_ID = ? " +
                    "AND ATTRIBUTE_NAME = ?";
    private static final String DELETE_SESSION_ATTRIBUTE_QUERY =
            "DELETE FROM %TABLE_NAME%_ATTRIBUTES " +
                    "WHERE SESSION_PRIMARY_ID = ? " +
                    "AND ATTRIBUTE_NAME = ?";
    private static final String DELETE_SESSION_QUERY =
            "DELETE FROM %TABLE_NAME% " +
                    "WHERE SESSION_ID = ?";
    private static final String LIST_SESSIONS_BY_PRINCIPAL_NAME_QUERY =
            "SELECT S.PRIMARY_ID, S.SESSION_ID, S.CREATION_TIME, S.LAST_ACCESS_TIME, S.MAX_INACTIVE_INTERVAL, SA.ATTRIBUTE_NAME, SA.ATTRIBUTE_BYTES " +
                    "FROM %TABLE_NAME% S " +
                    "LEFT OUTER JOIN %TABLE_NAME%_ATTRIBUTES SA ON S.PRIMARY_ID = SA.SESSION_PRIMARY_ID " +
                    "WHERE S.PRINCIPAL_NAME = ?";
    private static final String DELETE_SESSIONS_BY_EXPIRY_TIME_QUERY =
            "DELETE FROM %TABLE_NAME% " +
                    "WHERE EXPIRY_TIME < ?";

    private static final Log logger = LogFactory.getLog(JdbcOperationsSessionRepository.class);
    private static final PrincipalNameResolver PRINCIPAL_NAME_RESOLVER = new PrincipalNameResolver();
    private final ResultSetExtractor<List<JdbcSession>> extractor = new SessionResultSetExtractor();
    private String tableName = DEFAULT_TABLE_NAME;
    private String createSessionQuery;
    private String createSessionAttributeQuery;
    private String getSessionQuery;
    private String updateSessionQuery;
    private String updateSessionAttributeQuery;
    private String deleteSessionAttributeQuery;
    private String deleteSessionQuery;
    private String listSessionsByPrincipalNameQuery;
    private String deleteSessionsByExpiryTimeQuery;
    private Integer defaultMaxInactiveInterval;
    private ConversionService conversionService;
  private LobHandler lobHandler = new DefaultLobHandler();
    
  //--------------Modify by Jimmy Shan, the date is 2019-06-25 start--------------//
  private Map<Integer, JdbcOperations> jdbcOperationMaps = new Hash<>();
  private Map<Integer, TransactionOperations> transOperationMaps = new Hash<>();
  @Value("{mydb.server.sharding.num}")
  private String shardingNum;
  //--------------Modify by Jimmy Shan, the date is 2019-06-25 end----------------//
    
  /**
   * @desc 重写这个方法
   */
    public CustomizedJdbcOperationsSessionRepository(Map<Integer, JdbcTemplate> myJdbcTemplateMap,
            Map<Integer, PlatformTransactionManager> myDataSourceTransactionMap) {
            if (myJdbcTemplateMap == null || myJdbcTemplateMap.isEmpty()) {
                Assert.notNull(myJdbcTemplateMap, "myJdbcTemplateMap must not be null");
            }
            if (myDataSourceTransactionMap == null || myDataSourceTransactionMap.isEmpty()) {
                Assert.notNull(myDataSourceTransactionMap, "myDataSourceTransactionMap must not be null");
            }
            jdbcOperationMaps.putAll(myJdbcTemplateMap);
            this.conversionService = createDefaultConversionService();
            prepareQueries();
            Set<Integer> setKey = myDataSourceTransactionMap.keySet();
            for (Iterator ir = setKey.iterator(); ir.hasNext(); ) {
                Integer key = (Integer) ir.next();
                TransactionOperations transOperations = createTransactionTemplate(myDataSourceTransactionMap.get(key));
                transOperationMaps.put(key, transOperations);
            }        
    }
  
    public void setTableName(String tableName) {
        Assert.hasText(tableName, "Table name must not be empty");
        this.tableName = tableName.trim();
        prepareQueries();
    }
  
    public void setCreateSessionQuery(String createSessionQuery) {
        Assert.hasText(createSessionQuery, "Query must not be empty");
        this.createSessionQuery = createSessionQuery;
    }
  
    public void setCreateSessionAttributeQuery(String createSessionAttributeQuery) {
        Assert.hasText(createSessionAttributeQuery, "Query must not be empty");
        this.createSessionAttributeQuery = createSessionAttributeQuery;
    }
  
    public void setGetSessionQuery(String getSessionQuery) {
        Assert.hasText(getSessionQuery, "Query must not be empty");
        this.getSessionQuery = getSessionQuery;
    }
  
    public void setUpdateSessionQuery(String updateSessionQuery) {
        Assert.hasText(updateSessionQuery, "Query must not be empty");
        this.updateSessionQuery = updateSessionQuery;
    }
  
    public void setUpdateSessionAttributeQuery(String updateSessionAttributeQuery) {
        Assert.hasText(updateSessionAttributeQuery, "Query must not be empty");
        this.updateSessionAttributeQuery = updateSessionAttributeQuery;
    }
  
    public void setDeleteSessionAttributeQuery(String deleteSessionAttributeQuery) {
        Assert.hasText(deleteSessionAttributeQuery, "Query must not be empty");
        this.deleteSessionAttributeQuery = deleteSessionAttributeQuery;
    }
  
    public void setDeleteSessionQuery(String deleteSessionQuery) {
        Assert.hasText(deleteSessionQuery, "Query must not be empty");
        this.deleteSessionQuery = deleteSessionQuery;
    }
  
    public void setListSessionsByPrincipalNameQuery(String listSessionsByPrincipalNameQuery) {
        Assert.hasText(listSessionsByPrincipalNameQuery, "Query must not be empty");
        this.listSessionsByPrincipalNameQuery = listSessionsByPrincipalNameQuery;
    }
  
    public void setDeleteSessionsByExpiryTimeQuery(String deleteSessionsByExpiryTimeQuery) {
        Assert.hasText(deleteSessionsByExpiryTimeQuery, "Query must not be empty");
        this.deleteSessionsByExpiryTimeQuery = deleteSessionsByExpiryTimeQuery;
    }
  
    public void setDefaultMaxInactiveInterval(Integer defaultMaxInactiveInterval) {
        this.defaultMaxInactiveInterval = defaultMaxInactiveInterval;
    }

    public void setLobHandler(LobHandler lobHandler) {
        Assert.notNull(lobHandler, "LobHandler must not be null");
        this.lobHandler = lobHandler;
    }
  
    public void setConversionService(ConversionService conversionService) {
        Assert.notNull(conversionService, "conversionService must not be null");
        this.conversionService = conversionService;
    }

    @Override
    public JdbcSession createSession() {
        JdbcSession session = new JdbcSession();
        if (this.defaultMaxInactiveInterval != null) {
            session.setMaxInactiveInterval(Duration.ofSeconds(this.defaultMaxInactiveInterval));
        }
        return session;
    }
  
  
  /**
   * @desc Modify by Jimmy Shan, the date is 2019-06-25
   *      Implementing Routing Function
   */
    @Override
    public void save(final JdbcSession session) {
      String sessionId = session.getId();
      int hashCode = Math.abs(sessionId.hashCode());
      int mod = hashCode % Integer.parseInt(shardingNum);
        if (session.isNew()) {
            this.transOperationMaps.get(mod).execute(new TransactionCallbackWithoutResult() {
                        @Override
                        protected void doInTransactionWithoutResult(TransactionStatus status) {
                            CustomizedJdbcOperationsSessionRepository.this.jdbcOperationMaps.get(mod).update(
                                    CustomizedJdbcOperationsSessionRepository.this.createSessionQuery,
                                    (ps) -> {
                                        ps.setString(1, session.primaryKey);
                                        ps.setString(2, session.getId());
                                        ps.setLong(3, session.getCreationTime().toEpochMilli());
                                        ps.setLong(4, session.getLastAccessedTime().toEpochMilli());
                                        ps.setInt(5, (int) session.getMaxInactiveInterval().getSeconds());
                                        ps.setLong(6, session.getExpiryTime().toEpochMilli());
                                        ps.setString(7, session.getPrincipalName());
                                    });
                            Set<String> attributeNames = session.getAttributeNames();
                            if (!attributeNames.isEmpty()) {
                                  insertSessionAttributes(session, new ArrayList<>(attributeNames));
                            }
                }
            });
        }    else {
            this.transOperationMaps.get(mod).execute(new TransactionCallbackWithoutResult() {
                        @Override
                        protected void doInTransactionWithoutResult(TransactionStatus status) {
                            if (session.isChanged()) {
                                    CustomizedJdbcOperationsSessionRepository.this.jdbcOperationMaps.get(mod).update(
                                            CustomizedJdbcOperationsSessionRepository.this.updateSessionQuery,
                                            (ps) -> {
                                                ps.setString(1, session.getId());
                                                ps.setLong(2, session.getLastAccessedTime().toEpochMilli());
                                                ps.setInt(3, (int) session.getMaxInactiveInterval().getSeconds());
                                                ps.setLong(4, session.getExpiryTime().toEpochMilli());
                                                ps.setString(5, session.getPrincipalName());
                                                ps.setString(6, session.primaryKey);
                                            });
                            }
                            List<String> addedAttributeNames = session.delta.entrySet().stream()
                                    .filter((entry) -> entry.getValue() == DeltaValue.ADDED)
                                    .map(Map.Entry::getKey)
                                    .collect(Collectors.toList());
                            if (!addedAttributeNames.isEmpty()) {
                                insertSessionAttributes(session, addedAttributeNames);
                            }
                            List<String> updatedAttributeNames = session.delta.entrySet().stream()
                                    .filter((entry) -> entry.getValue() == DeltaValue.UPDATED)
                                    .map(Map.Entry::getKey)
                                    .collect(Collectors.toList());
                            if (!updatedAttributeNames.isEmpty()) {
                                updateSessionAttributes(session, updatedAttributeNames);
                            }
                            List<String> removedAttributeNames = session.delta.entrySet().stream()
                                    .filter((entry) -> entry.getValue() == DeltaValue.REMOVED)
                                    .map(Map.Entry::getKey)
                                    .collect(Collectors.toList());
                            if (!removedAttributeNames.isEmpty()) {
                                  deleteSessionAttributes(session, removedAttributeNames);
                            }
                        }
            });
        }
        session.clearChangeFlags();
    }
  
  /**
   * @desc Modify by Jimmy Shan, the date is 2019-06-25
   *      Implementing Routing Function
   */
    @Override
    public JdbcSession findById(final String id) {
      String sessionId = id;
      int hashCode = Math.abs(sessionId.hashCode());
      int mod = hashCode % Integer.parseInt(shardingNum);
        final JdbcSession session = this.transOperationMaps.get(mod).execute((status) -> {
            List<JdbcSession> sessions = CustomizedJdbcOperationsSessionRepository
                                 .this.jdbcOperationMaps.get(mod).query(
                                                                     CustomizedJdbcOperationsSessionRepository.this.getSessionQuery,
                    (ps) -> ps.setString(1, id),
                    CustomizedJdbcOperationsSessionRepository.this.extractor
            );
            if (sessions.isEmpty()) {
                    return null;
            }
            return sessions.get(0);
        });
        
        if (session != null) {
            if (session.isExpired()) {
                    deleteById(id);
            }    else {
                    return session;
            }
        }
        return null;
    }
    
    /**
   * @desc Modify by Jimmy Shan, the date is 2019-06-25
   *      Implementing Routing Function
   */
    @Override
    public void deleteById(final String id) {
      String sessionId = id;
      int hashCode = Math.abs(sessionId.hashCode());
      int mod = hashCode % Integer.parseInt(shardingNum);
        this.transOperationMaps.get(mod).execute(new TransactionCallbackWithoutResult() {
                @Override
                protected void doInTransactionWithoutResult(TransactionStatus status) {
                        CustomizedJdbcOperationsSessionRepository.this.jdbcOperationMaps.get(mod).update(
                                CustomizedJdbcOperationsSessionRepository.this.deleteSessionQuery, id);
                }
        });
    }
    
    /**
   * @desc Modify by Jimmy Shan, the date is 2019-06-25
   *      Implementing Routing Function
   */
    @Override
    public Map<String, JdbcSession> findByIndexNameAndIndexValue(String indexName, final String indexValue) {
        if (!PRINCIPAL_NAME_INDEX_NAME.equals(indexName)) {
                return Collections.emptyMap();
        }
        List<JdbcSession> sessions = new ArrayList<>();
        Set<Integer> setKey = transOperationMaps.keySet();
        for (Iterator ir = setKey.iterator(); ir.hasNext(); ) {
                Integer key = (Integer) ir.next();
                TransactionOperations transOperation = (TransactionOperations) transOperationMaps.get(key);
                List<JdbcSession> tempSession = transOperation.execute(status) -> 
                                CustomizedJdbcOperationsSessionRepository.this.jdbcOperationMaps.get(key).query(
                                        CustomizedJdbcOperationsSessionRepository.this.listSessionsByPrincipalNameQuery,
                                        (ps) -> ps.setString(1, indexValue),
                                        CustomizedJdbcOperationsSessionRepository.this.extractor));
                if (tempSession != null && !tempSession.isEmpty()) {
                        sessions.addAll(tempSession);
                }    
        }
        Map<String, JdbcSession> sessionMap = new HashMap<>(sessions.size());
        for (JdbcSession session : sessions) {
                sessionMap.put(session.getId(), session);
        }

        return sessionMap;
    }
    
    /**
   * @desc Modify by Jimmy Shan, the date is 2019-06-25
   *      Implementing Routing Function
   */
    private void insertSessionAttributes(JdbcSession session, List<String> attributeNames) {
        Assert.notEmpty(attributeNames, "attributeNames must not be null or empty");
      String sessionId = session.getId();
      int hashCode = Math.abs(sessionId.hashCode());
      int mod = hashCode % Integer.parseInt(shardingNum);
        if (attributeNames.size() > 1) {
            this.jdbcOperationMaps.get(mod).batchUpdate(this.createSessionAttributeQuery, new BatchPreparedStatementSetter() {
                        @Override
                        public void setValues(PreparedStatement ps, int i) throws SQLException {
                                String attributeName = attributeNames.get(i);
                                ps.setString(1, attributeName);
                                setObjectAsBlob(ps, 2, session.getAttribute(attributeName));
                                ps.setString(3, session.getId());
                        }
                        @Override
                        public int getBatchSize() {
                                return attributeNames.size();
                        }

            });
        }    else {
                this.jdbcOperationMaps.get(mod).update(this.createSessionAttributeQuery, (ps) -> {
                    String attributeName = attributeNames.get(0);
                    ps.setString(1, attributeName);
                    setObjectAsBlob(ps, 2, session.getAttribute(attributeName));
                    ps.setString(3, session.getId());
                });
        }
    }
    
    /**
   * @desc Modify by Jimmy Shan, the date is 2019-06-25
   *      Implementing Routing Function
   */
    private void updateSessionAttributes(JdbcSession session, List<String> attributeNames) {
        Assert.notEmpty(attributeNames, "attributeNames must not be null or empty");
      String sessionId = session.getId();
      int hashCode = Math.abs(sessionId.hashCode());
      int mod = hashCode % Integer.parseInt(shardingNum);
        if (attributeNames.size() > 1) {
                this.jdbcOperationMaps.get(mod).batchUpdate(this.updateSessionAttributeQuery, new BatchPreparedStatementSetter() {
                            @Override
                            public void setValues(PreparedStatement ps, int i) throws SQLException {
                                String attributeName = attributeNames.get(i);
                                setObjectAsBlob(ps, 1, session.getAttribute(attributeName));
                                ps.setString(2, session.primaryKey);
                                ps.setString(3, attributeName);
                            }
                            @Override
                            public int getBatchSize() {
                                return attributeNames.size();
                            }
                });
        }    else {
                this.jdbcOperationMaps.get(mod).update(this.updateSessionAttributeQuery, (ps) -> {
                    String attributeName = attributeNames.get(0);
                    setObjectAsBlob(ps, 1, session.getAttribute(attributeName));
                    ps.setString(2, session.primaryKey);
                    ps.setString(3, attributeName);
                });
        }
    }
    
    /**
   * @desc Modify by Jimmy Shan, the date is 2019-06-25
   *      Implementing Routing Function
   */
    private void deleteSessionAttributes(JdbcSession session, List<String> attributeNames) {
        Assert.notEmpty(attributeNames, "attributeNames must not be null or empty");
      String sessionId = session.getId();
      int hashCode = Math.abs(sessionId.hashCode());
      int mod = hashCode % Integer.parseInt(shardingNum);
        if (attributeNames.size() > 1) {
                this.jdbcOperationMaps.get(mod).batchUpdate(this.deleteSessionAttributeQuery, new BatchPreparedStatementSetter() {
                            @Override
                            public void setValues(PreparedStatement ps, int i) throws SQLException {
                                String attributeName = attributeNames.get(i);
                                ps.setString(1, session.primaryKey);
                                ps.setString(2, attributeName);
                            }
                            @Override
                            public int getBatchSize() {
                                return attributeNames.size();
                            }
                });
        } else {
                this.jdbcOperationMaps.get(mod).update(this.deleteSessionAttributeQuery, (ps) -> {
                    String attributeName = attributeNames.get(0);
                    ps.setString(1, session.primaryKey);
                    ps.setString(2, attributeName);
                });
        }
    }
    
    /**
   * @desc Modify by Jimmy Shan, the date is 2019-06-25
   *      Implementing Routing Function
   */
    public void cleanUpExpiredSessions() {
        Set<Integer> setKey = transOperationMaps.keySet();
        for (Iterator ir = setKey.iterator(); ir.hasNext(); ) {
                Integer key = (Integer) ir.next();
                TransactionOperations transOperation = (TransactionOperations) transOperationMaps.get(key);
                Integer deletedCount = transOperation.execute((status) ->
                        CustomizedJdbcOperationsSessionRepository.this.jdbcOperationMaps.get(key).update(
                                CustomizedJdbcOperationsSessionRepository.this.deleteSessionsByExpiryTimeQuery,
                                        System.currentTimeMillis()));
                if (logger.isDebugEnabled()) {
                        logger.debug("Cleaned up " + deletedCount + " expired sessions");
                }
        }
    }

    private static TransactionTemplate createTransactionTemplate(
            PlatformTransactionManager transactionManager) {
            TransactionTemplate transactionTemplate = new TransactionTemplate(
                    transactionManager);
            transactionTemplate.setPropagationBehavior(
                    TransactionDefinition.PROPAGATION_REQUIRES_NEW);
            transactionTemplate.afterPropertiesSet();
            return transactionTemplate;
    }

    private static GenericConversionService createDefaultConversionService() {
            GenericConversionService converter = new GenericConversionService();
            converter.addConverter(Object.class, byte[].class,
                    new SerializingConverter());
            converter.addConverter(byte[].class, Object.class,
                    new DeserializingConverter());
            return converter;
    }

    private String getQuery(String base) {
            return StringUtils.replace(base, "%TABLE_NAME%", this.tableName);
    }

    private void prepareQueries() {
            this.createSessionQuery = getQuery(CREATE_SESSION_QUERY);
            this.createSessionAttributeQuery = getQuery(CREATE_SESSION_ATTRIBUTE_QUERY);
            this.getSessionQuery = getQuery(GET_SESSION_QUERY);
            this.updateSessionQuery = getQuery(UPDATE_SESSION_QUERY);
            this.updateSessionAttributeQuery = getQuery(UPDATE_SESSION_ATTRIBUTE_QUERY);
            this.deleteSessionAttributeQuery = getQuery(DELETE_SESSION_ATTRIBUTE_QUERY);
            this.deleteSessionQuery = getQuery(DELETE_SESSION_QUERY);
            this.listSessionsByPrincipalNameQuery =
                    getQuery(LIST_SESSIONS_BY_PRINCIPAL_NAME_QUERY);
            this.deleteSessionsByExpiryTimeQuery =
                    getQuery(DELETE_SESSIONS_BY_EXPIRY_TIME_QUERY);
    }

    private void setObjectAsBlob(PreparedStatement ps, int paramIndex, Object object)
            throws SQLException {
            byte[] bytes = (byte[]) this.conversionService.convert(object,
                    TypeDescriptor.valueOf(Object.class),
                    TypeDescriptor.valueOf(byte[].class));
            this.lobHandler.getLobCreator().setBlobAsBytes(ps, paramIndex, bytes);
    }

    private Object getBlobAsObject(ResultSet rs, String columnName) throws SQLException {
            byte[] bytes = this.lobHandler.getBlobAsBytes(rs, columnName);
            return this.conversionService.convert(bytes, TypeDescriptor.valueOf(byte[].class),
                    TypeDescriptor.valueOf(Object.class));
    }

    private enum DeltaValue {
            ADDED, UPDATED, REMOVED
    }

    private static <T> Supplier<T> value(T value) {
            return (value != null) ? () -> value : null;
    }

    private static <T> Supplier<T> lazily(Supplier<T> supplier) {
            Supplier<T> lazySupplier = new Supplier<T>() {
                private T value;
                @Override
                public T get() {
                    if (this.value == null) {
                        this.value = supplier.get();
                    }
                    return this.value;
                }
            };
            
            return (supplier != null) ? lazySupplier : null;
    }
    
    
    final class JdbcSession implements Session {

        private final Session delegate;

        private final String primaryKey;

        private boolean isNew;

        private boolean changed;

        private Map<String, DeltaValue> delta = new HashMap<>();

        JdbcSession() {
            this.delegate = new MapSession();
            this.isNew = true;
            this.primaryKey = UUID.randomUUID().toString();
        }

        JdbcSession(String primaryKey, Session delegate) {
            Assert.notNull(primaryKey, "primaryKey cannot be null");
            Assert.notNull(delegate, "Session cannot be null");
            this.primaryKey = primaryKey;
            this.delegate = delegate;
        }

        boolean isNew() {
            return this.isNew;
        }

        boolean isChanged() {
            return this.changed;
        }

        Map<String, DeltaValue> getDelta() {
            return this.delta;
        }

        void clearChangeFlags() {
            this.isNew = false;
            this.changed = false;
            this.delta.clear();
        }

        String getPrincipalName() {
            return PRINCIPAL_NAME_RESOLVER.resolvePrincipal(this);
        }

        Instant getExpiryTime() {
            return getLastAccessedTime().plus(getMaxInactiveInterval());
        }

        @Override
        public String getId() {
            return this.delegate.getId();
        }

        @Override
        public String changeSessionId() {
            this.changed = true;
            return this.delegate.changeSessionId();
        }

        @Override
        public <T> T getAttribute(String attributeName) {
            Supplier<T> supplier = this.delegate.getAttribute(attributeName);
            return (supplier != null) ? supplier.get() : null;
        }

        @Override
        public Set<String> getAttributeNames() {
            return this.delegate.getAttributeNames();
        }

        @Override
        public void setAttribute(String attributeName, Object attributeValue) {
            boolean attributeExists = (this.delegate.getAttribute(attributeName) != null);
            boolean attributeRemoved = (attributeValue == null);
            if (!attributeExists && attributeRemoved) {
                return;
            }
            if (attributeExists) {
                if (attributeRemoved) {
                    this.delta.merge(attributeName, DeltaValue.REMOVED, (oldDeltaValue,
                            deltaValue) -> (oldDeltaValue == DeltaValue.ADDED) ? null
                                    : deltaValue);
                }
                else {
                    this.delta.merge(attributeName, DeltaValue.UPDATED,
                            (oldDeltaValue,
                                    deltaValue) -> (oldDeltaValue == DeltaValue.ADDED)
                                            ? oldDeltaValue
                                            : deltaValue);
                }
            }
            else {
                this.delta.merge(attributeName, DeltaValue.ADDED,
                        (oldDeltaValue, deltaValue) -> (oldDeltaValue == DeltaValue.ADDED)
                                ? oldDeltaValue
                                : DeltaValue.UPDATED);
            }
            this.delegate.setAttribute(attributeName, value(attributeValue));
            if (PRINCIPAL_NAME_INDEX_NAME.equals(attributeName) ||
                    SPRING_SECURITY_CONTEXT.equals(attributeName)) {
                this.changed = true;
            }
        }

        @Override
        public void removeAttribute(String attributeName) {
            setAttribute(attributeName, null);
        }

        @Override
        public Instant getCreationTime() {
            return this.delegate.getCreationTime();
        }

        @Override
        public void setLastAccessedTime(Instant lastAccessedTime) {
            this.delegate.setLastAccessedTime(lastAccessedTime);
            this.changed = true;
        }

        @Override
        public Instant getLastAccessedTime() {
            return this.delegate.getLastAccessedTime();
        }

        @Override
        public void setMaxInactiveInterval(Duration interval) {
            this.delegate.setMaxInactiveInterval(interval);
            this.changed = true;
        }

        @Override
        public Duration getMaxInactiveInterval() {
            return this.delegate.getMaxInactiveInterval();
        }

        @Override
        public boolean isExpired() {
            return this.delegate.isExpired();
        }

    }

    static class PrincipalNameResolver {

        private SpelExpressionParser parser = new SpelExpressionParser();

        public String resolvePrincipal(Session session) {
            String principalName = session.getAttribute(PRINCIPAL_NAME_INDEX_NAME);
            if (principalName != null) {
                return principalName;
            }
            Object authentication = session.getAttribute(SPRING_SECURITY_CONTEXT);
            if (authentication != null) {
                Expression expression = this.parser
                        .parseExpression("authentication?.name");
                return expression.getValue(authentication, String.class);
            }
            return null;
        }

    }

    private class SessionResultSetExtractor implements ResultSetExtractor<List<JdbcSession>> {

        @Override
        public List<JdbcSession> extractData(ResultSet rs) throws SQLException, DataAccessException {
            List<JdbcSession> sessions = new ArrayList<>();
            while (rs.next()) {
                String id = rs.getString("SESSION_ID");
                JdbcSession session;
                if (sessions.size() > 0 && getLast(sessions).getId().equals(id)) {
                    session = getLast(sessions);
                }
                else {
                    MapSession delegate = new MapSession(id);
                    String primaryKey = rs.getString("PRIMARY_ID");
                    delegate.setCreationTime(Instant.ofEpochMilli(rs.getLong("CREATION_TIME")));
                    delegate.setLastAccessedTime(Instant.ofEpochMilli(rs.getLong("LAST_ACCESS_TIME")));
                    delegate.setMaxInactiveInterval(Duration.ofSeconds(rs.getInt("MAX_INACTIVE_INTERVAL")));
                    session = new JdbcSession(primaryKey, delegate);
                }
                String attributeName = rs.getString("ATTRIBUTE_NAME");
                if (attributeName != null) {
                    Object attributeValue = getBlobAsObject(rs, "ATTRIBUTE_BYTES");
                    session.delegate.setAttribute(attributeName, lazily(() -> attributeValue));
                }
                sessions.add(session);
            }
            return sessions;
        }

        private JdbcSession getLast(List<JdbcSession> sessions) {
            return sessions.get(sessions.size() - 1);
        }

    }

}

 

以上工作都完成后,让我们来看看如何使用。

代码如下:

package com.szl.demo.spring.session.controller;

import java.io.PrintWriter;
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class TestSessionController {
        
        @RequestMapping("/testGetSession")
        public void testGetSession(HttpServletRequest request, HttpServletResponse response, ModelMap model) {
                PrintWriter out = null;
                try {
                        out = response.getWriter();
                        
                        HttpSession session = request.getSession();
                        String content = (String) session.getAttribute("userId");
                        System.out.println("session content is : " + content);
                        
                        out.println("session content is : " + content);
                        out.flush();
                        out.close();
                } catch (Exception e) {
                        e.printStackTrace();
                }
        }
        
        @RequestMapping("/testSetSession")
        public void testSetSession(HttpServletRequest request, HttpServletResponse response, ModelMap model) {
                PrintWriter out = null;
                try {
                        out = response.getWriter();
                        UUID uuid = UUID.randomUUID();
                        String uid = uuid.toString().replaceAll("-", "");
                        
                        HttpSession session = request.getSession();
                        String content = (String) session.getAttribute("userId");
                        System.out.println("old session content is : " + content);
                        
                        
                        // 设置session内容
                        session.setAttribute("userId", uid);
                        out.println("new session content is : " + uid);
                        out.flush();
                        out.close();
                } catch (Exception e) {
                        e.printStackTrace();
                }
        }

}

 

是不是很简单,和平时使用session方式一样,好了,备忘录记录到此,还是那句,
仅供有需要的朋友参考,也欢迎转载,但请注明原著,谢谢。

标签:分库,springboot2.1,spring,private,session,springframework,org,import,String
来源: https://www.cnblogs.com/jimmyshan-study/p/11087223.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有