IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Spring Bean的管理(IOC 依赖注入) -> 正文阅读

[Java知识库]Spring Bean的管理(IOC 依赖注入)

Spring Bean

bean是什么?
我们可以将Spring的Bean理解为在Spring框架下的对象。

基于xml的实现

bean标签里配置的是需要spring框架管理的类

bean标签里面都可以写
id :生成对象的名字,是唯一的

class:全类名(就是地址)

name:对象的别名,可以是多个

scope:范围,作用域
● singleton :单例,也是默认的,在容器中只讲对象创建一个,多次获取时也只是同一个,在Spring启动时就创建好了
● prototype :原型(多例),单个bean定义可以绑定到多个对象实例。
就是get一次,就创建一个对象。
● request:单个bean定义被绑定到当Http请求的生命周期上。就是每一次Http请求都是有属于自己的单独实例创建。仅用于 WebApplicationContext 环境
就是一个请求创建一个对象。
● session:单个bean的定义会绑定到Http Session的生命周期上。仅用于 WebApplicationContext 环境
一个会话,就创建一个对象。同一个 http session 共享一个 Bean, 不同 Session 使用不同的 Bean。
● application:带个bean的定义会绑定到 ServletContext的生命周期上。仅用于 WebApplicationContext 环境
整个应用程序只有这一个对象。
● websocket:单个bean的定义会绑定到WebSocket的生命周期中。仅用于 WebApplicationContext 环境
整个服务器中就创建一个对象。

代码演示:

package com.demo.spring.model;

public class User {

    private String name;
    private Integer age;

    public User(){
        System.out.println("这是User的无参构造方法");
    }


    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}

name定义别名的演示

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--配置我们项目中的类,配置进来后Spring就会对其进行管理(生成对象,存储)
        由Spring框架生成的这个对象就称为一个bean(特值Spring框架创建的对象,它会添加额外的功能)
    -->

    <bean id="user" name="user1,user2" class="com.demo.spring.model.User"></bean>

</beans>

测试代码

package com.demo.spring.test;

import com.demo.spring.model.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test1 {
    public static void main(String[] args) {

        //ApplicationContext是Spring的一个底层定义的接口,定义了一些接口
        //这个接口最终都会继承与BeanFactory
        //ClassPathXmlApplicationContext()是Spring中的一个具体落地实现的类,它就会创建并管理类
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        //现在是测试代码,所以就要启动ClassPathXmlApplicationContext,
        // 如果是web程序的话,就不用书写的,直接就可以启动的

        Object user = applicationContext.getBean("user");
        User user1 = (User) applicationContext.getBean("user1");
        //user1 user2 是通过name中而获得的 和id的意义一样
        User user2 = applicationContext.getBean("user2", User.class);

        System.out.println(user);
        System.out.println(user1);
        System.out.println(user2);
    }
}

通过name定义的别名都是可以调用到定义的bean标签。
在这里插入图片描述

scope作用域的演示

singleton 演示

在xml中的bean标签里加上scope="singleton"再执行测试代码

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--配置我们项目中的类,配置进来后Spring就会对其进行管理(生成对象,存储)
        由Spring框架生成的这个对象就称为一个bean(特值Spring框架创建的对象,它会添加额外的功能)
    -->

    <bean id="user" name="user1,user2" class="com.demo.spring.model.User" scope="singleton"></bean>

</beans>

在将测设代码,通过debug调试可以体现出singleton是在创建Spring时就创建好了对象。
在这里插入图片描述它只是创建了一个对象,每次拿到的是同一对象
在这里插入图片描述

prototype 演示

在xml中的bean标签里加上scope="prototype"再执行测试代码

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--配置我们项目中的类,配置进来后Spring就会对其进行管理(生成对象,存储)
        由Spring框架生成的这个对象就称为一个bean(特值Spring框架创建的对象,它会添加额外的功能)
    -->

    <bean id="user" name="user1,user2" class="com.demo.spring.model.User" scope="prototype"></bean>

</beans>

走测试代码,就可以明显的看出,它创建出了三个对象
在这里插入图片描述

xml配置方式的依赖注入(创建对象,为对象中的值赋值)

典型的企业级应用程序不会只有一个对象的(值Spring中的bean)。即使最简单的应用程序也有一些对象是一起工作的,最终传送到达前端的。

