日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術文章
文章詳情頁

Spring IOC原理補充說明(循環依賴、Bean作用域等)

瀏覽:104日期:2023-08-18 18:31:05

前言

通過之前的幾篇文章將Spring基于XML配置的IOC原理分析完成,但其中還有一些比較重要的細節沒有分析總結,比如循環依賴的解決、作用域的實現原理、BeanPostProcessor的執行時機以及SpringBoot零配置實現原理(@ComponentScan、@Import、@ImportSource、@Bean注解的使用和解析)等等。下面就先來看看循環依賴是怎么解決的,在此之前一定要熟悉整個Bean的實例化過程,本篇只會貼出關鍵性代碼。

正文

循環依賴

首先來看幾個問題:

什么是循環依賴?

在熟悉了Bean實例化原理后,你會怎么解決循環依賴的問題?

Spring怎么解決循環依賴?有哪些循環依賴可以被解決?哪些又不能?

什么是循環依賴?

這個概念很容易理解,簡單說就是兩個類相互依賴,類似線程死鎖的問題,也就是當創建A對象時需要注入B的依賴對象,但B同時也依賴A,那到底該先創建A還是先創建B呢?

Spring是如何解決循環依賴的?

探究Spring的解決方法之前,我們首先得搞清楚Spring Bean有幾種依賴注入的方式:

通過構造函數

通過屬性

通過方法(不一定是setter方法,只要在方法上加上了@Autowired,都會進行依賴注入)

其次,Spring作用域有singleton、prototype、request、session等等,但在非單例模式下發生循環依賴是會直接拋出異常的,下面這個代碼不知道你還有沒有印象,在AbstractBeanFactory.doGetBean中有這個判斷:

if (isPrototypeCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException(beanName);}

為什么這么設計呢?反過來想,如果不這么設計,你怎么知道循環依賴到底是依賴的哪個對象呢?搞清楚了這個再來看哪些依賴注入的方式發生循環依賴是可以解決,而那些又不能。結論是構造函數方式沒辦法解決循環依賴,其它兩種都可以。

