Spring

Spring概述

Spirng是一个企业级开发框架,是软件设计层面的框架,优势在于可以将应用程序进行分层,开发者可以自主选择组件。

Spring提供了各个层面的解决方案:

MVC:Strts2、Spring MVC

ORM:Hibernate、MyBatis、Spirng Data

Spring两大核心机制:IoC(控制反转)、AOP(面向切面)

Spirng的优点:

  • 低侵入式设计

  • 独立于各个应用服务器

  • 依赖注入特性将组件关系透明化,降低了耦合度

  • 面向切面编程特性允许将通用任务进行集中式处理

  • 与第三方框架的良好整合

Spring体系结构:

  • 核心容器

  • Spring上下文

  • Spirng AOP

  • Spirng DAO

  • Spring ORM

  • Spirng Web模块

  • Spring MVC框架

总结:Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器(框架)。

Spring IoC概述与简单使用

  1. 什么是控制反转

    在传统开发中,需要调用对象时,通常由调用者来创建被调用者的实例,即对象是由调用者主动new出来的。

    但在Spring框架中创建对象的工作不再由调用者完成,而是交给Ioc容器来创建,再推送给调用者,整个流程完成反转,所以是控制反转。

  2. IOC的简单使用

    • 创建maven工程,导入相关依赖

       <dependency> 
           <groupId>org.springframework</groupId>
           <artifactId>spring-webmvc</artifactId>
           <version>5.1.10.RELEASE</version>
       </dependency>

      这里只需要导入这一个依赖包就够了,因为这个依赖的导入会导致所有spring相关的依赖都被导入,下边是依赖图

    • 创建实体类

       package com.jarreet.pojo;
       
       import lombok.Data;
       
       @Data
       public class Student {
       
           private int id;
           private String name;
           private int age;
       }
    • 在配置文件中添加需要管理的对象,XML格式的配置 文件,文件名可自定义

       <?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
               类型 变量名 = new Hello();
               Hello hello = new Hello();
       
               id = 变量名
               class = new 的对象
               property 相当于给对象中的属性设置一个值
            -->
       
           <!-- 1 配置Student对象创建 -->
           <!-- 2 set方法注入属性 -->
           <bean id="student" class="com.jarreet.pojo.Student">
               <!-- 使用property完成属性注入
                   name:类里面属性名称
                   value:向属性注入的具体的值(基本数据类型)
                   ref:引用Spring容器中创建好的对象
                -->
               <property name="id" value="1"/>
               <property name="name" value="Jarreet"/>
               <property name="age" value="22"/>
           </bean>
       </beans>
    • 从IOC中获取对象

           @Test
           public void MyTest(){
               // 1 加载spring配置文件,获取spring的上下文对象
               ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
       
               // 我们的对象现在都在Spring中管理了,我们要使用,直接去里面取出来就可以了
               // 2 获取配置创建的对象(通过id获取)
               Student student = (Student) context.getBean("student");
               
               /* 还可通过其他方式获取bean
               ** 1、运行时类获取bean,但是这种方式配置文件中一个数据类型的对象只能有一个实例
               ** Student student = (Student) context.getBean(Student.class);
               ** 2、通过有参构造获取bean,使用这种方式,注入bean时应使用<constructor-arg></constructor-arg>
               ** Student student = (Student) context.getBean("student");
               */
               
               System.out.println(student.toString());
          }

      测试结果:

Spring IoC配置文件详解

  • spring ioc 通过配置 <bean></bean> 标签来完成对象的管理

    • id:对象名

    • class:对象的模板类(所有交给ioc容器来管理的类必须有无参构造函数,因为Spring底层是通过反射机制来创建对象的,调用的是无参构造)

  • 对象的成员变量通过<property></property>标签完成赋值

    • name:成员变量名

    • value:成员变量的值(基本数据类型,String)

    • ref:将ioc中的另外一个bean赋给当前的成员变量(DI:依赖注入)

       <bean id="student" class="com.jarreet.pojo.Student">
               <!-- 使用property完成属性注入
                   name:类里面属性名称
                   value:向属性注入的具体的值(基本数据类型)
                   ref:引用Spring容器中创建好的对象
                -->
               <property name="id" value="1"/>
               <property name="name" value="Jarreet"/>
               <property name="age" value="22"/>
          <!-- 将address注入 -->
               <property name="address" ref="address"/>
           </bean>
       
           <bean id="address" class="com.jarreet.pojo.Address">
               <property name="id" value="1"/>
               <property name="name" value="FuZhou"/>
           </bean>
  • 给bean注入集合

    • 修改实体类

       package com.jarreet.pojo;
       
       import lombok.Data;
       import java.util.List;
       
       @Data
       public class Student {
       
           private int id;
           private String name;
           private int age;
           private List<Address> addresses;
       }
    • 修改xml

           <!-- 1 配置Student对象创建  -->
           <!-- 2 set方法注入属性 -->
           <bean id="student" class="com.jarreet.pojo.Student">
               <!-- 使用property完成属性注入
                   name:类里面属性名称
                   value:向属性注入的具体的值(基本数据类型)
                   ref:引用Spring容器中创建好的对象
                -->
               <property name="id" value="1"/>
               <property name="name" value="Jarreet"/>
               <property name="age" value="22"/>
               <property name="addresses">
                   <list>
                       <ref bean="address1"></ref>
                       <ref bean="address2"></ref>
                   </list>
                   <!--
        此处如果不是注入集合,二是注入数组、Map、Set、Properties、Null也是类似的方法,知识标签不同
        1、注入数组,使用
        <array>
        <value></value>
        </array>
        2、注入Map,使用
        <map>
        <entry key="" value=""/>
        </map>
        3、注入Set,使用
        <set>
        <value></value>
        </set>
        4、注入Properties,使用
        <props>
        <prop key=""></prop>
        </props>
        5、注入Null
        <property name="wife"><null/></property>
        -->
               </property>
           </bean>
       
           <bean id="address1" class="com.jarreet.pojo.Address">
               <property name="id" value="1"/>
               <property name="name" value="FuZhou"/>
           </bean>
       
           <bean id="address2" class="com.jarreet.pojo.Address">
               <property name="id" value="2"/>
               <property name="name" value="XiaMen"/>
           </bean>

IoC底层原理

  1. 读取配置文件,解析XML

  2. 通过反射机制来实例化配置文件中所配置的Bean

下面我们模拟IOC的实现过程:

scope 作用域

Spring管理的bean是根据scope来生成的,表示bean的作用域,共4种,其默认值是singleton

  • singleton:单例,表示Spring容器获取的bean是唯一的

  • prototype:原型,表示通过Spring容器获取的bean是不同的

  • request:请求,表示在一次HTTP请求内有效

  • session:会话,表示在一个用户会话内有效

request和session只适用于Web项目,大多数情况下,使用单例和原型较多;

prototype模式当业务代码获取IoC容器中的bean时,Spring才去调用无参构造创建对应的bean;

singleton模式无论业务代码是否获取IoC容器中的bean,Spring在加载spring-xml时就会创建bean

Spring的继承

与java的继承不同,java是类层面的继承,子类可以继承父类的内部结构信息;Spring是对象层面的继承,子对象可以继承父对象的属性值。

 <!-- stu继承student -->
 <bean id="stu" class="com.jarreet.pojo.Student" parent="student">
     <!-- 子对象可对属性进行重写 -->
     <property name="name" value="LiYuan"/>
 </bean>

值得注意的是,Spring的继承关注点在于具体的对象,而不在于类,即不同的两个类的实例化对象可以完成继承,前提是子对象必须包含父对象的所有属性,同时可以在此基础之上添加其他的属性。

package com.jarreet.pojo;

import lombok.Data;
import java.util.List;

@Data
public class User {

private int id;
private String name;
private String password;
private int age;
private List<Address> addresses;
}
<!-- user继承student -->
<bean id="user" class="com.jarreet.pojo.User" parent="student">
<!-- 子对象可对属性进行重写、添加新的属性 -->
<property name="name" value="LiYuan"/>
<property name="password" value="123456"/>
</bean>

Spirng的依赖

与继承类似,依赖也是描述bean和bean之间关系一种关系,配置依赖以后,被依赖的bean一定先创建,再创建依赖的bean,A依赖于B,先创建B在创建A。

<bean id="user" class="com.jarreet.pojo.User" depends-on="student"></bean>
<bean id="student" class="com.jarreet.pojo.Student"></bean>

这里user依赖于student,所以在调用user时,会先调用student;如果没有依赖,则会直接调用user。

Spring的p命名空间

p命名空间是对 IoC/DI 的简化操作,使用p命名空间可以更加方便地完成bean的配置以及bean之间的依赖注入。使用p命名空间,需要在XML的头文件中导入约束xmlns:p="http://www.springframework.org/schema/p"

<bean id="student" class="com.jarreet.pojo.Student" p:id="1" p:name="Jarreet" p:age="22" p:address-ref="address"></bean>
<bean id="address" class="com.jarreet.pojo.Address" p:id="1" p:name="FuZhou"></bean>

