国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

spring6-實(shí)現(xiàn)簡易版IOC容器

這篇具有很好參考價(jià)值的文章主要介紹了spring6-實(shí)現(xiàn)簡易版IOC容器。希望對大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

我們都知道,Spring框架的IOC是基于Java反射機(jī)制實(shí)現(xiàn)的,下面我們先回顧一下java反射。

1、回顧Java反射

Java反射機(jī)制是在運(yùn)行狀態(tài)中,對于任意一個(gè)類,都能夠知道這個(gè)類的所有屬性和方法;對于任意一個(gè)對象,都能夠調(diào)用它的任意方法和屬性;這種動態(tài)獲取信息以及動態(tài)調(diào)用對象方法的功能稱為Java語言的反射機(jī)制。簡單來說,反射機(jī)制指的是程序在運(yùn)行時(shí)能夠獲取自身的信息。

要想解剖一個(gè)類,必須先要獲取到該類的Class對象。而剖析一個(gè)類或用反射解決具體的問題就是使用相關(guān)API**(1)java.lang.Class(2)java.lang.reflect**,所以,Class對象是反射的根源。

自定義類

package com.atguigu.reflect;

public class Car {

    //屬性
    private String name;
    private int age;
    private String color;

    //無參數(shù)構(gòu)造
    public Car() {
    }

    //有參數(shù)構(gòu)造
    public Car(String name, int age, String color) {
        this.name = name;
        this.age = age;
        this.color = color;
    }

    //普通方法
    private void run() {
        System.out.println("私有方法-run.....");
    }

    //get和set方法
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getColor() {
        return color;
    }
    public void setColor(String color) {
        this.color = color;
    }

    @Override
    public String toString() {
        return "Car{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", color='" + color + '\'' +
                '}';
    }
}

編寫測試類

package com.atguigu.reflect;

import org.junit.jupiter.api.Test;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class TestCar {

    //1、獲取Class對象多種方式
    @Test
    public void test01() throws Exception {
        //1 類名.class
        Class clazz1 = Car.class;

        //2 對象.getClass()
        Class clazz2 = new Car().getClass();

        //3 Class.forName("全路徑")
        Class clazz3 = Class.forName("com.atguigu.reflect.Car");

        //實(shí)例化
        Car car = (Car)clazz3.getConstructor().newInstance();
        System.out.println(car);
    }

    //2、獲取構(gòu)造方法
    @Test
    public void test02() throws Exception {
        Class clazz = Car.class;
        //獲取所有構(gòu)造
        // getConstructors()獲取所有public的構(gòu)造方法
//        Constructor[] constructors = clazz.getConstructors();
        // getDeclaredConstructors()獲取所有的構(gòu)造方法public  private
        Constructor[] constructors = clazz.getDeclaredConstructors();
        for (Constructor c:constructors) {
            System.out.println("方法名稱:"+c.getName()+" 參數(shù)個(gè)數(shù):"+c.getParameterCount());
        }

        //指定有參數(shù)構(gòu)造創(chuàng)建對象
        //1 構(gòu)造public
//        Constructor c1 = clazz.getConstructor(String.class, int.class, String.class);
//        Car car1 = (Car)c1.newInstance("夏利", 10, "紅色");
//        System.out.println(car1);
        
        //2 構(gòu)造private
        Constructor c2 = clazz.getDeclaredConstructor(String.class, int.class, String.class);
        c2.setAccessible(true);
        Car car2 = (Car)c2.newInstance("捷達(dá)", 15, "白色");
        System.out.println(car2);
    }

    //3、獲取屬性
    @Test
    public void test03() throws Exception {
        Class clazz = Car.class;
        Car car = (Car)clazz.getDeclaredConstructor().newInstance();
        //獲取所有public屬性
        //Field[] fields = clazz.getFields();
        //獲取所有屬性(包含私有屬性)
        Field[] fields = clazz.getDeclaredFields();
        for (Field field:fields) {
            if(field.getName().equals("name")) {
                //設(shè)置允許訪問
                field.setAccessible(true);
                field.set(car,"五菱宏光");
                System.out.println(car);
            }
            System.out.println(field.getName());
        }
    }

    //4、獲取方法
    @Test
    public void test04() throws Exception {
        Car car = new Car("奔馳",10,"黑色");
        Class clazz = car.getClass();
        //1 public方法
        Method[] methods = clazz.getMethods();
        for (Method m1:methods) {
            //System.out.println(m1.getName());
            //執(zhí)行方法 toString
            if(m1.getName().equals("toString")) {
                String invoke = (String)m1.invoke(car);
                //System.out.println("toString執(zhí)行了:"+invoke);
            }
        }

        //2 private方法
        Method[] methodsAll = clazz.getDeclaredMethods();
        for (Method m:methodsAll) {
            //執(zhí)行方法 run
            if(m.getName().equals("run")) {
                m.setAccessible(true);
                m.invoke(car);
            }
        }
    }
}