我們先來看看為什么通過屬性注入和方法注入可以解決。回憶一下Bean的實例化過程:

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException { // Instantiate the bean. BeanWrapper instanceWrapper = null; if (mbd.isSingleton()) { instanceWrapper = this.factoryBeanInstanceCache.remove(beanName); } if (instanceWrapper == null) { //創建實例 instanceWrapper = createBeanInstance(beanName, mbd, args); } final Object bean = instanceWrapper.getWrappedInstance(); Class<?> beanType = instanceWrapper.getWrappedClass(); if (beanType != NullBean.class) { mbd.resolvedTargetType = beanType; } // Allow post-processors to modify the merged bean definition. synchronized (mbd.postProcessingLock) { if (!mbd.postProcessed) { try { // Bean實例化完成后收集類中的注解(@PostConstruct,@PreDestroy,@Resource, @Autowired,@Value) applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName); } catch (Throwable ex) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, 'Post-processing of merged bean definition failed', ex); } mbd.postProcessed = true; } } // Eagerly cache singletons to be able to resolve circular references // even when triggered by lifecycle interfaces like BeanFactoryAware. // 單例bean提前暴露 boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName)); if (earlySingletonExposure) { if (logger.isTraceEnabled()) { logger.trace('Eagerly caching bean ’' + beanName + '’ to allow for resolving potential circular references'); } //這里著重理解,對理解循環依賴幫助非常大,重要程度 5 添加三級緩存 addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); } // Initialize the bean instance. Object exposedObject = bean; try { //ioc di,依賴注入的核心方法,該方法必須看 populateBean(beanName, mbd, instanceWrapper); //bean 實例化+ioc依賴注入完以后的調用,非常重要 exposedObject = initializeBean(beanName, exposedObject, mbd); } catch (Throwable ex) { if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) { throw (BeanCreationException) ex; } else { throw new BeanCreationException( mbd.getResourceDescription(), beanName, 'Initialization of bean failed', ex); } } if (earlySingletonExposure) { Object earlySingletonReference = getSingleton(beanName, false); if (earlySingletonReference != null) { if (exposedObject == bean) { exposedObject = earlySingletonReference; } else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) { String[] dependentBeans = getDependentBeans(beanName); Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length); for (String dependentBean : dependentBeans) { if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) { actualDependentBeans.add(dependentBean); } } if (!actualDependentBeans.isEmpty()) { throw new BeanCurrentlyInCreationException(beanName, 'Bean with name ’' + beanName + '’ has been injected into other beans [' + StringUtils.collectionToCommaDelimitedString(actualDependentBeans) + '] in its raw version as part of a circular reference, but has eventually been ' + 'wrapped. This means that said other beans do not use the final version of the ' + 'bean. This is often the result of over-eager type matching - consider using ' + '’getBeanNamesOfType’ with the ’allowEagerInit’ flag turned off, for example.'); } } } } // Register bean as disposable. try { //注冊bean銷毀時的類DisposableBeanAdapter registerDisposableBeanIfNecessary(beanName, bean, mbd); } catch (BeanDefinitionValidationException ex) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, 'Invalid destruction signature', ex); } return exposedObject; }

仔細看這個過程其實不難理解,首先Spring會通過無參構造實例化一個空的A對象,實例化完成后會調用addSingletonFactory存入到三級緩存中(注意這里存入的是singletonFactory對象):

protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) { Assert.notNull(singletonFactory, 'Singleton factory must not be null'); synchronized (this.singletonObjects) { // 一級緩存 if (!this.singletonObjects.containsKey(beanName)) { System.out.println('========set value to 3 level cache->beanName->' + beanName + '->value->' + singletonFactory); // 三級緩存 this.singletonFactories.put(beanName, singletonFactory); // 二級緩存 this.earlySingletonObjects.remove(beanName); this.registeredSingletons.add(beanName); } } }

然后才會去依賴注入觸發類B的實例化,所以這時緩存中已經存在了一個空的A對象;同樣B也是通過無參構造實例化,B依賴注入又調用getBean獲取A的實例,而在創建對象之前,先是從緩存中獲取對象:

//從緩存中拿實例 Object sharedInstance = getSingleton(beanName); protected Object getSingleton(String beanName, boolean allowEarlyReference) { //根據beanName從緩存中拿實例 //先從一級緩存拿 Object singletonObject = this.singletonObjects.get(beanName); //如果bean還正在創建,還沒創建完成,其實就是堆內存有了,屬性還沒有DI依賴注入 if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { synchronized (this.singletonObjects) { //從二級緩存中拿 singletonObject = this.earlySingletonObjects.get(beanName); //如果還拿不到,并且允許bean提前暴露 if (singletonObject == null && allowEarlyReference) { //從三級緩存中拿到對象工廠 ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName); if (singletonFactory != null) { //從工廠中拿到對象 singletonObject = singletonFactory.getObject(); //升級到二級緩存 System.out.println('======get instance from 3 level cache->beanName->' + beanName + '->value->' + singletonObject ); this.earlySingletonObjects.put(beanName, singletonObject); //刪除三級緩存 this.singletonFactories.remove(beanName); } } } } return singletonObject; }

很明顯,會從三級緩存中拿到singletonFactory對象并調用getObject方法,這是一個Lambda表達式,在表達式中又調用了getEarlyBeanReference方法:

protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) { Object exposedObject = bean; if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof SmartInstantiationAwareBeanPostProcessor) { SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp; exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName); } } } return exposedObject; }

這里你點進去看會發現都是返回之前我們創建的空的A對象,因此B對象能夠依賴注入完成并存入到一級緩存中,接著A對象繼續未完成的依賴注入自然是可以成功的,也存入到一級緩存中。Spring就是這樣通過緩存解決了循環依賴,但是不知道你注意到沒有在上面的getSingleton方法中,從三級緩存中拿到對象后,會添加到二級緩存并刪除三級緩存,這是為什么呢?這個二級緩存有什么用呢?

其實也很簡單,就是為了提高效率的,因為在getEarlyBeanReference方法中是循環調用BeanPostProcessor類的方法的,當只有一對一的依賴時沒有什么問題,但是當A和B相互依賴,A又和C相互依賴,A在注入完B觸發C的依賴注入時,這個循環還有必要么?讀者們可以自行推演一下整個過程。