Spring的工厂方法

IoC通过工厂模式创建bean的方式有两种:静态工厂方法和实例工厂方法。下面使用一个例子说明:

实体类Car:

package com.jarreet.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Car {
private int id;
private String name;
}
  • 静态工厂方法

    静态工厂类:

    package com.kuang.factory;

    import com.jarreet.pojo.Car;
    import java.util.HashMap;
    import java.util.Map;

    public class StaticCarFactory {
    private static Map<Integer, Car> carMap;
    static {
    carMap = new HashMap<Integer, Car>();
    carMap.put(1, new Car(1,"BWM"));
    carMap.put(2, new Car(1,"BenZ"));
    }

    public static Car getCar(int id){
    return carMap.get(id);
    }
    }

    XML文件:

    <?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">

    <!-- 配置静态工厂创建 Car -->
    <bean id="car" class="com.jarreet.factory.StaticCarFactory" factory-method="getCar">
    <constructor-arg value="1"></constructor-arg>
    </bean>

    </beans>

    调用:

        @Test
    public void testFactory(){
    ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
    Car car = (Car) context.getBean("car");
    System.out.println(car);
    }

    测试结果:

  • 实例工厂方法

    实例工厂类:

    package com.jarreet.factory;

    import com.kuang.pojo.Car;
    import java.util.HashMap;
    import java.util.Map;

    public class InstanceCarFactory {
    private Map<Integer, Car> carMap;
    public InstanceCarFactory(){
    carMap = new HashMap<Integer, Car>();
    carMap.put(1, new Car(1,"BWL"));
    carMap.put(2, new Car(2,"BenZ"));
    }

    public Car getCar(int id){
    return carMap.get(id);
    }
    }

    XML文件:

    <?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">

    <!-- 配置实例工厂bean -->
    <bean id="carFactory" class="com.jarreet.factory.InstanceCarFactory"></bean>

    <!-- 配置实例工厂创建car -->
    <bean id="car" factory-bean="carFactory" factory-method="getCar">
    <constructor-arg value="2"></constructor-arg>
    </bean>
    </beans>

    调用:

        @Test
    public void testFactory(){
    ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
    Car car = (Car) context.getBean("car");
    System.out.println(car);
    }

    测试结果:

IoC自动装配(Autowire)

IoC负责创建对象,DI负责完成对象的依赖注入,通过配置property标签的ref属性来完成,同时spring提供了一种更加简便的依赖注入方式:自动装载,不需要手动配置property,IoC容器会自动选择bean完成注入。

自动装配有两种方式:

  • byName:通过属性名自动装配

        <bean id="car" class="com.kuang.pojo.Car">
    <property name="id" value="1"></property>
    <property name="name" value="BWM"></property>
    </bean>

    <bean id="person" class="com.kuang.pojo.Person" autowire="byName">
    <property name="id" value="1"></property>
    <property name="name" value="Jarreet"></property>
    </bean>
  • byType:通过属性的数据类型自动装配

        <bean id="car" class="com.kuang.pojo.Car">
    <property name="id" value="1"></property>
    <property name="name" value="BWM"></property>
    </bean>

    <bean id="person" class="com.kuang.pojo.Person" autowire="byType">
    <property name="id" value="1"></property>
    <property name="name" value="Jarreet"></property>
    </bean>

    byType需要注意,如果同时存在两个及以上的符合条件的bean时,自动装配会抛出异常。

使用注解开发

  1. 使用注解需要引入aop依赖

  2. 在配置文件中需要引入一个context约束

    <?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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    </beans>
  3. bean的实现

    • 配置扫描哪些包下的注解

          <context:component-scan base-package="com.jarreet.pojo"/>
      <context:annotation-config/>
    • 在指定包下编写类,增加注解并进行属性注入

      package com.jarreet.pojo;

      import org.springframework.beans.factory.annotation.Value;
      import org.springframework.stereotype.Component;

      // 等价于 <bean id="user" class="com.kuang.pojo.User"/>
      // @Component 组件

      @Component
      @Data
      public class User {
      // 等价于 <property name="name" value="ZhangSan"/>
      @Value("Jarreet")
      private String name;

      // 根据类型自动装配,若加上@Qualifier(value = "car")则可根据名字自动装配
      // 若使用@Resource则先进行byName,若失败再进行byType
      @Autowired
      private Car car;
      }
  4. 衍生注解

    为了更好的进行分层,Spring可以使用@Component的三个衍生注解,功能一样,目前使用哪一个功能都一样。

    • @Controller:web层

    • @Service:service层

    • @Repository:dao层

    写上这些注解,就相当于将这个类交给Spring管理装配了