依赖项注入(DI:Dependency Injection)是指:对象仅仅通过构造函数的参数,工厂方法的参数或从工厂方法构造,或返回对象实例后在其上设置属性来定义依赖项(即它们使用的其他对象)。然后容器在创建bean时注入这些依赖项。这个过程基本上和bean通过直接类的构造器或服务定位器来定位其依赖的过程是相反的。(因此也称为了控制反转)

依赖(DI)和IOC可以说是同时存在的
IOC是在创建Spring的对象,DI是为依赖注入,为创建好的对象属性注入值。

依赖注入就是在Spring创建对象的时候,将对象的属性注入进去(就是赋值)
注入的方式有两种:

  1. 通过构造方法进行注入(采用这种的方式是比较少的)
  2. 通过set的方法进行注入
package com.demo.spring.model;

import java.util.List;

public class User {

    private String name;
    private Integer age;
    private List<Integer> list;

    public User() {
        System.out.println("这是User的无参构造方法");
    }

    public User(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        System.out.println("这是setName的方法");
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        System.out.println("这是setAge的方法");
        this.age = age;
    }

    public List<Integer> getList() {
        return list;
    }

    public void setList(List<Integer> list) {
        this.list = list;
    }

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

Test1类进行代码的测试验证

package com.demo.spring.test;

import com.demo.spring.model.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test1 {
    public static void main(String[] args) {

        //ApplicationContext是Spring的一个底层定义的接口,定义了一些接口
        //这个接口最终都会继承与BeanFactory
        //ClassPathXmlApplicationContext()是Spring中的一个具体落地实现的类,它就会创建并管理类
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        //现在是测试代码,所以就要启动ClassPathXmlApplicationContext,
        // 如果是web程序的话,就不用书写的,直接就可以启动的

        User user = applicationContext.getBean("user", User.class);

        System.out.println(user);

        //Spring的思想:IOC 就是把生成对象的控制权反转给Spring的框架
        //                在程序中需要对象的时候,直接从Spring容器中直接获取即可(也就是依赖输入)
    }
}

方式一:通过构造方式的注入属性值

在constructor-arg中 name是采用的是定义的赋值,type是值的是对象属性的数据类型,在采用属性的数据类型的时候如果是引用型的话,应该用去全类名(例如:java.lang.String。java.lang.Integer)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--配置我们项目中的类,配置进来后Spring就会对其进行管理(生成对象,存储)
        由Spring框架生成的这个对象就称为一个bean(特值Spring框架创建的对象,它会添加额外的功能)
    -->
    
    <!--第一种:通过构造方法进行传值-->
    <bean id="user" class="com.demo.spring.model.User">
        <constructor-arg name="name" value="Jim"></constructor-arg>
        <constructor-arg type="java.lang.Integer" value="15"></constructor-arg>
        <!--name就是通过定义的属性名进行赋值,type是通过属性的数据类型进行赋值-->
    </bean>
</beans>

在这里插入图片描述

方式二:通过set的方式注入属性的值

就是通过属性的名字将第一个字母大写拼上set构成以set的方式进行注入。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--配置我们项目中的类,配置进来后Spring就会对其进行管理(生成对象,存储)
        由Spring框架生成的这个对象就称为一个bean(特值Spring框架创建的对象,它会添加额外的功能)
    -->

    <!--第二种:通过set方法进行传值-->
    <bean id="user" class="com.demo.spring.model.User">
        <property name="name" value="Dark"></property>
        <property name="age" value="20"></property>
        <property name="list">
            <list>
                <value>1</value>
                <value>2</value>
                <value>3</value>
            </list>
        </property>
    </bean>
</beans>

在这里插入图片描述其他具体的可以结合官网的信息进行参考查询
在这里插入图片描述

set注入时用的ref (指向的是引用于另一个对象的使用)

这样就使得代码之间的依赖度更低,代码直接的关联也更加的方便。
这样在类中我们就可以不用去new对象,只需要标注一个对象类型的属性就可以了

package com.demo.spring.dao;

public class UserDao {

    public void save() {
        System.out.println("这是UserDao中的save方法");
    }
}
在这里通过在Spring的注入将UserDao赋给UserService中的userDao属性
然后在UserService中的直接使用
package com.demo.spring.service;

import com.demo.spring.dao.UserDao;

public class UserService {

    private UserDao userDao;