至此,Spring是如何解決循環依賴的相信你也很清楚了,現在再來看通過構造函數依賴注入為什么不能解決循環依賴是不是也很清晰了?因為通過構造函數實例化并依賴注入是沒辦法緩存一個實例對象供依賴對象注入的。

作用域實現原理以及如何自定義作用域

作用域實現原理

在Spring中主要有reqest、session、singleton、prototype等等幾種作用域,前面我們分析了singleton創建bean的原理,是通過緩存來實現的,那么其它的呢?還是回到AbstractBeanFactory.doGetBean方法中來:

if (mbd.isSingleton()) { sharedInstance = getSingleton(beanName, () -> { try { return createBean(beanName, mbd, args); } catch (BeansException ex) { // Explicitly remove instance from singleton cache: It might have been put there // eagerly by the creation process, to allow for circular reference resolution. // Also remove any beans that received a temporary reference to the bean. destroySingleton(beanName); throw ex; } }); // 該方法是FactoryBean接口的調用入口 bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);}else if (mbd.isPrototype()) { // It’s a prototype -> create a new instance. Object prototypeInstance = null; try { beforePrototypeCreation(beanName); prototypeInstance = createBean(beanName, mbd, args); } finally { afterPrototypeCreation(beanName); } // 該方法是FactoryBean接口的調用入口 bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);}else { String scopeName = mbd.getScope(); final Scope scope = this.scopes.get(scopeName); if (scope == null) { throw new IllegalStateException('No Scope registered for scope name ’' + scopeName + '’'); } try { Object scopedInstance = scope.get(beanName, () -> { beforePrototypeCreation(beanName); try { return createBean(beanName, mbd, args); } finally { afterPrototypeCreation(beanName); } }); // 該方法是FactoryBean接口的調用入口 bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd); }}

在singleton作用域下,會調用getSingleton方法,然后回調createBean創建對象,最終在getSingleton中完成緩存;而當scope為prototype時,可以看到是直接調用了createBean方法并返回,沒有任何的緩存操作,因此每次調用getBean都會創建新的對象,即使是同一個線程;除此之外都會進入到else片段中。

這個代碼也很簡單,首先通過我們配置的scopeName從scopes中拿到對應的Scope對象,如SessionScope和RequestScope(但這兩個只會在Web環境中被加載,在WebApplicationContextUtils.registerWebApplicationScopes可以看到注冊操作),然后調用對應的get方法存到對應的request或session對象中去。代碼很簡單,這里就不分析了。

自定義Scope

通過以上分析,不難發現我們是很容易實現一個自己的Scope的,首先實現Scope接口,然后將我們類的實例添加到scopes緩存中來,關鍵是怎么添加呢?在AbstractBeanFactory類中有一個registerScope方法就是干這個事的,因此我們只要拿到一個BeanFactory對象就行了,那要怎么拿?還記得在refresh中調用的invokeBeanFactoryPostProcessors方法么?因此我們只需要實現BeanFactoryPostProcessor接口就可以了,是不是So Easy!

BeanPostProcessor的執行時機

BeanPostProcessor執行點很多,根據其接口類型在不同的位置進行調用,只有熟記其執行時機,才能更好的進行擴展,這里以一張時序圖來總結:

Spring IOC原理補充說明(循環依賴、Bean作用域等)

SpringBoot零配置實現原理淺析

在SpringBoot項目中,省去了大量繁雜的xml配置,只需要使用@ComponentScan、@Configuration以及@Bean注解就可以達到和使用xml配置的相同效果,大大簡化了我們的開發,那這個實現原理是怎樣的呢?熟悉了xml解析原理,相信對于這種注解的方式基本上也能猜個大概。

首先我們進入到AnnotationConfigApplicationContext類,這個就是注解方式的IOC容器:

public AnnotationConfigApplicationContext(String... basePackages) { this(); scan(basePackages); refresh(); } public AnnotationConfigApplicationContext() { this.reader = new AnnotatedBeanDefinitionReader(this); this.scanner = new ClassPathBeanDefinitionScanner(this); }

這里ClassPathBeanDefinitionScanner在解析xml時出現過,就是用來掃描包找到合格的資源的;同時還創建了一個AnnotatedBeanDefinitionReader對象對應XmlBeanDefinitionReader,用來解析注解:

public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) { Assert.notNull(registry, 'BeanDefinitionRegistry must not be null'); Assert.notNull(environment, 'Environment must not be null'); this.registry = registry; this.conditionEvaluator = new ConditionEvaluator(registry, environment, null); AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry); } public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors( BeanDefinitionRegistry registry, @Nullable Object source) { DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry); if (beanFactory != null) { if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) { beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE); } if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) { beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver()); } } Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8); if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) { RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class); def.setSource(source); beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)); } if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) { RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class); def.setSource(source); beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)); } // Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor. if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) { RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class); def.setSource(source); beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)); } // Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor. if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) { RootBeanDefinition def = new RootBeanDefinition(); try { def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, AnnotationConfigUtils.class.getClassLoader())); } catch (ClassNotFoundException ex) { throw new IllegalStateException( 'Cannot load optional framework class: ' + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex); } def.setSource(source); beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)); } if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) { RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class); def.setSource(source); beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME)); } if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) { RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class); def.setSource(source); beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME)); } return beanDefs; }