Spring AOP概述

  1. 什么是AOP?

    AOP(Aspect Oriented Programming)意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

  2. AOP在Spring中的作用

    提供声明式事务,允许用户自定义切面

    • 横切关注点:跨越应用程序多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要关注的部分,就是横切关注点。如日志 , 安全 , 缓存 , 事务等等 ....

    • 切面(ASPECT):横切关注点 被模块化 的特殊对象。即,它是一个类。

    • 通知(Advice):切面必须要完成的工作。即,它是类中的一个方法。

    • 目标(Target):被通知对象,即被横切的对象。

    • 代理(Proxy):向目标对象应用通知之后创建的对象。

    • 切入点(PointCut):切面通知 执行的 “地点”的定义。

    • 连接点(JointPoint):与切入点匹配的执行点。

  3. AOP的优点

    • 降低模块之间的耦合度

    • 使系统容易扩展

    • 非业务代码更加集中,不分散,便于统一管理

    • 业务代码更简洁纯粹,没有其他代码的影响

代理模式

spring aop是通过动态代理实现的,给业务代码找一个代理,让打印日志信息等工作交给代理来做,这样的话业务代码就只需要关心自身的业务即可。为了能更深入的理解aop,我们先理解一下代理模式。

  1. 静态代理

    静态代理实际上就是你想要完成一件事,但是你不直接自己完成,而是找到一个代理帮你完成。举个生活中的例子。比如你要租一间房子,但是你一般不会通过房东直接租房,因为你找不到房东,这时你要通过中介来租房,此时中介就是代理,它和房东一样具有租房的功能,并且还有带你看房、收中介费等额外的功能,中介可以额外干很多事情,但是毫不影响房东租房这个业务。

    静态代理一般需要4个角色:

    • 抽象角色:即要真实角色要实现的业务功能,比如例子中的“租房”或者web项目中的CRUD操作,该角色一般通过接口或者抽象类来实现

    • 真实角色:被代理的角色,比如例子中的房东或者web项目中的业务接口实现类

    • 代理角色:代理真实角色,比如例子中的中介或者web项目中的Proxy类

    • 客户:使用代理角色进行一些操作

    下面通过一个更贴近真实开发的例子加深对静态代理的理解:在每个CRUD操作前添加日志

    • 创建一个抽象角色,比如CRUD操作

      //抽象角色:增删改查业务
      public interface UserService {
      void add();
      void delete();
      void update();
      void query();
      }
    • 创建一个真实对象完成这些操作,即编写接口实现类

      //真实对象,完成增删改查操作的人
      public class UserServiceImpl implements UserService {
      public void add() {
      System.out.println("增加了一个用户");
      }

      public void delete() {
      System.out.println("删除了一个用户");
      }

      public void update() {
      System.out.println("更新了一个用户");
      }

      public void query() {
      System.out.println("查询了一个用户");
      }
      }
    • 设置一个代理类来处理日志! 代理角色

      //代理角色,在这里面增加日志的实现
      public class UserServiceProxy implements UserService {
      private UserServiceImpl userService;

      public void setUserService(UserServiceImpl userService) {
      this.userService = userService;
      }

      public void add() {
      log("add");
      userService.add();
      }

      public void delete() {
      log("delete");
      userService.delete();
      }

      public void update() {
      log("update");
      userService.update();
      }

      public void query() {
      log("query");
      userService.query();
      }

      public void log(String msg){
      System.out.println("执行了"+msg+"方法");
      }
      }
    • 测试访问类:

      public class Client {
      public static void main(String[] args) {
      // 真实业务
      UserServiceImpl userService = new UserServiceImpl();
      // 代理类
      UserServiceProxy proxy = new UserServiceProxy();
      // 使用代理类实现日志功能!
      proxy.setUserService(userService);

      proxy.add();
      proxy.delete();
      proxy.update();
      proxy.query();
      }
      }

    可以看到,我们在不改变原来的代码的情况下,实现了对原有功能的增强,这是AOP中最核心的思想

  2. 动态代理

    使用静态代理虽然使业务扩展更加集中与方便,但是多了静态代理类,工作量变大了,降低了开发效率。我们想要静态代理的好处,又不想要静态代理的缺点,所以 , 就有了动态代理 !

    动态代理的角色和静态代理的一样,其代理类是动态生成的,动态代理分为两类 :

    • 一类是基于接口的动态代理 —— JDK动态代理

    • 一类是基于类的动态代理 —— cglib

    我们将静态代理的实例修改成动态代理来加深对动态代理的理解(接口与接口实现类与静态代理相同):

    • 生成动态代理类:

      public class ProxyInvocationHandler implements InvocationHandler {
      private Object target; // 被代理的类

      public void setTarget(Object target) {
      this.target = target;
      }

      // 生成代理类
      public Object getProxy(){
      return Proxy.newProxyInstance(this.getClass().getClassLoader(),
      target.getClass().getInterfaces(),this);
      }

      // proxy : 代理类
      // method : 代理类的调用处理程序的方法对象
      public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{
      log(method.getName());
      Object result = method.invoke(target, args);
      return result;
      }

      public void log(String methodName){
      System.out.println("执行了"+methodName+"方法");
      }
      }
    • 测试访问类

      public class Test {
      public static void main(String[] args) {
      // 真实对象
      UserServiceImpl userService = new UserServiceImpl();
      // 代理对象的调用处理程序
      ProxyInvocationHandler pih = new ProxyInvocationHandler();
      pih.setTarget(userService); // 设置要代理的对象
      UserService proxy = (UserService)pih.getProxy(); //动态生成代理类!

      proxy.add();
      proxy.delete();
      proxy.update();
      proxy.auery();
      }
      }

    一个动态代理,一般代理某一类业务,一个动态代理可以代理多个类,代理的是接口