    public UserDao getUserDao() {
        return userDao;
    }

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    //在这里通过在Spring的注入将UserDao赋给UserService中的userDao属性
    // 然后在UserService中的直接使用
    public void saveUser() {
        System.out.println("这是UserService中的saveUser中的方法");
        userDao.save();
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--配置我们项目中的类,配置进来后Spring就会对其进行管理(生成对象,存储)
        由Spring框架生成的这个对象就称为一个bean(特值Spring框架创建的对象,它会添加额外的功能)
    -->

    <!--Spring 就管理了UserDao和UserService-->
    <bean id="userDao" class="com.demo.spring.dao.UserDao"></bean>
    <bean id="userService" class="com.demo.spring.service.UserService">
        <property name="userDao" ref="userDao"></property>
    </bean>
</beans>
package com.demo.spring.test;

import com.demo.spring.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test2 {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");

        UserService userService = applicationContext.getBean("userService",UserService.class);

        userService.saveUser();
    }
}

执行结构如下:
在这里插入图片描述

用注解的方式进行依赖注入(主流方式)

注解是在2.5之后出现的
因为我们在写一个项目的时候,如果要创建300个对象,那么我们就要写600个bean,实在是太麻烦了,所以出现了注解,就是为了方便。

那注解是不是就比xml更好呢?
每种方法都有其优缺点,通常情况下,是由开发人员决定哪种策略更适合它们。由于它们的定义方式,注解在其声明中提供了大量上下文,从而导致配置更简短。
然而,XML擅长在不接触源代码或重新编译组件的情况下注入组件。一些开发人员更喜欢将注入靠近源代码,而其他人则认为带注解的类不再POJO,而且配置变得分散且难以控制。
无论选择哪一种,Spring都能容纳这两种风格,甚至可以将它们混合在一起。

注解功能是封装在AOP包当中,我们只要导入Spring aop jar包即可,在用maven结构时,我们在导入spring包时,就已经在依赖的关系下,工具已经帮我们导入了aop包。
在这里插入图片描述
接下来在Spring的配置文件中加这个配置

注解创建对象

● @Component(value=“user”) 等同于< bean id=“user” class=“ ” >< /bean > 就是简答的组件,一般用在model类上用这个
● @Service
● @Repository 数据访问层
这三个标签的意思为都等同于< bean id=“user” class=“ ” >< /bean >
以上这些注解都可以实现创建对象功能,功能都是一样的。
只是为了后续扩展功能,用于区分而在不同的层使用不同的注解标记。

scope作用域的注解标签的添加

● @Scope(value=“prototype”) 原型
● @Scope(value=“ singleton ”) 单例

注解方式注入属性[DI:Dependency Injection]

@Autowired

@Autowired 是 Spring 提供的注解,是可以写在属性和 setter 方法上,也可以写在构造方法上。如果写在属性上,那么就不需要再写 setter 方法。默认情况下它要求依赖对象必须存在, 不能为null。
如果允许 null 值,可以设置它的 required 属性为 false。比如这样设置@Autowired(required = false)

再属性上直接添加

    @Autowired
    private UserDao userDao;

在setter方法上添加

    public UserDao getUserDao() {
        return userDao;
    }
    
    @Autowired
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

在构造方法上添加

    @Autowired
    public UserService(UserDao userDao) {
        this.userDao = userDao;
    }
byType自动注入

@Autowired默认是根据属性的类型进行自动注入(根据属性的类型在Spring的容器进行查找)

byName自动注入

如果我们想要根据名字去查找的话,就要结合@Qualifier 注解一起来使用。
@Qualifier (value = “名字”)

需要在引用属性上联合使用注解@Autowired 与@Qualifier一起来使用。@Qualifier 的 value 属性值是用于指定要匹配的 Bean 的 id 值。


代码演示

spring配置文件中只需要开启注解扫描就可以了

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd">
    <!--注意约束的添加-->


    <!--开启Spring的注解扫描解析它-->
    <!--写package一定要注意好自己的包名,在高级部分之下的都是可以扫描到的-->
    <context:component-scan base-package="com.demo.spring"></context:component-scan>
</beans>
package com.demo.spring.model;

import org.springframework.stereotype.Component;

import java.util.List;

@Component(value = "user")
//等同于<bean id="user class="com.demo.spring.model.User"></bean>
@Scope(value = "singleton")//指定生成对象的策略 为单列的
public class User {