在AnnotatedBeanDefinitionReader構造方法中可以看到調用了registerAnnotationConfigProcessors注冊一些列注解解析的Processor類,重點關注ConfigurationClassPostProcessor類,該類是BeanDefinitionRegistryPostProcessor的子類,所以會在refresh中調用,該類又會委托ConfigurationClassParser去解析@Configuration、@Bean、@ComponentScan等注解,所以這兩個類就是SpringBoot實現零配置的關鍵類,實現和之前分析的注解解析流程差不多,所以具體的實現邏輯讀者請自行分析。

回頭看當解析器和掃描器創建好后,同樣是調用scan方法掃描包,然后refresh啟動容器,所以實現邏輯都是一樣的,殊途同歸,只不過通過父子容器的構造方式使得我們可以很方便的擴展Spring。

總結

本篇是關于IOC實現的一些補充,最重要的是要理解循環依賴的解決辦法,其次SpringBoot零配置實現原理雖然這里只是簡單起了個頭,但需要好好閱讀源碼分析。另外還有很多細節,不可能全都講到,需要我們自己反復琢磨,尤其是Bean實例化那一塊,這將是后面我們理解AOP的基礎。希望大家多多支持好吧啦網。

標簽: Spring
相關文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
另类国产ts人妖高潮视频| 中文字幕日韩欧美精品高清在线| 精品五月天堂| 日韩和的一区二在线| 国产精品分类| 色婷婷综合网| 久久久久亚洲| 日本在线一区二区三区| 日本91福利区| 四虎精品一区二区免费| 国产成人精品一区二区三区免费| 亚洲精品三级| 日韩午夜av| 91精品美女| 精品三级久久久| 日韩欧美二区| 国产福利一区二区精品秒拍| 国产精品最新自拍| 国产99久久| 日本 国产 欧美色综合| 成人午夜网址| 免费不卡在线视频| 国产日韩欧美一区二区三区在线观看| 午夜精品影视国产一区在线麻豆| 香蕉久久99| 亚洲天堂免费| 91成人在线网站| 黑人精品一区| 国产农村妇女精品一二区| 中文字幕日韩亚洲| 精品国产亚洲日本| 国产一区欧美| 国产精选一区| 亚洲一区不卡| 精品日韩一区| 亚洲精品看片| 中文av在线全新| 免费亚洲婷婷| 亚洲免费毛片| 婷婷成人综合| 国语精品一区| 伊人www22综合色| 人在线成免费视频| 欧美aa在线视频| 一区二区三区国产在线| 91精品观看| 久久久精品区| 亚洲尤物在线| 黄色aa久久| 日韩欧美精品一区二区综合视频| 国产高清亚洲| 中文一区一区三区高中清不卡免费| 欧美日韩四区| 国产欧美日韩视频在线| 日韩视频一区| 福利一区二区三区视频在线观看| 久久国产精品99国产| 国产精品一国产精品| 日韩精品久久久久久| 亚洲一二三区视频| 欧美日韩中文| 国产免费成人| 国产一区二区三区不卡视频网站| 精品亚洲精品| 久久国内精品| 麻豆成全视频免费观看在线看| 午夜日韩影院| 神马久久午夜| 亚洲福利免费| 亚洲综合电影| japanese国产精品| 色综合www| 久久久777| 日韩精品中文字幕吗一区二区| 久久久777| 国产韩日影视精品| 国内精品福利| 午夜久久美女| 视频在线观看91| 亚洲+小说+欧美+激情+另类| 亚洲精品看片| 精品视频亚洲| 久久久人人人| 精品91久久久久| 尤物精品在线| 日韩动漫一区| 欧美精品一二| 亚洲九九精品| 国产精品午夜一区二区三区| 欧美久久天堂| 三级在线观看一区二区| 亚洲精品第一| 日韩成人精品一区二区| 日韩激情中文字幕| 久久婷婷激情| 国产欧美高清视频在线| 久久久精品五月天| 国产亚洲一区二区三区啪| 国产一区二区三区四区五区传媒| 好看的av在线不卡观看| 麻豆国产欧美日韩综合精品二区| 久久精品1区| 久久av中文| 日韩欧美另类中文字幕| 激情久久婷婷| 国产乱人伦精品一区| 日韩中文首页| 国产日韩视频在线| 日韩午夜免费| 亚洲播播91| 国产一区国产二区国产三区| 婷婷视频一区二区三区| 精品日韩视频| 国产福利电影在线播放| 四虎成人精品一区二区免费网站| 精品国产第一福利网站| 国产精品亚洲片在线播放| 日本一区二区三区视频在线看| 精品国产乱码久久久久久樱花| 国产午夜久久av| 亚洲精品精选| 性欧美长视频| 日韩成人亚洲| 日韩精品永久网址| 国产成人77亚洲精品www| 日韩不卡免费视频| 香蕉久久久久久| 国产调教精品| 国产精品日韩精品中文字幕| 91欧美极品| 国产精品最新自拍| 精品午夜视频| 成人在线免费观看91| 精品五月天堂| 欧美91在线|欧美| 国产三级一区| 亚州av乱码久久精品蜜桃| 国产精品久久久久77777丨| 鲁大师精品99久久久| 成人午夜网址| 午夜免费一区| 日韩美女精品| 美女视频黄 久久| 精品一区二区三区免费看| 精品一区二区三区视频在线播放 | 狠狠久久伊人| 久久精品三级| 国产精品xxx在线观看| 精品国产一区二区三区噜噜噜| 国产三级精品三级在线观看国产| 国产精品久久久久久久久免费高清| 91av一区| 欧美福利专区| 爽好多水快深点欧美视频| 国产精品综合| 国产成人免费| 亚洲久久视频| 亚洲国产成人二区| 九一成人免费视频| 国产日产精品_国产精品毛片| 毛片在线网站| 神马午夜久久| 天堂va在线高清一区| 欧美三级网址| 日日摸夜夜添夜夜添国产精品| 另类综合日韩欧美亚洲| 影院欧美亚洲| 亚洲手机在线| 麻豆91精品视频| 天堂成人国产精品一区| аⅴ资源天堂资源库在线| 亚洲欧洲国产精品一区| 播放一区二区| 久久精品999| 老司机久久99久久精品播放免费| 在线天堂中文资源最新版| 中文亚洲免费| 久久精品资源| 青草av.久久免费一区| 91成人精品| 亚洲韩日在线| 欧美激情视频一区二区三区免费| 免播放器亚洲| 婷婷国产精品| 视频福利一区| 丁香婷婷久久| 精品一区二区三区在线观看视频| 国产精品嫩草99av在线| 蜜桃视频欧美| 中文字幕高清在线播放| 国产精品久久久亚洲一区| 亚洲3区在线| 久久精品官网| 美女久久久久| 亚洲在线观看| 亚洲一区二区免费看| 国产成人免费| 国产传媒在线| 欧美三级精品| re久久精品视频|