精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

模仿 Spring 實現一個類管理容器

網絡
項目的初衷是獨立作出一個成熟的有特色的IOC容器,但由于過程參考Spring太多,而且也無法作出太多改進,于是目的變為以此項目作為理解Spring的一個跳板,與網上的一些模仿Spring的框架不同,本項目主要是針對注解形式 地址是Thales

概述

項目的初衷是獨立作出一個成熟的有特色的IOC容器,但由于過程參考Spring太多,而且也無法作出太多改進,于是目的變為以此項目作為理解Spring的一個跳板,與網上的一些模仿Spring的框架不同,本項目主要是針對注解形式
地址是Thales

流程

在Spring中,一個bean的形成分三個大的階段,

bean的定義階段(包含BeanDefinition的加載,解析,與注冊)
bean的實例化階段(包含對象的創建,屬性的注入)
bean的初始化階段(包含一些資源的初始化,譬如打開文件建立連接等等)
這只是大概的劃分,關于BeanPostProcessor等后置處理并沒有顯式的提及.

類的設計

如果只想了解一個bean是怎么從生到死的,只需要一步步debug就好了,如果看不懂,就多debug幾遍.可是如果想實現一個類似的容器,類的設計,職責的分配,接口的實現繼承必然是要了解的(除非你想幾個類做完所有的事)

以下是DefaultListableBeanFactory的類圖

是不是頂不住

我們再來看一張圖

第一張是Spring5.0的,第二張圖是Spring0.9的,所以并沒有必要在一開始就引入過多的設計復雜度

我們再來看一套對比圖

哪一個是0.9的,哪一個是5.0的一目了然.

說這么多的目的,是說明我們沒必要一開始就奔著最完善的目標去寫,可以一步步來,一步步加入功能

實現簡易IOC
眾所周知,SpringIoC中最基本的就是BeanFactory

我們先定義一個BeanFactory接口

  1. //暫時就給這一個方法public interface BeanFactory {    /**     * 根據名字獲取Bean實例     * @param name     * @return     */    Object getBean(String name);} 

beanDefinition

由于是注解形式,我們不能再像xml那樣給定一個資源文件再去解析了,而應該去掃描classPath下所有帶有@Component的類,

這時候我們需要給定的參數就從文件路徑變成了包路徑,我們只需要掃描這個包及其子包內符合條件的類,并且將其轉化為BeanDefinition再注冊就好.執行這個功能的是ClassPathBeanDefinitionScanner這個類.在這一步,就已經和傳統的流程有所區別了,我們會傳入一個ResourceLoader去實現具體的掃描功能(即定位),但不會再有專門的類去處理解析這一步

  1. public interface Resource {    File getFile();    String getFilename();    String getFilePath();}//在最初設計的時候這個抽象類似乎沒有用,但考慮到以后的擴展,還是先放在這public abstract class AbstractResource implements Resource {    @Override    public String getFilename() {        return getFile().getName();    }    @Override    public String getFilePath() {        return getFile().getPath();    }}//這就是最終我們實例化bean時用到的Resource類,在Spring中并沒有直接用,而是通過外觀模式集成了一下成為RootBeanDefinitionpublic class ClassPathResource extends AbstractResource {    private final String path;    private ClassLoader classLoader;    private Class<?> clazz;    public ClassPathResource(String path, ClassLoader classLoader, Class<?> clazz) {        this.path = path;        this.classLoader = classLoader;        this.clazz = clazz;    }} 

  1. public interface ResourceLoader {    Resource getResource(String location);}//此類能夠實現加載多個資源public interface ResourcePatternResolver extends ResourceLoader {    String CLASSPATH_ALL_URL_PREFIX = "classpath*:";    List<? extends Resource> getResources(String location);}//這個類就是正式用于掃描的類了public class PathMatchingResourcePatternResolver implements ResourcePatternResolver {    private final ResourceLoader resourceLoader;    public PathMatchingResourcePatternResolver(ResourceLoader resourceLoader){        this.resourceLoader = resourceLoader;    }    @Override    public Resource getResource(String location) {        return resourceLoader.getResource(location);    }//在Spring中,是通過一層層方法的包裝完成包名到路徑的轉換再到每個文件的掃描再轉換為Resource,這里暫時就先一步到位,把具體實現放在工具類里    @Override    public List<? extends Resource> getResources(String location) {        Set<Class<?>> classes = ClassUtils.getClasses(location);        List<ClassPathResource> classPathResources = new ArrayList<>();        for (Class<?> clazz:classes) {            classPathResources.add(new ClassPathResource("",clazz.getClassLoader(),clazz));        }        return classPathResources;    }} 