    private String name;
    private Integer age;
    private List<Integer> list;

    public User() {
        System.out.println("这是User的无参构造方法");
    }

    public User(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        System.out.println("这是setName的方法");
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        System.out.println("这是setAge的方法");
        this.age = age;
    }

    public List<Integer> getList() {
        return list;
    }

    public void setList(List<Integer> list) {
        this.list = list;
    }
}
package com.demo.spring.dao;

import org.springframework.stereotype.Repository;

@Repository(value = "userDao")
public class UserDao {

    public void save() {
        System.out.println("这是UserDao中的save方法");
    }
}

根据值的属性进行赋值

package com.demo.spring.service;

import com.demo.spring.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service(value = "userService")
public class UserService {

    @Autowired//根据类型去匹配,使用这个时,连set方法都可以不用写,会直接注入进去
    private UserDao userDao;

    //在这里通过在Spring的注入将UserDao赋给UserService中的userDao属性
    // 然后在UserService中的直接使用
    public void saveUser() {
        System.out.println("这是UserService中的saveUser中的方法");
        userDao.save();
    }
}

测试代码

package com.demo.spring.test;

import com.demo.spring.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test2 {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");

        UserService userService = applicationContext.getBean("userService",UserService.class);

        userService.saveUser();
    }
}

在这里插入图片描述
2.根据getName来注入值

package com.demo.spring.service;

import com.demo.spring.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

@Service(value = "userService")
public class UserService {

    @Autowired
    @Qualifier(value = "userDao")//数据注入的方式是通过名字的来做出判断进行注入。
    private UserDao userDao;

    //在这里通过在Spring的注入将UserDao赋给UserService中的userDao属性
    // 然后在UserService中的直接使用
    public void saveUser() {
        System.out.println("这是UserService中的saveUser中的方法");
        userDao.save();
    }
}

在这里插入图片描述

@Resource

@Resource是jdk提供的注解用于自动注入
在Spring中也提供了对jdk中@Resource注解标签的支持。
@Resource 注解既可以按名称匹配 Bean,也可以按类型匹配 Bean。

@Resource(name = “userDao”)中name = "userDao"指定注入的对象名,比@Autowired比较,在通过name名查询的话,它只需要一行就可以了。
如果不加的话就按照数据类型来注入。

代码演示

通过byName注入

package com.demo.spring.service;

import com.demo.spring.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

@Service(value = "userService")
public class UserService {

    @Resource(name = "userDao")
    //是jdk自身提供的注解标签,也支持byName和ByType两种注入的方式
    //name = "userDao"指定注入的对象名
    //不加的话就按照数据类型来注入
    //相比@Autowired比较,在通过name名查询的话,它只需要一行就可以了
    private UserDao userDao;

    //在这里通过在Spring的注入将UserDao赋给UserService中的userDao属性
    // 然后在UserService中的直接使用
    public void saveUser() {
        System.out.println("这是UserService中的saveUser中的方法");
        userDao.save();
    }
}

运行Test方法

package com.demo.spring.test;

import com.demo.spring.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test2 {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");

        UserService userService = applicationContext.getBean("userService",UserService.class);

        userService.saveUser();
    }
}

是可以执行的
在这里插入图片描述
通过byType注入

package com.demo.spring.service;

import com.demo.spring.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

@Service(value = "userService")
public class UserService {

    @Resource
    //是jdk自身提供的注解标签,也支持byName和ByType两种注入的方式
    //不加的话就按照数据类型来注入
    private UserDao userDao;

    //在这里通过在Spring的注入将UserDao赋给UserService中的userDao属性
    // 然后在UserService中的直接使用
    public void saveUser() {
        System.out.println("这是UserService中的saveUser中的方法");
        userDao.save();
    }
}

在这里插入图片描述

xml与注解的对比

xml

● 优点是:配置和代码是分离的,在 xml 中做修改,无需编译代码,只需重 启服务器即可将新的配置加载。
● 缺点是:编写麻烦,效率低,大型项目过于复杂。

注解

● 优点:方便,直观,高效(代码少,没有配置文件的书写那么复杂)。
● 缺点:以硬编码的方式写入到 Java 代码中,修改后是需要重新编译代码的。

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-11-22 12:12:16  更:2021-11-22 12:14:46 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 2:43:15-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码