Spirng AOP的使用

Spirng框架中不需要创建 InvocationHandler,只需要创建一个切面对象,将所有的非业务代码在切面对象中完成即可,Spring框架底层会自动根据切面类以及目标类生成一个代理对象。

    1. 创建maven工厂,导入相关依赖

              <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
      <version>5.0.11.RELEASE</version>
      </dependency>
      <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aspects</artifactId>
      <version>4.3.9.RELEASE</version>
      </dependency>
    2. 编写业务接口和实现类

      public interface UserService {
      public void add();
      public void delete();
      public void update();
      public void query();
      }
      @Component
      public class UserServiceImpl implements UserService{

      @Override
      public void add() {
      System.out.println("增加用户");
      }

      @Override
      public void delete() {
      System.out.println("删除用户");
      }

      @Override
      public void update() {
      System.out.println("更新用户");
      }

      @Override
      public void query() {
      System.out.println("查询用户");
      }
      }
    3. 编写增强类

      package com.jarreet.config;

      import org.aspectj.lang.ProceedingJoinPoint;
      import org.aspectj.lang.annotation.After;
      import org.aspectj.lang.annotation.Around;
      import org.aspectj.lang.annotation.Aspect;
      import org.aspectj.lang.annotation.Before;

      @Aspect // 表示该类是切面类
      @Component // 将该类的对象注入到ioc容器中
      public class AnnotationPointcut {
      @Before("execution(* com.jarreet.service.UserServiceImpl.*(..))")
      public void before(){
      System.out.println("---------方法执行前---------");
      }

      @After("execution(* com.jarreet.service.UserServiceImpl.*(..))")
      public void after(){
      System.out.println("---------方法执行后---------");
      }

      @Around("execution(* com.jarreet.service.UserServiceImpl.*(..))")
      public void around(ProceedingJoinPoint jp) throws Throwable {
      System.out.println("环绕前");
      // 获取方法名
      System.out.println("签名:"+jp.getSignature());
      // 获取参数
      System.out.println("参数为:"+ Arrays.toString(jp.getArgs()));
      //执行目标方法proceed
      Object proceed = jp.proceed();
      System.out.println("环绕后");
      System.out.println(proceed);
      }
      }
    4. 在XML文件中配置aop

      <?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:aop="http://www.springframework.org/schema/aop"
      xsi:schemaLocation="http://www.springframework.org/schema/beans
      http://www.springframework.org/schema/beans/spring-beans.xsd
      http://www.springframework.org/schema/aop
      http://www.springframework.org/schema/aop/spring-aop.xsd">

      <!-- 自动扫描 -->
      <context:component-scan base-package="com.jarreet"></context:component-scan>

      <!-- 是Aspect注解生效,为目标类自动生成代理对象 -->
      <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
      </beans>
    5. 测试

          @Test
      public void testAop(){
      // 加载配置文件
      ApplicationContext context = new ClassPathXmlApplicationContext("spring-aop.xml");
      // 获取代理对象
      UserService proxy = (UserService)context.getBean("userServiceImpl");

      proxy.add();
      proxy.delete();
      proxy.update();
      proxy.query();
      }


posted @ 2021-05-06 00:49  离渊灬  阅读(51)  评论(0)    收藏  举报