2、實(shí)現(xiàn)Spring的IoC

我們知道,IoC(控制反轉(zhuǎn))和DI(依賴注入)是Spring里面核心的東西,那么,我們?nèi)绾巫约菏謱懗鲞@樣的代碼呢?下面我們就一步一步寫出Spring框架最核心的部分。

①搭建子模塊

搭建模塊:guigu-spring,搭建方式如其他spring子模塊

②準(zhǔn)備測試需要的bean

添加依賴

<dependencies>
    <!--junit5測試-->
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-api</artifactId>
        <version>5.3.1</version>
    </dependency>
</dependencies>

創(chuàng)建UserDao接口

package com.atguigu.spring6.test.dao;

public interface UserDao {

    public void print();
}

創(chuàng)建UserDaoImpl實(shí)現(xiàn)

package com.atguigu.spring6.test.dao.impl;

import com.atguigu.spring.dao.UserDao;

public class UserDaoImpl implements UserDao {

    @Override
    public void print() {
        System.out.println("Dao層執(zhí)行結(jié)束");
    }
}

創(chuàng)建UserService接口

package com.atguigu.spring6.test.service;

public interface UserService {

    public void out();
}

創(chuàng)建UserServiceImpl實(shí)現(xiàn)類

package com.atguigu.spring.test.service.impl;

import com.atguigu.spring.core.annotation.Bean;
import com.atguigu.spring.service.UserService;

@Bean
public class UserServiceImpl implements UserService {

//    private UserDao userDao;

    @Override
    public void out() {
        //userDao.print();
        System.out.println("Service層執(zhí)行結(jié)束");
    }
}

③定義注解

我們通過注解的形式加載bean與實(shí)現(xiàn)依賴注入

bean注解

package com.atguigu.spring.core.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Bean {
}

依賴注入注解

package com.atguigu.spring.core.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Di {
}

說明:上面兩個(gè)注解可以隨意取名

④定義bean容器接口

package com.atguigu.spring.core;

public interface ApplicationContext {

    Object getBean(Class clazz);
}

⑤編寫注解bean容器接口實(shí)現(xiàn)

AnnotationApplicationContext基于注解掃描bean

package com.atguigu.spring.core;

import java.util.HashMap;

public class AnnotationApplicationContext implements ApplicationContext {

    //存儲bean的容器
    private HashMap<Class, Object> beanFactory = new HashMap<>();

    @Override
    public Object getBean(Class clazz) {
        return beanFactory.get(clazz);
    }

    /**
     * 根據(jù)包掃描加載bean
     * @param basePackage
     */
    public AnnotationApplicationContext(String basePackage) {
        
    }
}

⑥編寫掃描bean邏輯

我們通過構(gòu)造方法傳入包的base路徑,掃描被@Bean注解的java對象,完整代碼如下:

package com.atguigu.spring.core;

import com.atguigu.spring.core.annotation.Bean;

import java.io.File;
import java.util.HashMap;

public class AnnotationApplicationContext implements ApplicationContext {

    //存儲bean的容器
    private HashMap<Class, Object> beanFactory = new HashMap<>();
    private static String rootPath;

    @Override
    public Object getBean(Class clazz) {
        return beanFactory.get(clazz);
    }