但最后直接使用的并不是PathMatchingResourcePatternResolver

而是把他作為ClassPathBeanDefinitionScanner的一個屬性,在這個類里調用.

我們得到了Resource,如何獲得對應的BeanDefinition?

先考慮這樣一個問題,什么樣的類可以被注冊BeanDefinition?

添加了@Component注解或者滿足其他注冊的條件
不是接口或者抽象類
所以我們可以單獨抽象出一個方法 boolean isCandidateComponent(Class<?> clazz)來判斷是否被注冊

現在到了注冊階段,依舊秉持面向接口編程的理念,同時考慮到單一職責,我們把注冊Bean定義單獨抽象出來

  1. public interface BeanDefinitionRegistry {    void registerBeanDefinition(BeanDefinition beanDefinition);} 

上文說到Bean定義的定位,解析,注冊都是在ClassPathBeanDefinitionScanner里完成的,于是BeanDefinitionRegistry自然也成為了ClassPathBeanDefinitionScanner的屬性之一

于是ClassPathBeanDefinitionScanner構建完成了

  1. public class ClassPathBeanDefinitionScanner {    //負責具體的Resource定位    private ResourcePatternResolver resourcePatternResolver;    //負責BeanDefinition解析    private BeanDefinitionRegistry registry;    public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry,String...basePackage) {        this.registry = registry;        this.resourcePatternResolver = new PathMatchingResourcePatternResolver((ResourceLoader) registry);        this.scan(basePackage);    }    public void scan(String...basePackages){        doScan(basePackages);    }    void doScan(String[] basePackages){        Set<BeanDefinition> beanDefinitions = new LinkedHashSet<>();        for (String basePackage:basePackages) {            Set<BeanDefinition> candidates = findCandidateComponents(basePackage);            for(BeanDefinition candidate:candidates){                beanDefinitions.add(candidate);                registry.registerBeanDefinition(candidate);            }        }    }    //獲取被注冊的bean的集合    private Set<BeanDefinition> findCandidateComponents(String basePackage) {        Set<BeanDefinition> candidates = new LinkedHashSet<>();        List<? extends Resource> resources = getResourcePatternResolver().getResources(basePackage);        for(Resource resource:resources){            if(resource instanceof ClassPathResource){                ClassPathResource classPathResource = (ClassPathResource)resource;                if(isCandidateComponent(classPathResource.getClazz())){                    AnnotationBeanDefinition beanDefinition = new AnnotationBeanDefinition();                    beanDefinition.setClazz(classPathResource.getClazz());                    beanDefinition.setBeanName(BeanUtils.generateBeanName(classPathResource.getClazz().getName()));                    candidates.add(beanDefinition);                }            }        }        return candidates;    }    private ResourcePatternResolver getResourcePatternResolver() {        return this.resourcePatternResolver;    }    //判斷是否被注冊    boolean isCandidateComponent(Class<?> clazz){        Component declaredAnnotation = clazz.getDeclaredAnnotation(Component.class);        return declaredAnnotation!=null&&!clazz.isInterface();    }    ;} 

實例化

在什么時候實例化?我們說,在調用getBean()而又沒有現成的bean時進行實例化

  1. public abstract class AbstractBeanFactory implements BeanFactory{    @Override    public Object getBean(String beanName)    } 

對象創建

有兩種方式,通過Jdk默認的反射實現,或者用cglib代理實現.

默認自然是無參構造,但是如果傳入了參數,則需要根據參數的類型和數量去匹配對應的構造函數,用其去實例化

于是我們抽象出InstantiationStrategy作為實例化接口,兩種實例化方法都需要實現這個接口,我們真正去用的時候只需要去調該接口的方法就好

  1. public interface InstantiationStrategy {    Object instantiate(BeanDefinition beanDefinition, String beanName, BeanFactory owner);}public class SimpleInstantiationStrategy implements InstantiationStrategy {} 

屬性注入

字段值獲取

有兩種方式可以實現字段值獲取

直接注解Autowired或者Value
Value里面填的不是值而是占位符,那么就需要解析占位符去獲取
我們通過Class對象獲取所有字段,再通過遍歷所有字段查找加在字段上的注解來獲取(這僅僅只是Spring的一種注入方式)

  1. //處理@Autowired注解        for(Field field:declaredFields){            Autowired autowired = field.getDeclaredAnnotation(Autowired.class);            if(autowired != null){                pvs.add(new PropertyValue(field.getName(),new BeanReference(BeanUtils.generateBeanName(field.getType().getName()),field.getType())));            }        }        //處理@Value注解        for(Field field:declaredFields){            Value value = field.getDeclaredAnnotation(Value.class);            if(value != null){                String value1 = value.value();                pvs.add(new PropertyValue(field.getName(),value1));            }        } 

字段值填充

獲取字段值后通過反射填入相應的字段中

  1. for(Field field:mbd.getBeanClass().getDeclaredFields()){                field.setAccessible(true);                if (field.getName().equals(propertiesValue.getName())&&field.getType().isAssignableFrom(newValue.getClass())) {                    field.set(bean,newValue);                }            } 

初始化

調用指定的初始化方法,進行資源的初始化.,如何獲取初始化方法?在xml模式中,只要加個標簽即可,如果是注解模式,加個注解標識一下或者在某個注解上加個參數,代表初始化方法,這個還沒有實現

功能填充

后置處理器添加

上面我們已經實現了一個可以進行依賴查找,依賴注入的Bean容器,讓我們再回顧一下Spring的流程,我們少了些什么,最容易想到的應該就是后置處理器了,包括BeanFactoryPostProcessor和BeanPostProcessor兩種,前者對于beanFactory進行修改操作,后者對于bean進行修改操作,同樣是面向接口編程

首先建立BeanPostProcessor

  1. public interface BeanPostProcessor {       Object postProcessBeforeInitialization(Object bean, String beanName);    Object postProcessAfterInitialization(Object bean, String beanName) ;} 

就目前來看,有什么是需要BeanPostProcessor來做的呢?我們可以把之前對注解進行處理,獲取注入屬性的代碼分離出來,專門用一個BeanPostProcessor去處理

所有自定義實現的BeanPostProcessor都需要繼承這個接口,由于BeanPostProcessor的作用是處理其他的Bean,所以必須要在其他被處理的Bean實例化之前被創建出來.于是我們在finishBeanFactoryInitialization(beanFactory);之前添加registerBeanPostProcessors(beanFactory);用于實例化所有的BeanPostProcessor

而這些beanPostProcessor的重要程度是不同的,例如處理注解注入的BeanPostProcessor優先級就要比一般的BeanPostProcessor優先級要高,所以需要先實例化

Aware接口添加

其實現在我們已經可以完全的把一個對象交由IOC容器了,但此時這個對象與容器之間的關系是單向的,容器能夠操作bean,但bean不能借助容器,為了解決此類問題,我們添加一個Aware接口作為標志接口,由各個更具體的Aware去繼承他,并在實例化屬性之后,初始化方法執行之完成相關容器屬性的注入

事件監聽器添加

監聽器是觀察者模式的一種實現

我們先定義以下幾個基本接口

  1. public interface ApplicationEventPublisher {    /**     * 發布事件     * @param event     */    void publishEvent(ApplicationEvent event);}public interface ApplicationEventMulticaster {    /**     * 添加廣播事件     * @param event     */    void multicastEvent(ApplicationEvent event);    /**     * 添加對于某個事件的監聽器     * @param listener     */    void addApplicationListener(ApplicationListener listener);    /**     * 移除指定監聽器     * @param listener     */    void removeApplicationListener(ApplicationListener listener);}public interface ApplicationListener <E extends ApplicationEvent> extends EventListener {    /**     * 監聽特定事件     * @param event     */    void onApplicationEvent(E event);} 

具體調用流程為具體的listener被添加到廣播器中,事件通過publisher統一發布,而publishEvent最后會調用 multicastEvent(ApplicationEvent event)方法,經過相應判斷后由對應監聽器做出相應操作.

如何判斷這個監聽器是否對該事件感興趣?

我們事先實現的listener是有泛型的,我們可以通過這個泛型與傳入的事件類型的關系來判斷

  1. public boolean supportEvent(ApplicationListener<ApplicationEvent> listener,ApplicationEvent event){        //先獲取Class對象        Class<? extends ApplicationListener> listenerClass = listener.getClass();        //獲取其實現的所有接口(包括泛型信息)        Type[] genericInterfaces = listenerClass.getGenericInterfaces();        for (Type genericInterface:genericInterfaces){            //判斷是否為泛型接口            if(genericInterface instanceof ParameterizedType){                ParameterizedType parameterizedType = (ParameterizedType) genericInterface;                //得到所有泛型參數                Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();                for(Type actualTypeArgument:actualTypeArguments){                    try {                        Class<?> aClass = Class.forName(actualTypeArgument.getTypeName());                        //判斷感興趣的事件類型是否與傳入事件相同,或者是其父類                        if(aClass.isAssignableFrom(event.getClass())){                            return true;                        }                    } catch (ClassNotFoundException e) {                        e.printStackTrace();                    }                }            }        }        return false;    } 

FactoryBean添加

目前的Bean都是由BeanFactory來產生的,

我們用FactoryBean接口來標識這個產生Bean的特殊的Bean

循環依賴的解決

循環依賴是指A依賴于B的同時B依賴于A,解決方法為實例化與初始化分離,如果只考慮一般情況的話用兩級緩存實際上就夠了,

代碼優化

實現簡易AOP

如果從正統的AOP開始的話,隨之而來的就是一堆概念,包括切點,通知一類

我們先看AOP要做什么

所以說AOP的核心就是動態代理,我們以Cglib為例來看看動態代理要怎么用

  1. Enhancer enhancer = new Enhancer();//1. 為哪個類進行代理        enhancer.setSuperclass(Buy.class);        enhancer.setCallback((MethodInterceptor) (o, method, objects, methodProxy) -> {            //2. 為該類的哪個方法進行代理            if(method.getName().equals("buyOne")){                //3. 代理究竟要做什么                System.out.println("hello");            }            //4. 調用原有的對象             methodProxy.invokeSuper(o,objects);                     return o;        });//5. 產生代理后的對象        Buy o = (Buy)enhancer.create(); 

這就是動態代理最核心的功能,也是AOP的核心功能,AOP的最終目的是代碼5,即產生一個代理對象,把這個代理對象交給IOC去管理

而為了達成這個目的,AOP框架需要做好代碼1-4所需要做的事,一和二組合起來,成了JoinPoint,3叫做Advice,這兩個組合起來就叫做Advisor,可不可以不分這些種類,就全寫在一個或幾個類里,當然可以,Spring0.9就是這么做的,但發展到如今,早已采用了這種劃分方式.本項目也采用這種分類.

先從連接點說起,如何確定到底在哪里實現功能增強,無非是類與方法兩個層次;

我們先定義ClassFilter與MethodMacther兩個接口

  1. public interface ClassFilter {    /**     * 給定類型是否匹配     * @param clazz     * @return     */    boolean matches(Class< ? > clazz);}public interface MethodMatcher {    /**     * 對應類的對應方法是否匹配     * @param method     * @param targetClass     * @return     */    boolean matches(Method method,Class< ? > targetClass);} 

這兩個接口必然是組合起來使用的,于是我們用PointCut將其組合起來

  1. public interface Pointcut {    /**     * 獲取ClassFilter     * @return     */    ClassFilter getClassFilter();    /**     * 獲取MethodMatcher     * @return     */    MethodMatcher getMethodMatcher();} 

接口只是定義了抽象功能,這些功能還要有具體的實現

我們默認用Java的正則去匹配方法名,以此構建出JdkRegexMethodMatcher

  1. public class JdkRegexMethodPointcut implements MethodMatcher, Pointcut{    private Pattern[] compiledPatterns = new Pattern[0];    @Override    public ClassFilter getClassFilter() {        return null;    }    @Override    public MethodMatcher getMethodMatcher() {        return this;    }    @Override    public boolean matches(Method method, Class<?> targetClass) {        String name = method.getName();        for (Pattern pattern :compiledPatterns) {            Matcher matcher = pattern.matcher(name);            if(matcher.matches()){                return true;            }        }        return false;    }    //預編譯    private Pattern[] compilePatterns(String[] source) throws PatternSyntaxException {        Pattern[] destination = new Pattern[source.length];        for (int i = 0; i < source.length; i++) {            destination[i] = Pattern.compile(source[i]);        }        return destination;    }    public void initPatternRepresentation(String[] patterns) throws PatternSyntaxException {        this.compiledPatterns = compilePatterns(patterns);    }} 

在Spring中,并不是直接繼承的MethodMatcher,考慮到正則的語法不同,額外做了一層抽象,但在此處省略掉了

而JdkRegexMethodMatcher同時也實現了PointCut類,也就是說,現在切點已經準備好了

再來看Advice

由于考慮的可擴展點比較多,于是繼承的層次也變的多了

  1. public interface Advice {}public interface BeforeAdvice extends Advice{}public interface MethodBeforeAdvice extends BeforeAdvice{        void before(Method method, Object[] args, Object target) throws Throwable;} 

現在Advice也定義完了,具體的實現我們交由用戶去做

接下來就是整合成Advisor了

  1. public interface Advisor {    Advice getAdvice();}public interface PointcutAdvisor extends Advisor{       Pointcut getPointcut();}public abstract class AbstractPointcutAdvisor implements PointcutAdvisor{    private Advice advice;    @Override    public Advice getAdvice() {        return advice;    }    public void setAdvice(Advice advice) {        this.advice = advice;    }} 

目前已經定義好了Advisor的功能

我們再實現這個接口

  1. public class RegexMethodPointcutAdvisor extends AbstractPointcutAdvisor {    JdkRegexMethodPointcut pointcut = new JdkRegexMethodPointcut();    private String[] patterns;    public RegexMethodPointcutAdvisor() {    }    public RegexMethodPointcutAdvisor(Advice advice) {        setAdvice(advice);    }    public void setPattern(String pattern) {        setPatterns(pattern);    }    public void setPatterns(String... patterns) {        this.patterns = patterns;        pointcut.initPatternRepresentation(patterns);    }    @Override    public Pointcut getPointcut() {        return pointcut;    }} 

RegexMethodPointcutAdvisor就整合了PointCut以及Advice,通過他,我們就可以確定在何處做何種增強.

現在的advisor可以完成檢驗一個類是否要被代理的功能,但是如果這個類需要被代理,advisor卻無法保存這個類的對應信息

于是我們需要一個類將advisor與對應的代理類結合起來,這就是AdvisedSupport

  1. public class AdvisedSupport {    private  TargetSource targetSource;    private List<MethodInterceptor> methodInterceptors = new ArrayList<>();    private List<PointcutAdvisor> advisors = new ArrayList<>();    public TargetSource getTargetSource() {        return targetSource;    }    public void setTargetSource(TargetSource targetSource) {        this.targetSource = targetSource;    }    public List<MethodInterceptor> getMethodInterceptor() {        return methodInterceptors;    }    public void addMethodInterceptor(MethodInterceptor methodInterceptor) {        this.methodInterceptors.add(methodInterceptor);    }    public List<PointcutAdvisor> getAdvisor() {        return advisors;    }    public void addAdvisor(PointcutAdvisor advisor) {        MethodBeforeAdviceInterceptor methodBeforeAdviceInterceptor = new MethodBeforeAdviceInterceptor();        methodBeforeAdviceInterceptor.setAdvice((MethodBeforeAdvice) advisor.getAdvice());        addMethodInterceptor(methodBeforeAdviceInterceptor);        this.advisors.add(advisor);    }} 

上類屬性中的TargetSource便是真正持有代理對象信息的類

現在萬事具備,只需要用Cglib去使用我們已經持有的信息就可以創建出新的類了

  1. public class CglibAopProxy implements AopProxy{    private final AdvisedSupport advised;    public CglibAopProxy(AdvisedSupport advised) {        this.advised = advised;    }    @Override    public Object getProxy() {        Enhancer enhancer = new Enhancer();        //1. 為哪個類進行代理        enhancer.setSuperclass(advised.getTargetSource().getTargetClass());        enhancer.setCallback(new DynamicAdvisedInterceptor(advised));        //5. 產生代理后的對象        return enhancer.create();    }    private static class DynamicAdvisedInterceptor implements MethodInterceptor {        private final AdvisedSupport advised;        public DynamicAdvisedInterceptor(AdvisedSupport advised) {            this.advised = advised;        }        @Override        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {            CglibInvocation cglibInvocation = new CglibInvocation(method,objects,o,methodProxy);            //2. 為該類的哪個方法進行代理            for(PointcutAdvisor advisor: advised.getAdvisor()){                if(advisor.getPointcut().getMethodMatcher().matches(method,advised.getTargetSource().getTargetClass())){                    //3. 代理究竟要做什么                    return advised.getMethodInterceptor().get(0).invoke(cglibInvocation);                }            }            //4. 調用源方法            return cglibInvocation.proceed();        }    }} 

將這份代碼與最初使用cglib的代碼比較,會發現過程幾乎是一模一樣.但是作為一個框架,應該盡可能的給用戶以方便

于是我們需要一個Creator去把這一切都做好,他需要負責將Advice和PointCut組合成Advisor,再將Advisor與TargetSource組裝成AdvisedSupport,再將AdvisedSupport交給Cglib動態代理,產生代理對象,而用戶只需要編寫Advice以及切入點表達式即可

功能演示

屬性注入基本類型引用類型循環依賴
容器感知
FactoryBean生成對象
AOP切面增強
自定義BeanPostProcessor

困難及解決

首先是設計上的問題
FactoryBean的實現
AOP與IOC的結合
字段的注入

責任編輯:梁菲 來源: 阿里云云棲號
相關推薦

2021-02-17 09:39:41

PodmanDockerLinux

2011-03-24 09:34:41

SPRING

2015-12-30 14:50:45

Kubernetes容器技術Docker

2022-09-22 16:21:43

開源GUI 應用

2019-01-11 13:57:06

2023-11-28 13:50:00

Kubernetes容器

2025-01-03 09:00:00

代碼C++gTest

2021-05-20 07:56:35

Bean容器Spring

2019-12-09 15:00:48

TomcatServlet容器

2025-03-21 08:30:00

容器管理開發開源

2023-05-15 13:59:53

紅帽容器原生虛擬化KubeVirt

2019-04-09 08:50:15

Rancher容器運維

2013-07-02 10:24:52

團隊管理團隊遠程團隊

2020-11-13 07:08:51

Spring Boot應用Spring

2023-10-18 15:25:29

數據源數據庫

2022-01-26 15:20:00

配置微服務架構

2022-07-13 15:31:29

手繪板canvas鴻蒙

2020-09-24 11:46:03

Promise

2022-08-02 14:21:20

滑動驗證碼鴻蒙

2022-07-28 14:20:44

懸浮球鴻蒙
點贊
收藏

51CTO技術棧公眾號

99久久国产免费看| 久久免费精品视频在这里| 无码av免费一区二区三区试看| 国产成人精品福利一区二区三区 | 中文字幕在线视频久| 26uuu另类欧美亚洲曰本| 国产精品精品视频| 欧美在线视频第一页| 国产精东传媒成人av电影| 欧美性猛交xxxxx水多| 亚洲精品电影在线一区| www.成人在线观看| 亚洲女人av| 色妞欧美日韩在线| www.四虎精品| 免费观看成人性生生活片| 日韩美女视频一区二区| 国产一区在线免费| 正在播放木下凛凛xv99| 亚洲一本视频| 在线观看日韩欧美| 任你躁av一区二区三区| 少妇精品视频一区二区免费看| 国产精品久久久久久久浪潮网站| 丁香五月网久久综合| 日韩不卡高清视频| 欧美日韩一区二区高清| 亚洲日本欧美日韩高观看| 日本亚洲一区二区三区| 欧美日韩不卡| 一区二区三区产品免费精品久久75| 狠狠色综合欧美激情| 亚洲天堂视频网| 99日韩精品| 久热精品在线视频| 乐播av一区二区三区| 51vv免费精品视频一区二区| 欧美天天综合网| 精品少妇人妻av免费久久洗澡| 婷婷免费在线视频| 久久久亚洲精品一区二区三区| 91久久大香伊蕉在人线| 亚洲无码精品在线观看| 午夜综合激情| 97国产在线观看| 性欧美疯狂猛交69hd| 亚洲日产av中文字幕| 精品欧美一区二区三区精品久久 | 国一区二区在线观看| 色哟哟网站入口亚洲精品| 久久久久久久久免费看无码| 日韩欧美高清一区二区三区| 欧美蜜桃一区二区三区| 欧美激情国产精品日韩| 成人bbav| 亚洲愉拍自拍另类高清精品| 精品一区二区成人免费视频| 成人在线免费视频| 国产欧美视频一区二区| 久久精品日韩| www.久久久久久| 国产精品影音先锋| 91性高湖久久久久久久久_久久99| 丰满人妻一区二区三区四区| 日韩影院在线观看| 欧美一区二区三区精品电影| 中文字幕一区二区三区手机版| 欧美精品播放| 欧美肥老妇视频| 国产探花在线免费观看| 欧美 日韩 国产精品免费观看| 久久精彩免费视频| 卡通动漫亚洲综合| 一精品久久久| 九色成人免费视频| 久久久久亚洲天堂| 激情亚洲成人| 亚洲18私人小影院| 男人天堂2024| 日韩国产一区二| 国产精品久久久久久久久男 | 欧美日韩精品福利| 日韩一级免费片| 成人97精品毛片免费看| 日韩三级高清在线| av2014天堂网| 精品视频日韩| 欧美久久精品一级黑人c片| 久草资源在线视频| 国产精品久久久久久久免费软件| 日韩男女性生活视频| 亚洲天堂中文网| 国产精品亚洲一区二区三区妖精| 国产精品二区在线观看| 色视频在线观看| 欧美—级在线免费片| 中文字幕99| 成人在线免费观看黄色| 一本大道久久a久久综合婷婷| 亚洲xxxx2d动漫1| 国产精品亚洲四区在线观看| 亚洲精品按摩视频| 美国精品一区二区| 亚洲国产国产亚洲一二三| 欧美在线观看网站| 国产精品伊人久久| 2023国产精品自拍| 亚洲欧美在线网| 国语对白在线刺激| 色视频成人在线观看免| 一区二区久久精品| 精品久久在线| 精品国产三级电影在线观看| 欧美一区二区三区成人精品| 欧美电影免费| 欧美国产在线电影| 久久精品人妻一区二区三区| 丝袜脚交一区二区| 91视频8mav| 熟妇高潮一区二区三区| 中文字幕av一区二区三区| 国产女主播av| 中文字幕不卡三区视频| 欧美日韩一区视频| jizz日本免费| 久久激情电影| 韩国视频理论视频久久| 国产一卡二卡三卡| 国产精品影视在线观看| 久久99精品久久久久久久久久| 国产精品一级伦理| 亚洲乱码日产精品bd| 99视频在线免费| 日韩高清在线观看一区二区| 日韩久久精品电影| 四虎精品免费视频| 日韩国产欧美一区二区三区| 97视频资源在线观看| 深夜视频在线免费| 樱桃视频在线观看一区| av在线com| www.欧美| 国产亚洲视频中文字幕视频| 国产在线一二区| 国产一二精品视频| 日韩高清在线播放| xxx.xxx欧美| 7777精品伊人久久久大香线蕉的| 波多野结衣av在线免费观看| 欧美另类亚洲| 成人xvideos免费视频| 国产小视频免费在线观看| 亚洲制服丝袜av| 999在线精品视频| 欧美男男gaytwinkfreevideos| 九九精品在线观看| 国产又大又黄的视频| 国产婷婷色一区二区三区在线| 国产成人亚洲综合无码| 四虎在线精品| 国产一区二区三区视频免费| 国偷自拍第113页| 国产精品77777竹菊影视小说| 亚洲ai欧洲av| 日韩欧美少妇| 日韩电影在线观看永久视频免费网站| 久久久久久蜜桃| 国产精品一卡二卡| 椎名由奈jux491在线播放| 成人av色网站| 国产亚洲人成a一在线v站| 黄色在线观看国产| 99天天综合性| 999香蕉视频| 精品国产乱码久久久久久果冻传媒 | 亚洲国产精品ⅴa在线观看| 男人天堂网视频| 亚洲免费福利一区| 992tv成人免费影院| 女人18毛片水真多18精品| 亚洲综合丁香婷婷六月香| 欧美色图校园春色| 欧美特黄一级| 国产高清精品一区二区三区| 久久大胆人体| 日韩精品视频在线| 黄色片视频网站| 99国产精品久久久久久久久久| 欧美激情 国产精品| 清纯唯美亚洲经典中文字幕| 日韩av电影在线免费播放| 草碰在线视频| 欧美日韩电影在线播放| 2025国产精品自拍| 懂色av中文一区二区三区| 国产三区在线视频| 精品欧美激情在线观看| 国产免费成人av| 国产黄a三级三级三级av在线看| 51午夜精品国产| 欧美成人精品激情在线视频| 国产精品亚洲一区二区三区在线| 日本日本19xxxⅹhd乱影响| 亚洲理论电影| 国产中文字幕日韩| 丰满诱人av在线播放| 亚洲美女视频网| 在线亚洲欧美日韩| 精品久久久视频| 阿v天堂2014| 精品亚洲aⅴ乱码一区二区三区| 久久最新免费视频| 欧美美女在线直播| 国产精品视频久久久| 国产夫妻在线| 中文字幕最新精品| 人妻中文字幕一区| 一本大道av一区二区在线播放| 久久国产高清视频| 99久久精品国产一区| 香蕉视频色在线观看| 亚洲视频播放| 色中文字幕在线观看| 欧美三级电影在线| 91精品久久久久久久久中文字幕 | 欧美国产成人精品| 国产精品久久久久久久99| 久久综合九色综合欧美狠狠| 成年人视频大全| 精品视频免费| 精品免费日产一区一区三区免费| 伦一区二区三区中文字幕v亚洲| 久久久久北条麻妃免费看| 成人高清免费观看mv| 精品国产区一区| 96亚洲精品久久久蜜桃| 狠狠躁夜夜躁人人躁婷婷91| 日韩三级在线观看视频| 国产欧美一区二区三区鸳鸯浴| 噜噜噜在线视频| 国产伦理精品不卡| 国产精品第12页| 亚洲视频日本| 在线观看欧美激情| 国产亚洲欧美日韩在线观看一区二区| 精品视频第一区| 国产精品亚洲综合在线观看| 国产精品嫩草影院久久久| 一个人www视频在线免费观看| 欧美精品一区三区| www在线观看播放免费视频日本| 亚洲一级免费视频| 亚洲三级中文字幕| 精品国产自在久精品国产| 国产精品久久综合青草亚洲AV| 午夜伦欧美伦电影理论片| 久久精品美女视频| 亚洲一区二区欧美日韩| 国产精品 欧美激情| 中文字幕乱码久久午夜不卡| 公侵犯人妻一区二区三区| thepron国产精品| 天堂va欧美va亚洲va老司机| 国产久卡久卡久卡久卡视频精品| 日本免费色视频| 蜜桃av一区二区| 99精品在线免费视频| 久久成人国产| 青青草原成人网| 在线亚洲观看| 波多野结衣综合网| 亚洲狼人精品一区二区三区| 欧美 丝袜 自拍 制服 另类| 欧美黄色免费| 天天爱天天做天天操| 中文精品久久| 久久久国内精品| 欧美另类综合| av一区二区三区免费观看| 国产精品hd| 免费在线a视频| 视频在线观看一区二区三区| 成年人视频在线免费| 日韩精品色哟哟| 在线免费观看视频黄| 久久电影一区| 一区二区三区国产好的精华液| 国产高清无密码一区二区三区| 午夜激情视频网| 成人三级在线视频| 人妻体内射精一区二区三区| 久久久影视传媒| 黄色av片三级三级三级免费看| 亚洲欧美国产77777| 久久久久久久久艹| 亚洲综合成人网| 午夜精品一区二| 欧美喷水一区二区| 精品国产无码一区二区| 亚洲国产日韩欧美在线99| 老牛影视av牛牛影视av| 在线观看不卡av| caoporn97在线视频| 国自在线精品视频| 经典三级一区二区| 91在线国产电影| 欧美日韩另类图片| 久久综合九色综合久99| 性欧美69xoxoxoxo| 被灌满精子的波多野结衣| 噜噜爱69成人精品| 成人不卡免费视频| 成人动漫一区二区| 特一级黄色录像| 动漫精品一区二区| 在线观看视频二区| 亚洲国产精品va| 噜噜噜在线观看播放视频| 欧美日本高清一区| 成人不卡视频| 国产精品v欧美精品v日韩| 欧美理论视频| 女人喷潮完整视频| 黄色资源网久久资源365| 亚洲午夜久久久久久久久| 中文字幕av一区二区三区高 | 美国三级日本三级久久99| 99热超碰在线| 亚洲素人一区二区| 久久午夜鲁丝片| 精品欧美一区二区久久| 在线激情网站| 欧美一级在线播放| 欧美大胆a级| 先锋影音男人资源| 日韩和的一区二区| 日韩免费高清一区二区| 亚洲精品乱码久久久久久久久 | 神马电影久久| 国产伦精品一区二区三区四区视频_| 免费在线看成人av| 久久久久久久无码| 亚洲精品老司机| 91丨porny丨在线中文| 亚洲精品自拍偷拍| 国产高清在线a视频大全| 91性高湖久久久久久久久_久久99| xvideos.蜜桃一区二区| 国产91沈先生在线播放| 韩国成人精品a∨在线观看| 欧美大波大乳巨大乳| 精品国产户外野外| 99热这里只有精品在线观看| 中文字幕在线日韩| 日本高清不卡一区二区三区视频| 国产日韩欧美一区二区| 国内久久视频| 性久久久久久久久久久| 亚洲成人av免费| 二区三区在线视频| 日韩中文字幕在线观看| 亚洲欧美在线人成swag| 亚洲精品国产系列| 日韩成人一级片| 久久人人爽人人爽人人片| 一本久道久久综合中文字幕| 日韩福利一区二区| 欧美有码在线视频| 午夜精品福利影院| 99精品免费在线观看| 91在线一区二区三区| 97超碰人人干| 国产视频久久久久久久| 亚洲精品在线影院| 亚洲春色在线| 麻豆91在线观看| 五月天色婷婷丁香| 亚洲精品一区二区在线观看| 成人高潮aa毛片免费| 国产区一区二区| 亚洲一区成人| 日本乱子伦xxxx| 欧洲一区二区三区在线| 免费在线超碰| 国产免费亚洲高清| 99精品在线| 乳色吐息在线观看| 亚洲乱码国产乱码精品精98午夜| 欧美 日韩 中文字幕| 91po在线观看91精品国产性色| 久久最新网址| 天天干天天综合| 一区二区免费在线| 亚洲欧美日韩精品永久在线| 国产精品999999| 欧美成人国产| 精品人妻一区二区三区日产乱码卜| 在线视频一区二区三区| 二区三区在线观看| 鲁鲁视频www一区二区|