|
關(guān)于session共享的方式有多種: (1)通過nginx的ip_hash,根據(jù)ip將請求分配到對應(yīng)的服務(wù)器 (2)基于關(guān)系型數(shù)據(jù)庫存儲 (3)基于cookie存儲 (4)服務(wù)器內(nèi)置的session復(fù)制域 (5)基于nosql(memcache、redis都可以) 常用的就是1和5,下面研究第5種方式,基于nosql存儲session。 ? 其實(shí)實(shí)現(xiàn)原理也比較簡單,在所有的請求之前配置一過濾器,在請求之前操作session,其實(shí)spring-session中真正起作用的session過濾器是:SessionRepositoryFilter。spring-session集成了redis與mongodb。 ===========session存到redis中的研究==========1.添加maven依賴 <project xmlns="http://maven./POM/4.0.0" xmlns:xsi="http://www./2001/XMLSchema-instance"
xsi:schemaLocation="http://maven./POM/4.0.0 http://maven./xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.qlq</groupId>
<artifactId>sessionDemo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
<version>1.2.1.RELEASE</version>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.8.1</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.2.5</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.7</source>
<target>1.7</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<!-- tomcat7插件 -->
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<port>88</port>
<path>/sess</path>
<uriEncoding>UTF-8</uriEncoding>
<server>tomcat7</server>
</configuration>
</plugin>
</plugins>
</build>
</project>
? 2.web.xml添加過濾器 <?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www./2001/XMLSchema-instance"
xmlns="http://java./xml/ns/javaee"
xsi:schemaLocation="http://java./xml/ns/javaee http://java./xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<display-name>sessionDemo</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<!--Spring配置 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springMVC.xml</param-value>
</context-param>
<!-- Spring監(jiān)聽器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<filter>
<filter-name>springSessionRepositoryFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSessionRepositoryFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
? 3.springMVC.xml配置bean <?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www./schema/beans"
xmlns:xsi="http://www./2001/XMLSchema-instance" xmlns:p="http://www./schema/p"
xmlns:context="http://www./schema/context"
xmlns:mvc="http://www./schema/mvc" xmlns:aop="http://www./schema/aop"
xsi:schemaLocation="http://www./schema/beans http://www./schema/beans/spring-beans-4.2.xsd http://www./schema/context http://www./schema/context/spring-context-4.2.xsd http://www./schema/mvc http://www./schema/mvc/spring-mvc-4.0.xsd http://www./schema/aop http://www./schema/aop/spring-aop-4.2.xsd ">
<!--1.掃描controller注解(只是掃描@Controller) -->
<context:component-scan base-package="cn" />
<bean id="redisHttpSessionConfiguration"
class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration">
<property name="maxInactiveIntervalInSeconds" value="600" />
</bean>
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxTotal" value="100" />
<property name="maxIdle" value="10" />
</bean>
<bean id="jedisConnectionFactory"
class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
destroy-method="destroy">
<property name="hostName" value="127.0.0.1" />
<property name="port" value="6379" />
<property name="timeout" value="3000" />
<property name="usePool" value="true" />
<property name="poolConfig" ref="jedisPoolConfig" />
</bean>
</beans>
? 4.index.jsp簡單的讀取一下sessioid <%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www./TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
jsessionid=${pageContext.session.id}
<br />
<%=request.getRealPath("/")%>
</body>
</html>
結(jié)果: 啟動tomcat訪問之后查看頁面:
? 可視化界面查看redis庫中的數(shù)據(jù): redis中的key: ? 可視化界面中查看:
? ?在redis中通過flushall清空所有數(shù)據(jù)之后再次刷新界面發(fā)現(xiàn)重新生成sessionid,確實(shí)是與redis中session同步。 ? 補(bǔ)充:這里需要注意,如果需要在session中存bean的話,bean需要實(shí)現(xiàn)Serializable接口。 例如: package sessionDemo;
import java.io.Serializable;
public class User implements Serializable {
/**
*
*/
private static final long serialVersionUID = -5654418863461227475L;
private String username;
private int age;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public static long getSerialversionuid() {
return serialVersionUID;
}
public User(String username, int age) {
super();
this.username = username;
this.age = age;
}
}
? 修改頁面: <%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page import="sessionDemo.*"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www./TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<%
request.getSession().setAttribute("user", new User("zs", 5));
%>
jsessionid=${pageContext.session.id}
<br />
${user.username}
<br />
<%=request.getRealPath("/")%>
</body>
</html>
? 訪問頁面查看效果:
? 查看redis:
? 源碼地址:https://github.com/qiao-zhi/spring-session-redis ? ?補(bǔ)充:關(guān)于org.springframework.web.filter.DelegatingFilterProxy過濾器的使用 ? DelegatingFilterProxy就是一個(gè)對于servlet filter的代理,用這個(gè)類的好處主要是通過Spring容器來管理servlet filter的生命周期,還有就是如果filter中需要一些Spring容器的實(shí)例,可以通過spring直接注入,另外讀取一些配置文件這些便利的操作都可以通過Spring來配置實(shí)現(xiàn)。 ? DelegatingFilterProxy的使用方法: 首先在web.xml中配置: <filter> < filter-name>filterName</filter-name> < filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter-mapping> < filter-name>filterName</filter-name> < url-pattern>/*</url-pattern> </filter-mapping> ? 然后在Spring的配置文件中,配置具體的Filter類的實(shí)例。 <bean name="filterName" class="com.*.Filter"></bean> ? 在Spring中配置的bean的name要和web.xml中的<filter-name>一樣 或者在DelegatingFilterProxy的filter配置中配置初始參數(shù):targetBeanName,對應(yīng)到Spring配置中的beanname 如果要保留Filter原有的init,destroy方法的調(diào)用,還需要配置初始化參數(shù)targetFilterLifecycle為true,該參數(shù)默認(rèn)為false ? 在上面session的過濾器使用中,我們在web.xml中配置的filter的name為:springSessionRepositoryFilter,所以spring容器中應(yīng)該有bean為springSessionRepositoryFilter的過濾器。查閱源碼發(fā)現(xiàn)如下:SpringHttpSessionConfiguration 類中。(下面是spring4.0提倡的java配置方式,方法的名稱就是bean的name,@Bean生命一個(gè)bean) @Bean
public <S extends ExpiringSession> SessionRepositoryFilter<? extends ExpiringSession> springSessionRepositoryFilter(
SessionRepository<S> sessionRepository) {
SessionRepositoryFilter<S> sessionRepositoryFilter = new SessionRepositoryFilter<S>(
sessionRepository);
sessionRepositoryFilter.setServletContext(this.servletContext);
if (this.httpSessionStrategy instanceof MultiHttpSessionStrategy) {
sessionRepositoryFilter.setHttpSessionStrategy(
(MultiHttpSessionStrategy) this.httpSessionStrategy);
}
else {
sessionRepositoryFilter.setHttpSessionStrategy(this.httpSessionStrategy);
}
return sessionRepositoryFilter;
}
? ========結(jié)合nginx實(shí)現(xiàn)集群 session共享========1.配置nginx集群注意下面紅色部分的配置,nginx監(jiān)聽84端口,采用權(quán)重的方式分別分發(fā)到本機(jī)的85端口和86端口。85端口和86端口分別啟動兩個(gè)tomcat并且部署上面的項(xiàng)目。 #user nobody;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
server {
listen 84;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
proxy_connect_timeout 3;
proxy_send_timeout 30;
proxy_read_timeout 30;
proxy_pass http://clustername;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
# another virtual host using mix of IP-, name-, and port-based configuration
#
#server {
# listen 8000;
# listen somename:8080;
# server_name somename alias another.alias;
# location / {
# root html;
# index index.html index.htm;
# }
#}
#集群配置:服務(wù)器列表
upstream clustername {
server 127.0.0.1:85 weight=1;#服務(wù)器配置
server 127.0.0.1:86 weight=1;#服務(wù)器配置
}
# HTTPS server
#
#server {
# listen 443 ssl;
# server_name localhost;
# ssl_certificate cert.pem;
# ssl_certificate_key cert.key;
# ssl_session_cache shared:SSL:1m;
# ssl_session_timeout 5m;
# ssl_ciphers HIGH:!aNULL:!MD5;
# ssl_prefer_server_ciphers on;
# location / {
# root html;
# index index.html index.htm;
# }
#}
}
? ? 測試:訪問nginx的84端口,多次訪問發(fā)現(xiàn)平均是一次85端口的tomcat、一次86端口的tomcat,并且其session不變,也就是兩個(gè)tomcat共用一個(gè)redis的session,實(shí)現(xiàn)了session共享。
?
? 至此完成了redis spring-session實(shí)現(xiàn)了session共享,并且也簡單的實(shí)現(xiàn)了結(jié)合nginx實(shí)現(xiàn)集群 session共享。 接下來還會研究shiro redis的session共享。 ? 關(guān)于nginx的ip_hash實(shí)現(xiàn)根據(jù)ip分發(fā)到對應(yīng)server,參考:https://www.cnblogs.com/qlqwjy/p/9833669.html ? 來源:http://www./content-2-114451.html |
|
|