    /**
     * 根據(jù)包掃描加載bean
     * @param basePackage
     */
    public AnnotationApplicationContext(String basePackage) {
       try {
            String packageDirName = basePackage.replaceAll("\\.", "\\\\");
            Enumeration<URL> dirs =Thread.currentThread().getContextClassLoader().getResources(packageDirName);
            while (dirs.hasMoreElements()) {
                URL url = dirs.nextElement();
                String filePath = URLDecoder.decode(url.getFile(),"utf-8");
                rootPath = filePath.substring(0, filePath.length()-packageDirName.length());
                loadBean(new File(filePath));
            }

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private  void loadBean(File fileParent) {
        if (fileParent.isDirectory()) {
            File[] childrenFiles = fileParent.listFiles();
            if(childrenFiles == null || childrenFiles.length == 0){
                return;
            }
            for (File child : childrenFiles) {
                if (child.isDirectory()) {
                    //如果是個(gè)文件夾就繼續(xù)調(diào)用該方法,使用了遞歸
                    loadBean(child);
                } else {
                    //通過文件路徑轉(zhuǎn)變成全類名,第一步把絕對路徑部分去掉
                    String pathWithClass = child.getAbsolutePath().substring(rootPath.length() - 1);
                    //選中class文件
                    if (pathWithClass.contains(".class")) {
                        //    com.xinzhi.dao.UserDao
                        //去掉.class后綴,并且把 \ 替換成 .
                        String fullName = pathWithClass.replaceAll("\\\\", ".").replace(".class", "");
                        try {
                            Class<?> aClass = Class.forName(fullName);
                            //把非接口的類實(shí)例化放在map中
                            if(!aClass.isInterface()){
                                Bean annotation = aClass.getAnnotation(Bean.class);
                                if(annotation != null){
                                    Object instance = aClass.newInstance();
                                    //判斷一下有沒有接口
                                    if(aClass.getInterfaces().length > 0) {
                                        //如果有接口把接口的class當(dāng)成key,實(shí)例對象當(dāng)成value
                                        System.out.println("正在加載【"+ aClass.getInterfaces()[0] +"】,實(shí)例對象是:" + instance.getClass().getName());
                                        beanFactory.put(aClass.getInterfaces()[0], instance);
                                    }else{
                                        //如果有接口把自己的class當(dāng)成key,實(shí)例對象當(dāng)成value
                                        System.out.println("正在加載【"+ aClass.getName() +"】,實(shí)例對象是:" + instance.getClass().getName());
                                        beanFactory.put(aClass, instance);
                                    }
                                }
                            }
                        } catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }

}

⑦java類標(biāo)識Bean注解

@Bean
public class UserServiceImpl implements UserService
@Bean
public class UserDaoImpl implements UserDao 

⑧測試Bean加載

package com.atguigu.spring;

import com.atguigu.spring.core.AnnotationApplicationContext;
import com.atguigu.spring.core.ApplicationContext;
import com.atguigu.spring.test.service.UserService;
import org.junit.jupiter.api.Test;

public class SpringIocTest {

    @Test
    public void testIoc() {
        ApplicationContext applicationContext = new AnnotationApplicationContext("com.atguigu.spring.test");
        UserService userService = (UserService)applicationContext.getBean(UserService.class);
        userService.out();
        System.out.println("run success");
    }
}

控制臺打印測試

⑨依賴注入

只要userDao.print();調(diào)用成功,說明就注入成功

package com.atguigu.spring.test.service.impl;

import com.atguigu.spring.core.annotation.Bean;
import com.atguigu.spring.core.annotation.Di;
import com.atguigu.spring.dao.UserDao;
import com.atguigu.spring.service.UserService;

@Bean
public class UserServiceImpl implements UserService {

    @Di
    private UserDao userDao;

    @Override
    public void out() {
        userDao.print();
        System.out.println("Service層執(zhí)行結(jié)束");
    }
}

執(zhí)行第八步:報(bào)錯(cuò)了,說明當(dāng)前userDao是個(gè)空對象

⑩依賴注入實(shí)現(xiàn)

package com.atguigu.spring.core;

import com.atguigu.spring.core.annotation.Bean;
import com.atguigu.spring.core.annotation.Di;

import java.io.File;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

public class AnnotationApplicationContext implements ApplicationContext {

    //存儲bean的容器
    private HashMap<Class, Object> beanFactory = new HashMap<>();
    private static String rootPath;

    @Override
    public Object getBean(Class clazz) {
        return beanFactory.get(clazz);
    }

    /**
     * 根據(jù)包掃描加載bean
     * @param basePackage
     */
    public AnnotationApplicationContext(String basePackage) {
        try {
            String packageDirName = basePackage.replaceAll("\\.", "\\\\");
            Enumeration<URL> dirs =Thread.currentThread().getContextClassLoader().getResources(packageDirName);
            while (dirs.hasMoreElements()) {
                URL url = dirs.nextElement();
                String filePath = URLDecoder.decode(url.getFile(),"utf-8");
                rootPath = filePath.substring(0, filePath.length()-packageDirName.length());
                loadBean(new File(filePath));
            }

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        
        //依賴注入
        loadDi();
    }
    
    private  void loadBean(File fileParent) {
        if (fileParent.isDirectory()) {
            File[] childrenFiles = fileParent.listFiles();
            if(childrenFiles == null || childrenFiles.length == 0){
                return;
            }
            for (File child : childrenFiles) {
                if (child.isDirectory()) {
                    //如果是個(gè)文件夾就繼續(xù)調(diào)用該方法,使用了遞歸
                    loadBean(child);
                } else {
                    //通過文件路徑轉(zhuǎn)變成全類名,第一步把絕對路徑部分去掉
                    String pathWithClass = child.getAbsolutePath().substring(rootPath.length() - 1);
                    //選中class文件
                    if (pathWithClass.contains(".class")) {
                        //    com.xinzhi.dao.UserDao
                        //去掉.class后綴,并且把 \ 替換成 .
                        String fullName = pathWithClass.replaceAll("\\\\", ".").replace(".class", "");
                        try {
                            Class<?> aClass = Class.forName(fullName);
                            //把非接口的類實(shí)例化放在map中
                            if(!aClass.isInterface()){
                                Bean annotation = aClass.getAnnotation(Bean.class);
                                if(annotation != null){
                                    Object instance = aClass.newInstance();
                                    //判斷一下有沒有接口
                                    if(aClass.getInterfaces().length > 0) {
                                        //如果有接口把接口的class當(dāng)成key,實(shí)例對象當(dāng)成value
                                        System.out.println("正在加載【"+ aClass.getInterfaces()[0] +"】,實(shí)例對象是:" + instance.getClass().getName());
                                        beanFactory.put(aClass.getInterfaces()[0], instance);
                                    }else{
                                        //如果有接口把自己的class當(dāng)成key,實(shí)例對象當(dāng)成value
                                        System.out.println("正在加載【"+ aClass.getName() +"】,實(shí)例對象是:" + instance.getClass().getName());
                                        beanFactory.put(aClass, instance);
                                    }
                                }
                            }
                        } catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }

    private void loadDi() {
        for(Map.Entry<Class,Object> entry : beanFactory.entrySet()){
            //就是咱們放在容器的對象
            Object obj = entry.getValue();
            Class<?> aClass = obj.getClass();
            Field[] declaredFields = aClass.getDeclaredFields();
            for (Field field : declaredFields){
                Di annotation = field.getAnnotation(Di.class);
                if( annotation != null ){
                    field.setAccessible(true);
                    try {
                        System.out.println("正在給【"+obj.getClass().getName()+"】屬性【" + field.getName() + "】注入值【"+ beanFactory.get(field.getType()).getClass().getName() +"】");
                        field.set(obj,beanFactory.get(field.getType()));
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

}

執(zhí)行第八步:執(zhí)行成功,依賴注入成功文章來源地址http://www.zghlxwxcb.cn/news/detail-713617.html

到了這里,關(guān)于spring6-實(shí)現(xiàn)簡易版IOC容器的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 【Spring6】| Spring IoC注解式開發(fā)

    【Spring6】| Spring IoC注解式開發(fā)

    目錄 一:Spring IoC注解式開發(fā) 1.?回顧注解 2.?聲明Bean的四個(gè)注解 3.?Spring注解的使用 4.?選擇性實(shí)例化Bean 5.?負(fù)責(zé)注入的注解(重點(diǎn)) 5.1 @Value 5.2?@Autowired與@Qualifier 5.3?@Resource 6.?全注解式開發(fā) 注解的存在主要是為了簡化XML的配置 ,Spring6倡導(dǎo)全注解開發(fā)。 我們來回顧一下:

    2023年04月12日
    瀏覽(25)
  • 2023新版Spring6全新講解-核心內(nèi)容之IoC

    2023新版Spring6全新講解-核心內(nèi)容之IoC

    ??IoC 是 Inversion of Control 的簡寫,譯為“控制反轉(zhuǎn)”,它不是一門技術(shù),而是一種設(shè)計(jì)思想,是一個(gè)重要的面向?qū)ο缶幊谭▌t,能夠指導(dǎo)我們?nèi)绾卧O(shè)計(jì)出松耦合、更優(yōu)良的程序。 ??Spring 通過 IoC 容器來管理所有 Java 對象的實(shí)例化和初始化,控制對象與對象之間的依賴關(guān)系

    2024年02月06日
    瀏覽(18)
  • Spring6學(xué)習(xí)技術(shù)|IoC+基于xml管理bean

    Spring6學(xué)習(xí)技術(shù)|IoC+基于xml管理bean

    尚硅谷Spring零基礎(chǔ)入門到進(jìn)階,一套搞定spring6全套視頻教程(源碼級講解) 控制反轉(zhuǎn)。是一種設(shè)計(jì)思想。 通過id,通過class,和雙重方式。 普通屬性:String, Interger (set和構(gòu)造器:感覺還是set比較方便) 特殊屬性:null,特殊的大于小于等(xml轉(zhuǎn)義字符,cdata) 對象:外部

    2024年02月21日
    瀏覽(28)
  • Spring Framework的核心:IoC容器的實(shí)現(xiàn)(1)

    Spring Framework的核心:IoC容器的實(shí)現(xiàn)(1)

    個(gè)人名片: ?? 作者簡介:一名大二在校生 ????? 個(gè)人主頁:落798. ?? 個(gè)人WeChat:落798. ??? 系列專欄: 零基礎(chǔ)學(xué)java ----- 重識c語言 ---- 計(jì)算機(jī)網(wǎng)絡(luò) — 【Spring技術(shù)內(nèi)幕】 ?? 每日一句: 看淡一點(diǎn)在努力,你吃的苦會鋪成你要的路! Spring 容器是 Spring 框架的核心。 容

    2024年02月15日
    瀏覽(25)
  • Spring IOC容器:讓Java對象的管理和配置更簡單

    在Java開發(fā)中,我們經(jīng)常需要創(chuàng)建和使用各種Java對象,例如實(shí)體類,服務(wù)類,控制器類等。這些對象之間通常存在著一定的依賴關(guān)系,例如一個(gè)服務(wù)類可能需要調(diào)用另一個(gè)服務(wù)類或一個(gè)數(shù)據(jù)訪問類的方法。為了創(chuàng)建和使用這些對象,我們通常需要做以下幾件事: 在代碼中通過

    2024年02月11日
    瀏覽(24)
  • Spring中IOC容器常用的接口和具體的實(shí)現(xiàn)類

    在Spring框架沒有出現(xiàn)之前,在Java語言中,程序員們創(chuàng)建對象一般都是通過new來完成,那時(shí)流行一句話“萬物即可new,包括女朋友”。但是這種創(chuàng)建對象的方式維護(hù)成本很高,而且對于類之間的相互關(guān)聯(lián)關(guān)系很不友好。鑒于這種情況,Spring框架應(yīng)運(yùn)而生,Spring框架絕對是

    2024年02月15日
    瀏覽(15)
  • Spring IoC容器、IoC與DI

    Spring IoC容器、IoC與DI

    目錄 Spring是什么? 理解容器? 什么是IoC(Inversion of Control) 傳統(tǒng)的new創(chuàng)建對象的方式中類與類的耦合程度很大。? IoC的優(yōu)勢:? Spring IoC容器最核心的功能? 什么是DI (Dependency Injection) IoC和DI的區(qū)別? Spring是指Spring Framework(Spring框架),它是開源的框架,有著很龐大的社區(qū),通過

    2023年04月21日
    瀏覽(25)
  • Spring核心容器IOC案例講解,帶你理解IOC

    Universe Infinity inc. 什么是IOC容器,先把IOC給忽略到,其實(shí)就是個(gè)容器。 什么?容器又是個(gè)啥玩意?容器是用來放東西的東西啊。 各個(gè)領(lǐng)域都喜歡起一些專業(yè)術(shù)語,顯得很高級。給你講IOC是不是很高級,給你講Map是不是就明白了。 bean對象最終存儲在spring容器中,在spring源碼底

    2024年01月24日
    瀏覽(20)
  • spring ioc容器

    ioc是 inversion of Control的簡寫,意為控制反轉(zhuǎn)。通過其對所有的Java對象的實(shí)例化和初始化,控制對象與對象之間的依賴關(guān)系。 (1)控制反轉(zhuǎn)是一種思想。 (2)控制反轉(zhuǎn)是為了 降低程序耦合度,提高程序擴(kuò)展力。 (3)控制反轉(zhuǎn),反轉(zhuǎn)的是什么? 答:將對象的創(chuàng)建權(quán)利交出去

    2024年01月17日
    瀏覽(17)
  • 3、Spring 之IOC 容器 詳解

    3、Spring 之IOC 容器 詳解

    IoC 是 Inversion of Control 的簡寫,譯為“控制反轉(zhuǎn)”,它不是一門技術(shù),而是一種 設(shè)計(jì)思想 ,是一個(gè)重要的面向?qū)ο缶幊谭▌t,能夠指導(dǎo)我們?nèi)绾卧O(shè)計(jì)出松耦合、更優(yōu)良的程序。 Spring 通過 IoC 容器 來管理 所有 Java 對象的實(shí)例化和初始化 , 控制對象與對象之間的依賴關(guān)系 。我

    2024年02月09日
    瀏覽(16)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包