<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          手把手教你看 Spring 源碼

          共 18521字,需瀏覽 38分鐘

           ·

          2021-03-19 11:47

          公眾號(hào)關(guān)注 “GitHub今日熱榜
          設(shè)為 “星標(biāo)”,帶你挖掘更多開(kāi)發(fā)神器!






          Spring類(lèi)的初始化和實(shí)例化的不同



          IOC


          探究spring的IOC容器


          DefaultListableBeanFactory是最終實(shí)現(xiàn)類(lèi),在代碼中可以找到HashMap的影子;IOC容器就是用HashMap裝的Bean;


          public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
              implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
          @Nullable
            private static Class<?> javaxInjectProviderClass;

            static {
              try {
                javaxInjectProviderClass =
                    ClassUtils.forName("javax.inject.Provider", DefaultListableBeanFactory.class.getClassLoader());
              }
              catch (ClassNotFoundException ex) {
                // JSR-330 API not available - Provider interface simply not supported then.
                javaxInjectProviderClass = null;
              }
            }


            /** Map from serialized id to factory instance. */
            private static final Map<String, Reference<DefaultListableBeanFactory>> serializableFactories =
                new ConcurrentHashMap<>(8);

            /** Optional id for this factory, for serialization purposes. */
            @Nullable
            private String serializationId;

            /** Whether to allow re-registration of a different definition with the same name. */
            private boolean allowBeanDefinitionOverriding = true;

            /** Whether to allow eager class loading even for lazy-init beans. */
            private boolean allowEagerClassLoading = true;

            /** Optional OrderComparator for dependency Lists and arrays. */
            @Nullable
            private Comparator<Object> dependencyComparator;

            /** Resolver to use for checking if a bean definition is an autowire candidate. */
            private AutowireCandidateResolver autowireCandidateResolver = SimpleAutowireCandidateResolver.INSTANCE;

            /** Map from dependency type to corresponding autowired value. */
            private final Map<Class<?>, Object> resolvableDependencies = new ConcurrentHashMap<>(16);

            /** Map of bean definition objects, keyed by bean name. */
            private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

            /** Map from bean name to merged BeanDefinitionHolder. */
            private final Map<String, BeanDefinitionHolder> mergedBeanDefinitionHolders = new ConcurrentHashMap<>(256);

            /** Map of singleton and non-singleton bean names, keyed by dependency type. */
            private final Map<Class<?>, String[]> allBeanNamesByType = new ConcurrentHashMap<>(64);

            /** Map of singleton-only bean names, keyed by dependency type. */
            private final Map<Class<?>, String[]> singletonBeanNamesByType = new ConcurrentHashMap<>(64);

            /** List of bean definition names, in registration order. */
            private volatile List<String> beanDefinitionNames = new ArrayList<>(256);

            /** List of names of manually registered singletons, in registration order. */
            private volatile Set<String> manualSingletonNames = new LinkedHashSet<>(16);

            /** Cached array of bean definition names in case of frozen configuration. */
            @Nullable
            private volatile String[] frozenBeanDefinitionNames;
          ................
          ...........
          }


          BeanFactory:主要方法為getBean(String beanName),該方法根據(jù)Bean名稱(chēng)從容器返回對(duì)應(yīng)的Bean


          BeanFactory是接口,提供了IOC容器最基本的形式,給具體的IOC容器的實(shí)現(xiàn)提供了規(guī)范,



          發(fā)現(xiàn)BeanFactory是Spring的IOC容器核心接口,它的職責(zé)包括,實(shí)例化,有很多的實(shí)現(xiàn)類(lèi);



          原始的BeanFactory無(wú)法支持spring的許多插件,如AOP功能、Web應(yīng)用等



          那么BeanFactroy是否有AOP的影子呢?


          找到BeanFactroyAware接口看到很多關(guān)鍵字有proxy類(lèi)似代理的接口


          so 猜想是否跟AOP(面向切面,動(dòng)態(tài)代理)有關(guān)



          然后點(diǎn)進(jìn)去其中一個(gè)方法(AbstractAutoProxyCreator),發(fā)現(xiàn)引入很多跟AOP相關(guān)的包


          import org.springframework.aop.Advisor;
          import org.springframework.aop.Pointcut;
          import org.springframework.aop.TargetSource;
          import org.springframework.aop.framework.AopInfrastructureBean;
          import org.springframework.aop.framework.ProxyFactory;
          import org.springframework.aop.framework.ProxyProcessorSupport;
          import org.springframework.aop.framework.adapter.AdvisorAdapterRegistry;
          import org.springframework.aop.framework.adapter.GlobalAdvisorAdapterRegistry;
          import org.springframework.aop.target.SingletonTargetSource;


          往下看看這個(gè)類(lèi),做了什么?找?guī)讉€(gè)方法出來(lái);


          看看類(lèi)的注釋


          此類(lèi)區(qū)分通用攔截器(由創(chuàng)建的所有代理共享)和特定攔截器:每個(gè)bean實(shí)例唯一。不需要任何通用攔截器。如果存在,則使用interceptorNames屬性設(shè)置它們。


          與{@link org.springframework.aop.framework.ProxyFactoryBean}一樣,使用當(dāng)前工廠中的攔截器名稱(chēng)而不是bean引用來(lái)正確處理原型顧問(wèn)程序和攔截器例如,以支持有狀態(tài)的混合。{@link #set InterceptorNames interceptorNames}條目支持任何建議類(lèi)型。如果有大量的豆需要用類(lèi)似的代理包裝,即委托給相同的攔截器,則這種自動(dòng)代理特別有用。代替x個(gè)目標(biāo)bean的x個(gè)重復(fù)代理定義,您可以在bean工廠注冊(cè)一個(gè)這樣的后處理器,以達(dá)到相同的效果


          public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport 
              implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
              /**
             *設(shè)置公共攔截器。這些必須是當(dāng)前工廠中的bean名稱(chēng)
             */

            public void setInterceptorNames(String... interceptorNames) {
              this.interceptorNames = interceptorNames;
            }
          /**
            為給定的bean創(chuàng)建一個(gè)AOP代理
             */

            protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
                @Nullable Object[] specificInterceptors, TargetSource targetSource) {

              if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
                AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
              }
              ProxyFactory proxyFactory = new ProxyFactory();
              proxyFactory.copyFrom(this);
                  
              if (!proxyFactory.isProxyTargetClass()) {
                if (shouldProxyTargetClass(beanClass, beanName)) {
                  proxyFactory.setProxyTargetClass(true);
                }
                else {
                  evaluateProxyInterfaces(beanClass, proxyFactory);
                }
              }
              Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
              proxyFactory.addAdvisors(advisors);
              proxyFactory.setTargetSource(targetSource);
              customizeProxyFactory(proxyFactory);
              proxyFactory.setFrozen(this.freezeProxy);
                  
              if (advisorsPreFiltered()) {
                proxyFactory.setPreFiltered(true);
              }
              return proxyFactory.getProxy(getProxyClassLoader());
            }
              
              
          }


          AbstractAutoProxyCreator類(lèi)關(guān)系UML圖



          說(shuō)明AOP橫切在Bean的生命周期中


          AOP


          Spring 通過(guò) AbstractAutoProxyCreator 來(lái)創(chuàng)建 AOP 代理,AbstractAutoProxyCreator 是一個(gè)抽象類(lèi),它實(shí)現(xiàn)了 BeanPostProcessor 接口,用于在 bean 初始化完成之后創(chuàng)建它的代理(從上面IOC容器創(chuàng)建Bean過(guò)程中有點(diǎn)體現(xiàn));


          在AbstractAutoProxyCreator類(lèi)關(guān)系UML圖中找到一個(gè)特殊的接口—>BeanPostProcessor


          劃重點(diǎn):


          • 與工廠掛鉤,允許自定義修改新bean實(shí)例,如檢查標(biāo)記接口或使用代理包裝bean;

          • 普通的{@code BeanFactory}允許以編程方式注冊(cè)后處理器,并將其應(yīng)用于通過(guò)bean工廠創(chuàng)建的所有bean中;跟上面的AOP橫切BeanFactroy聯(lián)系上了;


          /**
           工廠掛鉤,允許自定義修改新bean實(shí)例-例如,檢查標(biāo)記接口或使用代理包裝bean。<p>通常,通過(guò)標(biāo)記接口*或類(lèi)似對(duì)象填充bean的后處理器將實(shí)現(xiàn){@link #postProcessBeforeInitialization},而使用代理包裝bean的后處理器通常將實(shí)現(xiàn){@link #postProcessAfterInitialization}。<h3>注冊(cè)</h3> <p> {@ code ApplicationContext}可以在其bean定義中自動(dòng)檢測(cè){@code BeanPostProcessor} bean,并將這些后處理器應(yīng)用于隨后創(chuàng)建的任何bean。普通的{@code BeanFactory}允許以編程方式注冊(cè)后處理器,并將其應(yīng)用于通過(guò)bean工廠創(chuàng)建的所有bean
           */

          public interface BeanPostProcessor {

            /**
             在任何bean 初始化回調(diào)(如InitializingBean的{@code afterPropertiesSet} 或自定義的init-method)之前,將此{(lán)@code BeanPostProcessor}應(yīng)用于給定的新bean實(shí)例<i> </ i>。該bean將已經(jīng)用屬性值填充。返回的bean實(shí)例也可能是原始實(shí)例的包裝;
             */

            @Nullable
            default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
              return bean;
            }

            /**
          在任何bean 初始化回調(diào)(例如InitializingBean的{@code afterPropertiesSet} 或自定義的初始化方法)之后,將此{(lán)@code BeanPostProcessor}應(yīng)用于給定的新bean實(shí)例。該bean將已經(jīng)用屬性值填充。返回的bean實(shí)例可能是原始實(shí)例的包裝。對(duì)于FactoryBean,將為FactoryBean 實(shí)例和由FactoryBean創(chuàng)建的對(duì)象(從Spring 2.0開(kāi)始)調(diào)用此回調(diào)。后處理器可以通過(guò)相應(yīng)的{@code bean instanceof FactoryBean}檢查來(lái)決定是應(yīng)用到FactoryBean還是創(chuàng)建的對(duì)象,還是兩者都應(yīng)用。
             */

            @Nullable
            default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
              return bean;
            }

          }


          在來(lái)看這張圖(IOC容器工作過(guò)程)


          BeanPostProcessor就是AOP切入的位置,處在對(duì)象的生命周期中;



          BeanFactoryPostProcessor(初始化Bean,如上圖)


          public interface BeanFactoryPostProcessor {
            /**
            在標(biāo)準(zhǔn)初始化之后,修改應(yīng)用程序上下文的內(nèi)部bean工廠。所有bean定義都將被加載,但是還沒(méi)有實(shí)例化bean *。這甚至可以覆蓋或添加*屬性,甚至可以用于初始化bean。
             */

            void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;}


          另外提點(diǎn)東西(來(lái)自面試)


          BeanFactory 簡(jiǎn)介以及它 和FactoryBean的區(qū)別(阿里面試)


          FactoryBean接口是什么?


          看看官方注釋?zhuān)?/p>


          在BeanFactory中的對(duì)象實(shí)現(xiàn)的接口,這些對(duì)象本身是個(gè)單個(gè)對(duì)象的工廠,如果這些對(duì)象實(shí)現(xiàn)FactoryBean接口,它將用作對(duì)象公開(kāi)的工廠,而不是直接將自身公開(kāi);



          好像還是有點(diǎn)蒙吧看看其他解釋


          FactoryBean是個(gè)Bean。在Spring中,所有的Bean都是由BeanFactory(也就是IOC容器)來(lái)進(jìn)行管理的。但對(duì)FactoryBean而言,這個(gè)Bean不是簡(jiǎn)單的Bean,而是一個(gè)能生產(chǎn)或者修飾對(duì)象生成的工廠Bean,它的實(shí)現(xiàn)與設(shè)計(jì)模式中的工廠模式和修飾器模式類(lèi)似

              

          FactoryBean接口用的是Class getObjectType();可以理解為高級(jí)定制Bean;


          看FactoryBean接口抽象類(lèi)(AbstractFactoryBean)


          public abstract class AbstractFactoryBean<T>
              implements FactoryBean<T>, BeanClassLoaderAware, BeanFactoryAware, InitializingBean, DisposableBean 
          {
            /** Logger available to subclasses. */
            protected final Log logger = LogFactory.getLog(getClass());
            private boolean singleton = true;
            @Nullable
            private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
            @Nullable
            private BeanFactory beanFactory;
            private boolean initialized = false;
            @Nullable
            private T singletonInstance;
            @Nullable
            private T earlySingletonInstance;

            /**
                設(shè)置是否應(yīng)該創(chuàng)建一個(gè)單例,或者在每個(gè)請(qǐng)求上創(chuàng)建一個(gè)新對(duì)象*否則。默認(rèn)值為{@code true}(單例)。
             */

            public void setSingleton(boolean singleton) {
              this.singleton = singleton;
            }
            @Override
            public boolean isSingleton() {
              return this.singleton;
            }
            @Override
            public void setBeanClassLoader(ClassLoader classLoader) {
              this.beanClassLoader = classLoader;
            }
            @Override
            public void setBeanFactory(@Nullable BeanFactory beanFactory) {
              this.beanFactory = beanFactory;
            }
            /**
             返回運(yùn)行該bean的BeanFactory
             */

            @Nullable
            protected BeanFactory getBeanFactory() {
              return this.beanFactory;
            }

            /**
                從運(yùn)行該bean的BeanFactory獲取一個(gè)bean類(lèi)型轉(zhuǎn)換器
             */

            protected TypeConverter getBeanTypeConverter() {
              BeanFactory beanFactory = getBeanFactory();
              if (beanFactory instanceof ConfigurableBeanFactory) {
                return ((ConfigurableBeanFactory) beanFactory).getTypeConverter();
              }
              else {
                return new SimpleTypeConverter();
              }
            }
              /**
                 公開(kāi)單例實(shí)例(用于通過(guò)“早期單例”代理訪問(wèn))。返回此FactoryBean持有的單例實(shí)例
             */

            @Nullable
            private T getSingletonInstance() throws IllegalStateException {
              Assert.state(this.initialized, "Singleton instance not initialized yet");
              return this.singletonInstance;
            }
          }


          看完FactoryBean接口抽象類(lèi)(AbstractFactoryBean)基本的代碼后,發(fā)現(xiàn)什么?


          FactoryBean基于BeanFactory,F(xiàn)actoryBean是一個(gè)能生產(chǎn)或者修飾對(duì)象生成的工廠Bean;


          FactoryBean中定義了一個(gè)Spring Bean的很重要的三個(gè)特性:是否單例、Bean類(lèi)型、Bean實(shí)例


          ApplicationContext接口,由BeanFactory接口派生而來(lái)


          看到ApplicationContext接口,提供應(yīng)用程序配置的中央接口。在應(yīng)用程序運(yùn)行時(shí)為只讀,但如果實(shí)現(xiàn)支持,則可以重新加載。


          ApplicationContext提供:


          • 用于訪問(wèn)應(yīng)用程序組件的Bean工廠方法。繼承自{@link org.springframework.beans.factory.ListableBeanFactory}。 

          • 以通用方式加載文件資源的能力。繼承自{@link org.springframework.core.io.ResourceLoader}接口。

          • 將事件發(fā)布到注冊(cè)的偵聽(tīng)器的能力。繼承自{@link ApplicationEventPublisher}接口。

          • 解決消息的能力,支持國(guó)際化。繼承自{@link MessageSource}接口。

          • 從父上下文繼承。在后代上下文中的定義將始終優(yōu)先。例如,這意味著整個(gè)Web應(yīng)用程序都可以使用單個(gè)父上下文,而每個(gè)servlet都有自己的子上下文,而該子上下文獨(dú)立于任何其他servlet的子上下文。

          • 除了標(biāo)準(zhǔn)的{@link org.springframework.beans.factory.BeanFactory}生命周期功能之外,ApplicationContext實(shí)現(xiàn)還檢測(cè)并調(diào)用{@link ApplicationContextAware} Bean以及{@link ResourceLoaderAware },{@link ApplicationEventPublisherAware}和{@link MessageSourceAware} bean。


          public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
              MessageSource, ApplicationEventPublisher, ResourcePatternResolver 
          {

            /**
                返回此應(yīng)用程序上下文的唯一ID
             */

            @Nullable
            String getId();

            /**
            返回此上下文所屬的已部署應(yīng)用程序的名稱(chēng)
             */

            String getApplicationName();

            /**
               返回此上下文的顯示名稱(chēng)
             */

            String getDisplayName();

            /**
            返回首次加載此上下文時(shí)的時(shí)間戳
             */

            long getStartupDate();

            /**
             返回父級(jí)上下文,如果沒(méi)有父級(jí),則返回{@code null}
             */

            @Nullable
            ApplicationContext getParent();

            /**
            針對(duì)此上下文公開(kāi)AutowireCapableBeanFactory功能。* <p>應(yīng)用程序代碼通常不使用此功能,除非是為了*初始化存在于應(yīng)用程序上下文之外的bean實(shí)例,*將Spring bean生命周期(全部或部分)應(yīng)用于它們。* <p>或者,通過(guò){@link ConfigurableApplicationContext}接口公開(kāi)的內(nèi)部BeanFactory也提供對(duì){{link AutowireCapableBeanFactory}接口的訪問(wèn)。本方法主要*用作ApplicationContext接口上的便捷特定工具。* <p> <b>注意:從4.2開(kāi)始,在關(guān)閉應(yīng)用程序上下文之后,此方法將始終拋出IllegalStateException *。</ b>在當(dāng)前的Spring Framework *版本中,只有可刷新的應(yīng)用程序上下文才具有這種行為;從4.2開(kāi)始,*所有應(yīng)用程序上下文實(shí)現(xiàn)都將必須遵守。* @為此上下文返回AutowireCapableBeanFactory *如果上下文不支持{@link AutowireCapableBeanFactory}接口,或者尚不具有支持自動(dòng)連線(xiàn)功能的bean工廠,則拋出IllegalStateException(例如,如果{@code refresh()}具有*從未調(diào)用過(guò)),或者上下文已經(jīng)關(guān)閉* @see ConfigurableApplicationContext#refresh()* @see ConfigurableApplicationContext#getBeanFactory()* /
             */

            AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException;


          ApplicationContext接口UML類(lèi)圖



          ApplicationContext有兩個(gè)主要的實(shí)現(xiàn)類(lèi):ClassPathXmlApplicationContext:默認(rèn)從類(lèi)路徑加載配置文件,還有FileSystemXmlApplicationContext:默認(rèn)從文件系統(tǒng)中裝載配置文件


          WebApplicationContext


          提供Web應(yīng)用程序配置的界面。在應(yīng)用程序運(yùn)行時(shí)為只讀,但是如果實(shí)現(xiàn)支持,則可以重新加載。此接口在通用ApplicationContext接口中添加了一個(gè){@code getServletContext()}方法,并定義了一個(gè)眾所周知的應(yīng)用程序?qū)傩悦Q(chēng),該名稱(chēng)必須在引導(dǎo)過(guò)程中綁定到根上下文。類(lèi)似于通用應(yīng)用程序上下文,Web應(yīng)用程序上下文是分層的。每個(gè)應(yīng)用程序只有一個(gè)根上下文,而應(yīng)用程序中的每個(gè)servlet(包括MVC框架中的調(diào)度程序servlet)都有自己的子上下文。除了標(biāo)準(zhǔn)的應(yīng)用程序上下文生命周期功能外,WebApplicationContext實(shí)現(xiàn)還需要檢測(cè){@link ServletContextAware} bean,并相應(yīng)地調(diào)用{@code setServletContext}方法


          public interface WebApplicationContext extends ApplicationContext {

            /**
            Context屬性,用于在成功啟動(dòng)時(shí)將根WebApplicationContext綁定到該屬性。* <p>注意:如果根上下文的啟動(dòng)失敗,則此屬性可以包含*異常或錯(cuò)誤作為值。使用WebApplicationContextUtils方便*查找根WebApplicationContext。
             */

            String ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".ROOT";

            /**
            請(qǐng)求范圍的范圍標(biāo)識(shí)符:“ request”。*除了標(biāo)準(zhǔn)范圍“ singleton”和“ prototype”之外,還受支持。
             */

            String SCOPE_REQUEST = "request";

            /**
            會(huì)話(huà)范圍的范圍標(biāo)識(shí)符:“session”。*除了標(biāo)準(zhǔn)范圍“ singleton”和“ prototype”之外,還受支持。
             */

            String SCOPE_SESSION = "session";

            /**
            全局Web應(yīng)用程序范圍的范圍標(biāo)識(shí)符:“application”。*除了標(biāo)準(zhǔn)范圍“ singleton”和“ prototype”之外,還受支持。
             */

            String SCOPE_APPLICATION = "application";

            /**
            工廠中ServletContext環(huán)境Bean的名稱(chēng)
             */

            String SERVLET_CONTEXT_BEAN_NAME = "servletContext";

            /**
            工廠中ServletContext init-params環(huán)境Bean的名稱(chēng)
             */

            String CONTEXT_PARAMETERS_BEAN_NAME = "contextParameters";

            /**
            工廠中ServletContext屬性環(huán)境bean的名稱(chēng)
             */

            String CONTEXT_ATTRIBUTES_BEAN_NAME = "contextAttributes";


            /**
            返回此應(yīng)用程序的標(biāo)準(zhǔn)Servlet API ServletContext
             */

            @Nullable
            ServletContext getServletContext();
          }


          WebApplicationContext的UML類(lèi)圖(從圖中可以發(fā)現(xiàn)WebApplicationContext擴(kuò)展了ApplicationContext的功能,ApplicationContext擴(kuò)展了BeanFactory的功能。)



          這幾個(gè)接口間的區(qū)別


          1.BeanFactory和ApplicationContext, WebApplicationContext初始化區(qū)別:BeanFactory在初始化容器時(shí)并沒(méi)有實(shí)例化Bean,而是在第一次訪問(wèn)到目標(biāo)Bean時(shí)才實(shí)例化該Bean;而ApplicationContext會(huì)在初始化上下文時(shí)實(shí)例化所有的單例的Bean。WebApplicationContext的初始化需要servletContext實(shí)例(getServletContext();),即初始化需要擁有web容器,我們需要在web.xml中配置自啟動(dòng)的servlet或web容器監(jiān)聽(tīng)器(servletContextListener)


          2.Bean的作用域


          在BeanFactory和ApplicationContext中的Bean的作用域有兩種:singleton和prototype,在WebApplicationContext中的Bean的作用域有三種:request,session和globalSession。

              

          • singleton:在IOC容器中僅存在一個(gè)Bean實(shí)例,Bean以單例方式存在,外部引用都指向這個(gè)Bean

          • prototype:每次調(diào)用Bean都返回一個(gè)新實(shí)例

          • request:在同一個(gè)Http請(qǐng)求的Bean相同,每個(gè)Http請(qǐng)求創(chuàng)建一個(gè)新的Bean。

          • session:在Http請(qǐng)求對(duì)應(yīng)同一個(gè)session時(shí)對(duì)應(yīng)同一個(gè)Bean。

          • globalSession:一般的web應(yīng)用中g(shù)lobalSession等價(jià)于session,只有在portlet web應(yīng)用中才存在globalSession概念。




          出處:https://blog.csdn.net/weixin_44313584/article/details/114785885








          關(guān)注GitHub今日熱榜,專(zhuān)注挖掘好用的開(kāi)發(fā)工具,致力于分享優(yōu)質(zhì)高效的工具、資源、插件等,助力開(kāi)發(fā)者成長(zhǎng)!







          點(diǎn)個(gè)在看 你最好看


          瀏覽 96
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国语对白中文字幕第二页 | 精品成人视频 | 亚洲日韩欧美动漫 | 99热思思 | 日韩人妻综合 |