久久福利_99r_国产日韩在线视频_直接看av的网站_中文欧美日韩_久久一

您的位置:首頁技術(shù)文章
文章詳情頁

springboot中如何使用自定義兩級緩存

瀏覽:119日期:2023-03-10 11:34:22

工作中用到了springboot的緩存,使用起來挺方便的,直接引入redis或者ehcache這些緩存依賴包和相關(guān)緩存的starter依賴包,然后在啟動類中加入@EnableCaching注解,然后在需要的地方就可以使用@Cacheable和@CacheEvict使用和刪除緩存了。這個(gè)使用很簡單,相信用過springboot緩存的都會玩,這里就不再多說了。美中不足的是,springboot使用了插件式的集成方式,雖然用起來很方便,但是當(dāng)你集成ehcache的時(shí)候就是用ehcache,集成redis的時(shí)候就是用redis。如果想兩者一起用,ehcache作為本地一級緩存,redis作為集成式的二級緩存,使用默認(rèn)的方式據(jù)我所知是沒法實(shí)現(xiàn)的(如果有高人可以實(shí)現(xiàn),麻煩指點(diǎn)下我)。畢竟很多服務(wù)需要多點(diǎn)部署,如果單獨(dú)選擇ehcache可以很好地實(shí)現(xiàn)本地緩存,但是如果在多機(jī)之間共享緩存又需要比較費(fèi)時(shí)的折騰,如果選用集中式的redis緩存,因?yàn)槊看稳?shù)據(jù)都要走網(wǎng)絡(luò),總感覺性能不會太好。

為了不要侵入springboot原本使用緩存的方式,這里自己定義了兩個(gè)緩存相關(guān)的注解,如下

@Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface Cacheable {String value() default '';String key() default '';//泛型的Class類型Class<?> type() default Exception.class; }@Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface CacheEvict {String value() default '';String key() default ''; }

如上兩個(gè)注解和spring中緩存的注解基本一致,只是去掉了一些不常用的屬性。說到這里,不知道有沒有朋友注意過,當(dāng)你在springboot中單獨(dú)使用redis緩存的時(shí)候,Cacheable和CacheEvict注解的value屬性,實(shí)際上在redis中變成了一個(gè)zset類型的值的key,而且這個(gè)zset里面還是空的,比如@Cacheable(value='cache1',key='key1'),正常情況下redis中應(yīng)該是出現(xiàn)cache1 -> map(key1,value1)這種形式,其中cache1作為緩存名稱,map作為緩存的值,key作為map里的鍵,可以有效的隔離不同的緩存名稱下的緩存。但是實(shí)際上redis里確是cache1 -> 空(zset)和key1 -> value1,兩個(gè)獨(dú)立的鍵值對,試驗(yàn)得知不同的緩存名稱下的緩存完全是共用的,如果有感興趣的朋友可以去試驗(yàn)下,也就是說這個(gè)value屬性實(shí)際上是個(gè)擺設(shè),鍵的唯一性只由key屬性保證。我只能認(rèn)為這是spring的緩存實(shí)現(xiàn)的bug,或者是特意這么設(shè)計(jì)的,(如果有知道啥原因的歡迎指點(diǎn))。

回到正題,有了注解還需要有個(gè)注解處理類,這里我使用aop的切面來進(jìn)行攔截處理,原生的實(shí)現(xiàn)其實(shí)也大同小異。切面處理類如下:

import com.xuanwu.apaas.core.multicache.annotation.CacheEvict; import com.xuanwu.apaas.core.multicache.annotation.Cacheable; import com.xuanwu.apaas.core.utils.JsonUtil; import org.apache.commons.lang3.StringUtils; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; import org.json.JSONArray; import org.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.LocalVariableTableParameterNameDiscoverer; import org.springframework.expression.ExpressionParser; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.support.StandardEvaluationContext; import org.springframework.stereotype.Component; import java.lang.reflect.Method; /** * 多級緩存切面 * @author rongdi */ @Aspect @Component public class MultiCacheAspect {private static final Logger logger = LoggerFactory.getLogger(MultiCacheAspect.class);@Autowiredprivate CacheFactory cacheFactory;//這里通過一個(gè)容器初始化監(jiān)聽器,根據(jù)外部配置的@EnableCaching注解控制緩存開關(guān)private boolean cacheEnable;@Pointcut('@annotation(com.xuanwu.apaas.core.multicache.annotation.Cacheable)')public void cacheableAspect() {}@Pointcut('@annotation(com.xuanwu.apaas.core.multicache.annotation.CacheEvict)')public void cacheEvict() {}@Around('cacheableAspect()')public Object cache(ProceedingJoinPoint joinPoint) { //得到被切面修飾的方法的參數(shù)列表 Object[] args = joinPoint.getArgs(); // result是方法的最終返回結(jié)果 Object result = null; //如果沒有開啟緩存,直接調(diào)用處理方法返回 if(!cacheEnable){try { result = joinPoint.proceed(args);} catch (Throwable e) { logger.error('',e);}return result; } // 得到被代理方法的返回值類型 Class returnType = ((MethodSignature) joinPoint.getSignature()).getReturnType(); // 得到被代理的方法 Method method = ((MethodSignature) joinPoint.getSignature()).getMethod(); // 得到被代理的方法上的注解 Cacheable ca = method.getAnnotation(Cacheable.class); //獲得經(jīng)過el解析后的key值 String key = parseKey(ca.key(),method,args); Class<?> elementClass = ca.type(); //從注解中獲取緩存名稱 String name = ca.value(); try {//先從ehcache中取數(shù)據(jù)String cacheValue = cacheFactory.ehGet(name,key);if(StringUtils.isEmpty(cacheValue)) { //如果ehcache中沒數(shù)據(jù),從redis中取數(shù)據(jù) cacheValue = cacheFactory.redisGet(name,key); if(StringUtils.isEmpty(cacheValue)) {//如果redis中沒有數(shù)據(jù)// 調(diào)用業(yè)務(wù)方法得到結(jié)果result = joinPoint.proceed(args);//將結(jié)果序列化后放入rediscacheFactory.redisPut(name,key,serialize(result)); } else {//如果redis中可以取到數(shù)據(jù)//將緩存中獲取到的數(shù)據(jù)反序列化后返回if(elementClass == Exception.class) { result = deserialize(cacheValue, returnType);} else { result = deserialize(cacheValue, returnType,elementClass);} } //將結(jié)果序列化后放入ehcache cacheFactory.ehPut(name,key,serialize(result));} else { //將緩存中獲取到的數(shù)據(jù)反序列化后返回 if(elementClass == Exception.class) {result = deserialize(cacheValue, returnType); } else {result = deserialize(cacheValue, returnType,elementClass); }} } catch (Throwable throwable) {logger.error('',throwable); } return result;}/** * 在方法調(diào)用前清除緩存,然后調(diào)用業(yè)務(wù)方法 * @param joinPoint * @return * @throws Throwable * */@Around('cacheEvict()')public Object evictCache(ProceedingJoinPoint joinPoint) throws Throwable { // 得到被代理的方法 Method method = ((MethodSignature) joinPoint.getSignature()).getMethod(); //得到被切面修飾的方法的參數(shù)列表 Object[] args = joinPoint.getArgs(); // 得到被代理的方法上的注解 CacheEvict ce = method.getAnnotation(CacheEvict.class); //獲得經(jīng)過el解析后的key值 String key = parseKey(ce.key(),method,args); //從注解中獲取緩存名稱 String name = ce.value(); // 清除對應(yīng)緩存 cacheFactory.cacheDel(name,key); return joinPoint.proceed(args);}/** * 獲取緩存的key * key 定義在注解上,支持SPEL表達(dá)式 * @return */private String parseKey(String key,Method method,Object [] args){ if(StringUtils.isEmpty(key)) return null; //獲取被攔截方法參數(shù)名列表(使用Spring支持類庫) LocalVariableTableParameterNameDiscoverer u = new LocalVariableTableParameterNameDiscoverer(); String[] paraNameArr = u.getParameterNames(method); //使用SPEL進(jìn)行key的解析 ExpressionParser parser = new SpelExpressionParser(); //SPEL上下文 StandardEvaluationContext context = new StandardEvaluationContext(); //把方法參數(shù)放入SPEL上下文中 for(int i=0;i<paraNameArr.length;i++){context.setVariable(paraNameArr[i], args[i]); } return parser.parseExpression(key).getValue(context,String.class);}//序列化private String serialize(Object obj) { String result = null; try {result = JsonUtil.serialize(obj); } catch(Exception e) {result = obj.toString(); } return result;}//反序列化private Object deserialize(String str,Class clazz) { Object result = null; try {if(clazz == JSONObject.class) { result = new JSONObject(str);} else if(clazz == JSONArray.class) { result = new JSONArray(str);} else { result = JsonUtil.deserialize(str,clazz);} } catch(Exception e) { } return result;}//反序列化,支持List<xxx>private Object deserialize(String str,Class clazz,Class elementClass) { Object result = null; try {if(clazz == JSONObject.class) { result = new JSONObject(str);} else if(clazz == JSONArray.class) { result = new JSONArray(str);} else { result = JsonUtil.deserialize(str,clazz,elementClass);} } catch(Exception e) { } return result;}public void setCacheEnable(boolean cacheEnable) { this.cacheEnable = cacheEnable;} }

上面這個(gè)界面使用了一個(gè)cacheEnable變量控制是否使用緩存,為了實(shí)現(xiàn)無縫的接入springboot,必然需要受到原生@EnableCaching注解的控制,這里我使用一個(gè)spring容器加載完成的監(jiān)聽器,然后在監(jiān)聽器里找到是否有被@EnableCaching注解修飾的類,如果有就從spring容器拿到MultiCacheAspect對象,然后將cacheEnable設(shè)置成true。這樣就可以實(shí)現(xiàn)無縫接入springboot,不知道朋友們還有沒有更加優(yōu)雅的方法呢?歡迎交流!監(jiān)聽器類如下

import com.xuanwu.apaas.core.multicache.CacheFactory; import com.xuanwu.apaas.core.multicache.MultiCacheAspect; import org.springframework.cache.annotation.EnableCaching; import org.springframework.context.ApplicationListener; import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.stereotype.Component; import java.util.Map; /** * 用于spring加載完成后,找到項(xiàng)目中是否有開啟緩存的注解@EnableCaching * @author rongdi */ @Component public class ContextRefreshedListener implements ApplicationListener<ContextRefreshedEvent> { @Override public void onApplicationEvent(ContextRefreshedEvent event) { // 判斷根容器為Spring容器,防止出現(xiàn)調(diào)用兩次的情況(mvc加載也會觸發(fā)一次) if(event.getApplicationContext().getParent()==null){//得到所有被@EnableCaching注解修飾的類Map<String,Object> beans = event.getApplicationContext().getBeansWithAnnotation(EnableCaching.class);if(beans != null && !beans.isEmpty()) { MultiCacheAspect multiCache = (MultiCacheAspect)event.getApplicationContext().getBean('multiCacheAspect'); multiCache.setCacheEnable(true);} }} }

實(shí)現(xiàn)了無縫接入,還需要考慮多點(diǎn)部署的時(shí)候,多點(diǎn)的ehcache怎么和redis緩存保持一致的問題。在正常應(yīng)用中,一般redis適合長時(shí)間的集中式緩存,ehcache適合短時(shí)間的本地緩存,假設(shè)現(xiàn)在有A,B和C服務(wù)器,A和B部署了業(yè)務(wù)服務(wù),C部署了redis服務(wù)。當(dāng)請求進(jìn)來,前端入口不管是用LVS或者nginx等負(fù)載軟件,請求都會轉(zhuǎn)發(fā)到某一個(gè)具體服務(wù)器,假設(shè)轉(zhuǎn)發(fā)到了A服務(wù)器,修改了某個(gè)內(nèi)容,而這個(gè)內(nèi)容在redis和ehcache中都有,這時(shí)候,A服務(wù)器的ehcache緩存,和C服務(wù)器的redis不管控制緩存失效也好,刪除也好,都比較容易,但是這時(shí)候B服務(wù)器的ehcache怎么控制失效或者刪除呢?一般比較常用的方式就是使用發(fā)布訂閱模式,當(dāng)需要?jiǎng)h除緩存的時(shí)候在一個(gè)固定的通道發(fā)布一個(gè)消息,然后每個(gè)業(yè)務(wù)服務(wù)器訂閱這個(gè)通道,收到消息后刪除或者過期本地的ehcache緩存(最好是使用過期,但是redis目前只支持對key的過期操作,沒辦法操作key下的map里的成員的過期,如果非要強(qiáng)求用過期,可以自己加時(shí)間戳自己實(shí)現(xiàn),不過用刪除出問題的幾率也很小,畢竟加緩存的都是讀多寫少的應(yīng)用,這里為了方便都是直接刪除緩存)。總結(jié)起來流程就是更新某條數(shù)據(jù),先刪除redis中對應(yīng)的緩存,然后發(fā)布一個(gè)緩存失效的消息在redis的某個(gè)通道中,本地的業(yè)務(wù)服務(wù)去訂閱這個(gè)通道的消息,當(dāng)業(yè)務(wù)服務(wù)收到這個(gè)消息后去刪除本地對應(yīng)的ehcache緩存,redis的各種配置如下

import com.fasterxml.jackson.annotation.JsonAutoDetect;import com.fasterxml.jackson.annotation.PropertyAccessor;import com.fasterxml.jackson.databind.ObjectMapper;import com.xuanwu.apaas.core.multicache.subscriber.MessageSubscriber;import org.springframework.cache.CacheManager;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.data.redis.cache.RedisCacheManager;import org.springframework.data.redis.connection.RedisConnectionFactory;import org.springframework.data.redis.core.RedisTemplate;import org.springframework.data.redis.core.StringRedisTemplate;import org.springframework.data.redis.listener.PatternTopic;import org.springframework.data.redis.listener.RedisMessageListenerContainer;import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;import org.springframework.data.redis.serializer.StringRedisSerializer;import java.util.HashMap;import java.util.Map;@Configurationpublic class MultiCacheConfig { @Bean public CacheManager cacheManager(RedisTemplate redisTemplate) { RedisCacheManager rcm = new RedisCacheManager(redisTemplate); //設(shè)置緩存過期時(shí)間(秒) Map<String, Long> expires = new HashMap<>(); expires.put('ExpOpState',0L); expires.put('ImpOpState',0L); rcm.setExpires(expires); rcm.setDefaultExpiration(600); return rcm; } @Bean public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory) { StringRedisTemplate template = new StringRedisTemplate(factory); StringRedisSerializer redisSerializer = new StringRedisSerializer(); template.setValueSerializer(redisSerializer); template.afterPropertiesSet(); return template; } /** * redis消息監(jiān)聽器容器 * 可以添加多個(gè)監(jiān)聽不同話題的redis監(jiān)聽器,只需要把消息監(jiān)聽器和相應(yīng)的消息訂閱處理器綁定,該消息監(jiān)聽器 * 通過反射技術(shù)調(diào)用消息訂閱處理器的相關(guān)方法進(jìn)行一些業(yè)務(wù)處理 * @param connectionFactory * @param listenerAdapter * @return */ @Bean public RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory, MessageListenerAdapter listenerAdapter) { RedisMessageListenerContainer container = new RedisMessageListenerContainer(); container.setConnectionFactory(connectionFactory); //訂閱了一個(gè)叫redis.uncache的通道 container.addMessageListener(listenerAdapter, new PatternTopic('redis.uncache')); //這個(gè)container 可以添加多個(gè) messageListener return container; } /** * 消息監(jiān)聽器適配器,綁定消息處理器,利用反射技術(shù)調(diào)用消息處理器的業(yè)務(wù)方法 * @param receiver * @return */ @Bean MessageListenerAdapter listenerAdapter(MessageSubscriber receiver) { //這個(gè)地方 是給messageListenerAdapter 傳入一個(gè)消息接受的處理器,利用反射的方法調(diào)用“handle” return new MessageListenerAdapter(receiver, 'handle'); }}

消息發(fā)布類如下:

import com.xuanwu.apaas.core.multicache.CacheFactory; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component public class MessageSubscriber {private static final Logger logger = LoggerFactory.getLogger(MessageSubscriber.class);@Autowiredprivate CacheFactory cacheFactory;/** * 接收到redis訂閱的消息后,將ehcache的緩存失效 * @param message 格式為name_key */public void handle(String message){ logger.debug('redis.ehcache:'+message); if(StringUtils.isEmpty(message)) { return; } String[] strs = message.split('#'); String name = strs[0]; String key = null; if(strs.length == 2) {key = strs[1]; } cacheFactory.ehDel(name,key);} }

具體操作緩存的類如下:

import com.xuanwu.apaas.core.multicache.publisher.MessagePublisher;import net.sf.ehcache.Cache;import net.sf.ehcache.CacheManager;import net.sf.ehcache.Element;import org.apache.commons.lang3.StringUtils;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.data.redis.RedisConnectionFailureException;import org.springframework.data.redis.core.HashOperations;import org.springframework.data.redis.core.RedisTemplate;import org.springframework.stereotype.Component;import java.io.InputStream;/** * 多級緩存切面 * @author rongdi */@Componentpublic class CacheFactory { private static final Logger logger = LoggerFactory.getLogger(CacheFactory.class); @Autowired private RedisTemplate redisTemplate; @Autowired private MessagePublisher messagePublisher; private CacheManager cacheManager; public CacheFactory() {InputStream is = this.getClass().getResourceAsStream('/ehcache.xml');if(is != null) { cacheManager = CacheManager.create(is);} } public void cacheDel(String name,String key) {//刪除redis對應(yīng)的緩存redisDel(name,key);//刪除本地的ehcache緩存,可以不需要,訂閱器那里會刪除 // ehDel(name,key);if(cacheManager != null) { //發(fā)布一個(gè)消息,告訴訂閱的服務(wù)該緩存失效 messagePublisher.publish(name, key);} } public String ehGet(String name,String key) {if(cacheManager == null) return null;Cache cache=cacheManager.getCache(name);if(cache == null) return null;cache.acquireReadLockOnKey(key);try { Element ele = cache.get(key); if(ele == null) return null; return (String)ele.getObjectValue();} finally { cache.releaseReadLockOnKey(key);} } public String redisGet(String name,String key) {HashOperations<String,String,String> oper = redisTemplate.opsForHash();try { return oper.get(name, key);} catch(RedisConnectionFailureException e) { //連接失敗,不拋錯(cuò),直接不用redis緩存了 logger.error('connect redis error ',e); return null;} } public void ehPut(String name,String key,String value) {if(cacheManager == null) return;if(!cacheManager.cacheExists(name)) { cacheManager.addCache(name);}Cache cache=cacheManager.getCache(name);//獲得key上的寫鎖,不同key互相不影響,類似于synchronized(key.intern()){}cache.acquireWriteLockOnKey(key);try { cache.put(new Element(key, value));} finally { //釋放寫鎖 cache.releaseWriteLockOnKey(key);} } public void redisPut(String name,String key,String value) {HashOperations<String,String,String> oper = redisTemplate.opsForHash();try { oper.put(name, key, value);} catch (RedisConnectionFailureException e) { //連接失敗,不拋錯(cuò),直接不用redis緩存了 logger.error('connect redis error ',e);} } public void ehDel(String name,String key) {if(cacheManager == null) return;Cache cache = cacheManager.getCache(name);if(cache != null) { //如果key為空,直接根據(jù)緩存名刪除 if(StringUtils.isEmpty(key)) {cacheManager.removeCache(name); } else {cache.remove(key); }} } public void redisDel(String name,String key) {HashOperations<String,String,String> oper = redisTemplate.opsForHash();try { //如果key為空,直接根據(jù)緩存名刪除 if(StringUtils.isEmpty(key)) {redisTemplate.delete(name); } else {oper.delete(name,key); }} catch (RedisConnectionFailureException e) { //連接失敗,不拋錯(cuò),直接不用redis緩存了 logger.error('connect redis error ',e);} }}

 工具類如下

import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.commons.lang3.StringUtils; import org.json.JSONArray; import org.json.JSONObject; import java.util.*; public class JsonUtil {private static ObjectMapper mapper;static { mapper = new ObjectMapper(); mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);}/** * 將對象序列化成json * * @param obj 待序列化的對象 * @return * @throws Exception */public static String serialize(Object obj) throws Exception { if (obj == null) {throw new IllegalArgumentException('obj should not be null'); } return mapper.writeValueAsString(obj);}/** 帶泛型的反序列化,比如一個(gè)JSONArray反序列化成List<User>*/public static <T> T deserialize(String jsonStr, Class<?> collectionClass,Class<?>... elementClasses) throws Exception { JavaType javaType = mapper.getTypeFactory().constructParametrizedType( collectionClass, collectionClass, elementClasses); return mapper.readValue(jsonStr, javaType);}/** * 將json字符串反序列化成對象 * @param src 待反序列化的json字符串 * @param t 反序列化成為的對象的class類型 * @return * @throws Exception */public static <T> T deserialize(String src, Class<T> t) throws Exception { if (src == null) {throw new IllegalArgumentException('src should not be null'); } if('{}'.equals(src.trim())) {return null; } return mapper.readValue(src, t);} }

具體使用緩存,和之前一樣只需要關(guān)注@Cacheable和@CacheEvict注解,同樣也支持spring的el表達(dá)式。而且這里的value屬性表示的緩存名稱也沒有上面說的那個(gè)問題,完全可以用value隔離不同的緩存,例子如下

@Cacheable(value = 'bo',key='#session.productVersionCode+’’+#session.tenantCode+’’+#objectcode')@CacheEvict(value = 'bo',key='#session.productVersionCode+’’+#session.tenantCode+’’+#objectcode')

附上主要的依賴包

'org.springframework.boot:spring-boot-starter-redis:1.4.2.RELEASE',’net.sf.ehcache:ehcache:2.10.4’,'org.json:json:20160810'

以上就是springboot中如何使用自定義兩級緩存的詳細(xì)內(nèi)容,更多關(guān)于springboot 使用自定義兩級緩存的資料請關(guān)注好吧啦網(wǎng)其它相關(guān)文章!

標(biāo)簽: Spring
相關(guān)文章:
主站蜘蛛池模板: 精品久久久久久久久福利 | 日韩激情一区二区 | 一区二区三区在线免费观看 | 国产一区二区三区四区在线观看 | 日本一区二区三区四区 | 国产精品无码专区在线观看 | 欧美a级在线观看 | 欧美日韩精品一区二区在线观看 | 国产高清第一页 | 成人一区二区在线 | 日本一区二区三区视频免费看 | 亚洲精品视频免费看 | 中文字幕av在线播放 | 国产在线成人 | 99精品热视频 | 欧美综合在线一区 | 久久69精品久久久久久久电影好 | 亚洲高清在线 | 国产亚洲一区二区三区在线 | 国产成人精品免高潮在线观看 | 国产亚洲一区二区三区在线观看 | 黑人粗黑大躁护士 | 日韩一区二区精品 | 四虎影院入口 | 三级欧美在线观看 | 一区二区三区在线 | 久久久国产精品免费 | 黄色av网站在线观看 | 欧美操穴| 精品视频在线观看 | 最新中文字幕视频 | 韩国成人精品a∨在线观看 国产伊人av | 欧美激情在线播放 | 久久1区| 久久综合久久受 | 91视频网址| 毛片网站在线 | 国产在线区 | 一级免费黄色 | 高清免费av | 日韩特黄一级欧美毛片特黄 | 欧美经典一区 | 国产精品视频播放 | 97久久超碰 | 精品国产伦一区二区三区观看说明 | 成人午夜免费网站 | 日本一本视频 | 久草 在线| 一区二区在线视频 | 亚洲高清免费视频 | 欧美日韩电影一区二区 | 91一区二区三区 | 日韩色综合 | 成人精品一区二区三区中文字幕 | 一区二区日韩在线观看 | 精品视频在线观看一区二区三区 | 草草网 | 国产精品国产精品国产专区不卡 | 太子妃好紧皇上好爽h | 欧美一级欧美三级在线观看 | 欧美黄色片| 香蕉久久一区二区不卡无毒影院 | 久久国产精品系列 | 午夜影院黄色 | 色一情一乱一伦一区二区三区 | 国产免费av一区二区三区 | 国产9色在线 | 日韩 | 男人的天堂在线视频 | 色约约精品免费看视频 | 日韩精品三区 | 国产精品成人品 | 国产免费视频 | 亚洲一区二区av | 中文字幕一区二区三区在线视频 | 国产日韩精品视频 | 国产成人免费视频网站高清观看视频 | 自拍偷拍欧美 | 超碰高清| 国产精品高清一区二区 | 中文字幕 亚洲一区 | 国产精品成人av | 国产成人精品午夜 | 亚洲视频自拍 | 亚洲激情在线观看 | 在线中文字幕视频 | 丁香五月亚洲综合在线 | 色综合久久久久久久久久久 | 日本一区二区三区四区 | 精品一二三区 | 三级在线视频 | 在线色网站| 可以在线观看的av网站 | 国产一级一级毛片女人精品 | 久久精品一区二区三区四区 | 国产一区二区精品 | 日韩成人精品视频 | 国产福利在线观看 | 国产美女高潮一区二区三区 | 欧美成人免费视频 | 伊人免费网 | 亚洲一区二区久久 | 亚洲精品一区久久久久久 | 99视频在线 | 国产精品不卡 | 伊人欧美在线 | 狠狠综合久久av一区二区老牛 | a级性视频| 日本在线观看 | 久久久xxxx| 日韩6699人妻熟女毛片 | 中文字幕 欧美 日韩 | 综合二区 | 天天天干夜夜夜操 | 欧美日韩在线免费观看 | 国产精品久久婷婷六月丁香 | 精品久久久久久久 | 91精品国产综合久久久蜜臀粉嫩 | 精品在线一区二区三区 | 国产激情偷乱视频一区二区三区 | 91精品视频在线 | 欧美精品在线观看 | 欧美日韩不卡在线 | www.久久 | 国产欧美综合一区二区三区 | 欧美一区二区三区在线观看视频 | www.99热.com| 欧美精品在线免费观看 | 一区二区三区国产 | 亚洲欧美另类久久久精品2019 | 精品国产乱码久久久久久久软件 | 亚洲第一av | 日韩国产欧美视频 | 亚洲自拍一区在线 | 99看片| 在线日韩一区 | 久久久艹| 九九亚洲 | av手机电影 | 国产在线小视频 | 在线观看国产一区 | 中文字幕视频在线观看 | 五月婷婷激情 | 成人欧美一区二区三区黑人孕妇 | 91亚洲精品视频 | 久久黄视频 | 天天色av | 久久久久久中文字幕 | 亚洲成人三区 | 激情小网站 | 欧美日韩国产在线看 | 嫩草影院永久入口 | 国产精品一区二区三区在线播放 | 嫩草视频在线播放 | 久久999视频 | 日韩超级大片免费看国产国产播放器 | 欧美成人激情视频 | 婷婷毛片 | 久久久国产一区二区 | 国产精品1区2区 | 亚洲自拍在线观看 | 天天干天天看天天操 | 中文字幕在线视频网站 | 一区二区三区国产 | 欧美成人精品一区 | 国产成人av在线 | 奇米精品一区二区三区在线观看 | 亚洲视频在线观看视频 | 日本精品一区二区三区视频 | 欧美福利电影在线观看 | 成人xxx | 欧美激情国产日韩精品一区18 | 亚洲国产免费 | 亚洲一区二区三区四区在线观看 | 国产成人午夜精品影院游乐网 | 91国自产精品中文字幕亚洲 | 一级特黄网站 | 龙珠z国语版291集全 | 日韩精品一区在线 | av网站免费 | 一级片国产 | 欧美日韩国产影院 | 精品国产乱码久久久久久影片 | 久久www免费视频 | 欧美伊人影院 | 爱福利视频 | 日韩成人在线免费视频 | 日韩久久网站 | 日韩精品一区二区三区老鸭窝 | 国产视频久久 | 国产a久久精品一区二区三区 | 婷婷五月色综合香五月 | 男人的天堂在线视频 | 久久手机视频 | 精品在线视频一区 | 精品日韩欧美一区二区三区在线播放 | 国产精品婷婷午夜在线观看 | 国产成人精品一区二 | 欧美一二三四成人免费视频 | 蜜桃视频在线观看www社区 | 国产在线一区二区 | 亚洲免费在线观看 | 中文字幕乱码亚洲精品一区 | 日本高清视频一区二区三区 | 91色视频在线观看 | 一区免费观看 | 欧美一区二区免费 | 午夜激情在线 | 欧美日韩精品一区二区在线播放 | 国产一区二区视频免费 | 久久国产区 | 日韩精品免费观看 | 久久久精品网站 | 99热这里有 | 国产精品久久久久久久久 | 欧洲精品在线视频 | 日韩成人在线视频 | 国产精品第一国产精品 | 欧美日韩综合精品 | 欧美日韩精品一区 | 久久9999| 亚洲精品免费观看 | 欧美日韩中文 | 91免费视频在线 | 这里只有精品视频 | 久久久99久久久国产自输拍 | 狠狠色狠狠色合久久伊人 | 毛片网站在线观看 | 欧美中文字幕在线 | 国产一区二区在线视频 | 欧美日本亚洲 | 经典法国性xxxx精品 | 日韩草比 | 亚洲午夜精品一区二区三区他趣 | 美女超碰 | 成人免费毛片aaaaaa片 | 日韩精品免费在线观看 | 国产成人精品久久二区二区 | 三级成人在线 | 成年免费观看 | 新疆少妇videos高潮 | 成年入口无限观看网站 | 日韩在线观看中文字幕 | 国产日产欧美a级毛片 | 99热在线看 | 久久久久久综合 | 国产一区二区三区视频 | 欧美视频一二 | 国产精品一区av | 天堂一区二区三区 | 亚洲精品久久久 | 成人免费在线电影 | 亚洲最大免费视频 | 成人国产免费视频 | 另类五月天 | 一区二区三区视频 | 亚洲国产一区二区在线 | 国产精品久久久久一区二区三区 | 91高清视频在线观看 | 久久精品一区 | 欧美寡妇偷汉性猛交 | 狠狠久 | 9se成人免费网站 | 国产精品久久久久久久一区探花 | 影音先锋中文字幕在线 | 久久精品国产亚洲blacked | 国产一区二区三区免费视频 | 91在线精品一区二区 | 国产乱a视频在线 | 久久精品久久久 | 夜夜操天天干 | 99国产精品99久久久久久 | 精品国产一区二区在线 | 国产日韩欧美一区二区 | 日本在线看| 日韩高清中文字幕 | 插插射啊爱视频日a级 | 黄色国产视频 | 日韩av电影观看 | 日韩av电影免费 | 欧美成人猛片aaaaaaa | 国产一区二区在线看 | 日韩欧美国产一区二区三区 | 精品亚洲国产成av人片传媒 | 婷婷午夜激情网 | 国产在视频一区二区三区吞精 | 久久伊人一区二区 | 成人伊人 | 国产激情网 | www在线看片 | 日韩国产在线播放 | 成人免费xxxxxx视频 | 午夜视频| 国产精品不卡 | 在线视频三级 | 精品亚洲成a人片在线观看 国产高清在线 | 99色资源 | 毛片天堂| 一区二区三区在线 | 国产一区二区三区在线视频 | 亚洲国产aⅴ成人精品无吗 国产精品永久在线观看 | 国产欧美综合一区二区三区 | 欧美精品日韩 | 久久精品久久久久久 | 亚洲精品aaa| 精品视频一区二区三区 | 三级色黄| 精品国产一区二区三区久久久 | 午夜艹| 亚洲一区二区三区久久 | 成人欧美一区二区三区在线播放 | 成年人网站国产 | 国产精品久久久久久久久久久久久久 | 日韩精品一区二区三区在线观看 | 成人一区二区三区久久精品嫩草 | 一区二区三区高清 | 国产h在线| 波多野结衣电影一区 | 中文字幕日韩欧美一区二区三区 | 国产精品久久久久久久久久久新郎 | 午夜电影网址 | 69免费视频| 免费欧美| 一级h片| 最新日韩av | 久久精品黄色 | 久久99精品视频 | 亚洲精品美女在线观看 | 欧美日韩欧美日韩 | 免费日韩成人 | 亚洲成av人片在线观看无码 | 亚洲男人av| 日韩午夜av| 国产欧美日韩一区 | 中文字幕成人影院 | 三级精品| 五月激情综合婷婷 | 精品成人免费视频 | 中文字幕三区 | 久久只有精品 | 午夜精品一区二区三区在线播放 | 特黄特黄aaaa级毛片免费看 | 在线国产视频 | 岛国av一区| 午夜免费福利在线 | 国产精品久久免费视频在线 | 日韩成人在线网站 | 欧美二区三区 | 国产成人精品一区二区三区视频 | 99免费精品 | 91视频观看 | 国产在线观看91一区二区三区 | 操操网站 | 精品久久久久久久久福利 | 一级黄色片欧美 | 国产精品久久国产精品 | 成人免费视频观看视频 | 久久久天天 | 精品久久久久久久 | 日韩精品在线网站 | 日韩免费视频 | 亚洲成人免费在线观看 | 理论片一区 | 91精品免费 | 欧美视频免费在线观看 | 日韩欧美不卡 | a一级片在线观看 | 国产成人一区 | 欧美性猛交一区二区三区精品 | 成人国产精品视频 | 91精品国产欧美一区二区成人 | 亚洲国产一区二区三区四区 | 国产高清一区二区三区 | 国产精品久久嫩一区二区免费 | 国产精品视频一区二区三区 | 日韩一级免费在线观看 | 国产欧美一区二区精品忘忧草 | 国产欧美精品一区二区三区 | 天堂中文资源在线 | 日韩欧美一区二区三区免费观看 | 99国产精品99久久久久久 | 久久国产成人 | 精品久久久久久国产 | 久久精品国产亚卅av嘿嘿 | 国产成人aⅴ | 97夜夜操| 欧美黄色激情 | 色综合一区二区三区 | 一区二区三区四区在线视频 | 亚洲精品9999 | 国产视频中文字幕 | 免费在线看a | 91精品国产综合久久久久久软件 | 天堂在线网 | 国产精品一区二区在线 | 免费在线观看国产 | 免费黄在线观看 | 欧美一区二区视频 | 欧美日韩在线免费观看 | 一级毛片,一级毛片 | 伊人影院久久 | 精品1区2区 | 国产最新视频 | 亚洲三级在线播放 | 美女久久| 天天澡天天狠天天天做 | 高清国产午夜精品久久久久久 | 精品一区二区免费视频 | 亚洲精品综合 | 成人激情视频在线播放 | 久久精品久久久 | 国产一区二区三区免费在线观看 | 亚洲精品乱码久久久久久蜜糖图片 | 国产黄色精品 | 亚洲精品第一页 | 亚州精品天堂中文字幕 | 激情久久av一区av二区av三区 | 国产成人免费视频网站视频社区 | 久久精品久久综合 | 国产精品久久免费视频在线 | 很黄很污的网站 | 真实国产露脸乱 | av在线日韩 | 精品一区二区在线观看 | 午夜精品91 | 欧美精品一区二 | 欧美二区三区 | 午夜精品久久久久久99热软件 | 免费成人在线视频网站 | av网址在线播放 | 成人在线免费观看 | 伊人激情网 | 国产偷自视频区视频 | 欧美区在线 | 久久99精品久久久久久园产越南 | 午夜四虎 | 久久三区 | 国产一区二区三区免费播放 | 国产片在线观看 | 亚洲乱码一区二区 | 久久亚洲一区二区 | 国产999精品久久久久久麻豆 | 综合一区 | 成人av免费观看 | 久色视频在线 | aaa久久| 国产伦精品久久久一区二区三区 | 久久精品亚洲 | 欧美一级黄 | 色吧综合网 | 亚洲视频中文 | 久久久噜噜噜www成人网 | 中文在线一区二区 | 91色视频在线观看 | 亚洲精品免费观看 | 日韩亚洲视频 | 伊人av超碰久久久麻豆 | 成人免费一区二区三区视频网站 | 欧美一区二区三区视频 | 亚洲美女网站 | 日韩欧美一区二区三区免费观看 | 亚洲福利av| 日韩国产一区二区 | 精品国产鲁一鲁一区二区在线观看 | 成人午夜在线 | 欧美日韩精品久久 | 一区二区三区亚洲精品国 | 欧美亚洲国产一区 | 手机看片亚洲 | 毛片在线网站 | 国产黄色免费网站 | 91网站在线播放 | 精品91久久久 | 欧美精品免费在线观看 | 亚洲日韩欧美一区二区在线 | 亚洲精彩视频在线观看 | 国产91视频一区二区 | 亚洲精品大片 | 欧美精品在线一区二区三区 | 国产伦精品一区二区三区高清 | 国产精品九九九 | 91视频精选 | 午夜精品一区二区三区在线视频 | 精品久久久蜜桃 | 天天爱爱网 | 精品91久久久 | 福利社午夜影院 | 亚洲最新中文字幕 | 亚洲第一视频 | 国产精品久久免费观看spa | 可以在线观看的av网站 | 欧美日韩在线二区 | 成人在线免费小视频 | 久久成人在线视频 | 一区二区三区四区 | 最近免费中文字幕大全免费版视频 | 国产欧美日韩综合精品一区二区 | www.一区二区 | 免费h| 日日夜夜一区二区 | 免费亚洲婷婷 | 中文字幕第66页 | 91视频8mav| 中文字幕第18页 | 国产精品久久免费视频 | 91高清在线 | 国产一区二区精品在线 | 久久久综合亚洲91久久98 | 九色porny国模私拍av | 国产精品免费观看 | 成人高清视频在线 | 午夜妇女aaaa区片 | 色婷婷久久 | 亚洲一区视频 | 欧美日韩一级在线观看 | 一区二区三区 在线 | 色婷婷亚洲 | 中文字幕一区在线 | 黄色毛片一级 | 欧美日韩国产高清视频 | 精品在线免费视频 | 久久精品免费一区二区 | 国产一区二区三区久久久久久 | 精品香蕉一区二区三区 | 久久综合九九 | 亚洲欧美在线观看 | 亚洲天堂久久 | 中文字幕国产区 | 成人在线影视 | 国产精品日韩在线 | 黄色日本视频 | 国产高清一区二区三区 | 国产精品久久久久久久久费观看 | 影视一区二区 | 精品亚洲国产成av人片传媒 | 一区二区三区在线播放 | 91在线观看视频 | 黄网在线免费观看 | www.久久精品 | 日韩在线观看一区 | 一区二区久久 | 99久久久久久 | 青青草视频在线免费观看 | 亚洲成人av | 国产精品日产欧美久久久久 | 97碰碰碰| 国产精品三级久久久久久电影 | 成人精品一区 | 一区二区久久 | 国产亚洲一区二区三区在线观看 | 亚洲成年片 | 国产网站在线 | 日韩精品一区二区三区在线播放 | 九九免费视频 | 亚洲第一av | 在线播放国产视频 | 久久精品亚洲精品 | 亚洲精品久久久久午夜 | 亚洲精品成人在线 | 亚洲自拍偷拍欧美 | 亚洲欧美一区二区在线观看 | av免费网站 | 99re| 天天爱天天操 | 亚洲欧洲无码一区二区三区 | 久久久久女人精品毛片九一韩国 | 久久久亚洲精品视频 | 午夜剧院官方 | 国产高潮好爽受不了了夜色 | 一区二区精品在线 | 这里精品 | 亚洲毛片在线观看 | 国产精品99久久久久久久vr | 久久99精品久久久久久园产越南 | 日本中文字幕一区 | 一区二区三区四区在线视频 | 日韩高清一区二区 | 国内精品一区二区三区 | 精品久久久久久国产 | 免费观看av毛片 | 毛片网子| 日韩中文在线 | 欧美日韩精品在线一区 | 99精品国产高清在线观看 | 在线91| 中文字幕av一区 | 一区二区毛片 | 久久精品网 | 91香蕉视频在线观看 | 中文字幕一区二区三区在线视频 | 我要看免费黄色片 | 中文字幕二区 | 精品国产一区二区三区久久久蜜月 | 亚洲专区中文字幕 | 亚洲国产精品一区 | 毛片91| 欧美精品综合 | 国产www在线| 国产精品久久久久久亚洲调教 | 欧美在线播放一区二区三区 | 日韩素人在线 | 国产精品高潮呻吟久久av野狼 | 国产亚洲一区二区三区在线 | 国产日韩欧美在线观看 | 91精品综合久久久久久五月天 | 久草观看 | 久久久久久国产一级毛片高清版 | 九色一区 | 日韩在线不卡 | 欧美日韩精品一区二区三区四区 | 国产精品成人3p一区二区三区 | 91伊人网| 北条麻妃一区二区三区在线观看 | 日本一区二区三区四区不卡视频 | 人人爽日日爽 | 日韩精品一区二区三区四区视频 |