Spring中的IOC和AOP

Spring两大核心机制:IOC和AOP

一、IOC:控制反转

传统开发中,需要调用对象的时候,需要调用者手动来创建被调用者的实例,即对象是由调用者new出来的;
但在Spring框架中,创建对象的工作不再由调用者来完成,而是交给IOC容器来创建,再推送给调用者,用完再还回来,类似于缓冲池,整个流程完成反转,所以是控制反转。

  • Spring全家桶各个功能模块的基础,是创建对象的容器。
  • IOC的特点是解耦合:比如说A需要用到B,传统的开发,我们要直接创建B的实例,但是在Spring中,IOC这个容器会创建B的实例,然后把这个B注入到A。

IOC的使用:基于xml配置文件、基于注解(主要)


 注:以下内容,获取DataConfig的对象是最终目的

1.基于xml:借助与DataConfig类对应的xml文件-spring.xml,主要靠Bean

1.1 创建Maven项目,在pom.xml配置文件中导入spring依赖
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.3.15</version>
</dependency>
1.2 创建一个类-DataConfig

@Data是可以不用手动set、get

package com.circle.ioc;

import lombok.Data;

@Data
public class DataConfig {
    private String url;
    private String driverName;
    private String username;
    private String password;
}
1.3 在resources路径下创建与类对应的配置文件,IOC容器通过读取配置文件,加载配置bean标签来创建对象
<bean class="com.circle.ioc.DataConfig" id="config">
        <property name="driverName" value="Driver"></property>
        <property name="url" value="localhost:3306"></property>
        <property name="username" value="root"></property>
        <property name="password" value="root"></property>
</bean>
1.3.1配置文件:
  • bean:通过配置bean标签来完成对象的管理
  • id:对象名
  • class:对象的模板类(所有交给IOC容器来管理的类必须要有无参构造函数,因为Spring底层是通过反射机制来创建对象,调用的是无参构造)
  • property:对象的成员变量通过property标签完成赋值
  • name:成员变量名
  • value:成员变量值(基本数据类型,String可以直接赋值,如果是其他引用类型不可以通过value赋值)
  • ref:把IOC中的另一个bean赋给当前成员变量(DI依赖注入),见下图(一个类中有另一个类的对象)此时用ref,不能用value,否则会抛出类型转换异常

1.3.2 IOC容器创建bean的两种方法: 
  • 无参构造函数(需要提供对应的set方法或使用lombok):property
  • 有参构造函数:constructor-arg
        type:用于指定要注入的数据的数据类型,该数据类型也是构造函数中某个或某些参数的类型。
        index:用于指定要注入的数据给构造函数中指定索引位置的参数赋值。索引的位置是从0开始。
        name:用于指定给构造函数中指定名称的参数赋值。
<bean id="stu1" class="com.zyh.pojo.Student">
    <constructor-arg name="id" value="1">  </constructor-arg>
    <constructor-arg name="name" value="李四"></constructor-arg>
</bean>

<bean id="stu1" class="com.zyh.pojo.Student">
    <constructor-arg index=0 value="1">  </constructor-arg>
    <constructor-arg index=1 value="李四"></constructor-arg>
</bean>
 1.3.3 bean是根据scope来生成的,表示bean的作用域
  1. singleton,单例,表示通过Spring容器获取的对象是唯一的,是默认值。只要加载IOC容器,不管是否从IOC种取出bean,配置文件中的bean都会被创建,而且只会创建一个对象
  2. prototype,原型,表示通过Spring容器获取的对象是不同的。如果不从IOC中取出bean,则不创建对象,取一次bean,就会创建一个对象
    <bean id="user" class="com.zyh.pojo.User" scope="prototype">
            <property name="id" value="1"></property>
            <property name="name" value="张三"></property>
        </bean>
    
  3. request,请求,表示在异常HTTP请求内有效,一般用于web项目
  4. session,会话,表示在一个用户会话内有效,一般用于web项目
1.3.4 复杂类型的依赖注入:
public class Student {
    private String name;
    private Person person;
    private String[] arr;
    private List<String> myList;
    private Map<String,String> myMap;
    private Set<String> mySet;
    private String wife;
    private Properties myPro;
}
<bean id="student" class="com.kang.pojo.Student">
        <!--普通值注入,value:具体属性值-->
        <property name="name" value="jerry"/>

        <!--Bean注入,ref:对象-->
        <property name="person" ref="person"/>

        <!--数组注入-->
        <property name="arr">
            <array>
                <value>AAA</value>
                <value>BBB</value>
                <value>CCC</value>
            </array>
        </property>

        <!--List注入-->
        <property name="myList">
            <list>
                <value>111</value>
                <value>222</value>
                <value>333</value>
            </list>
        </property>

        <!--Map注入-->
        <property name="myMap">
            <map>
                <entry key="aaa" value="aaaa"></entry>
                <entry key="bbb" value="bbbb"></entry>
                <entry key="ccc" value="cccc"></entry>
            </map>
        </property>

        <!--Set注入-->
        <property name="mySet">
            <set>
                <value>111</value>
                <value>222</value>
                <value>333</value>
            </set>
        </property>

        <!--null注入-->
        <property name="wife">
            <null/>
        </property>

        <!--Properties注入-->
        <property name="myPro">
            <props>
                <prop key="aaa">aaaa</prop>
                <prop key="bbb">bbbb</prop>
                <prop key="ccc">cccc</prop>
            </props>
        </property>
</bean>
1.3.5 bean的属性如果包含特殊字符:使用CDATA

1.3.6 依赖注入之p、c命名空间
p命名空间是set注入的一种快捷实现方式,想要使用p命名空间注入,需要注意一下几点。
1. 实体类中必须有set方法;
2. 实体类中必须有无参构造器(默认存在);
3. 必须导入p命名空间注入方式依赖。(类对应的xml配置文件)
xmlns:p="http://www.springframework.org/schema/p"
4. 导入后即可使用:
<bean id="user" class="com.yd.pojo.User" p:age="18" p:name="老王"/>
c命名空间是构造器注入的一种快捷实现方式,想要使用c命名空间,需要注意一下几点。
1. 实体类中必须存在有参构造器;
2. 必须导入c命名空间注入方式依赖。
xmlns:c="http://www.springframework.org/schema/c"

3. 导入后即可使用:

<bean id="user2" class="com.yd.pojo.User" c:age="23" c:name="中王"/>
1.4 创建一个test文件,调用API,从IOC获取对象
package com.circle.ioc;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import javax.xml.crypto.Data;

public class Test {
    public static void main(String[] args) {
//        // 不用ioc,所有对象开发者自己创建
//        DataConfig dataConfig = new DataConfig();
//        dataConfig.setDriverName("Driver");
//        dataConfig.setUrl("localhost::3306/dbname");
//        dataConfig.setUsername("root");
//        dataConfig.setPassword("root");

        // 使用ioc,对象不用开发者创建,交给spring框架完成
        // 两种方式:基于注解和XML(bean),主要是注解
        // 基于xml:把需要的对象在xml中进行配置,spring框架读取这个配置文件,根据配置文件的内容和反射机制来创建对象
        ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");  // ioc容器
        System.out.println(context.getBean("config"));  // 从ioc中取出bean,通过id
    }
}
1.4.1从IOC容器中取bean的方法:
  • 通过id取值:
 Student stu = (Student)applicationContext.getBean("stu");
  • 通过类型取值
 Student stu = applicationContext.getBean(Student.class);
   当IOC容器中存在两个以上Student Bean的时候就会抛出异常,因为此时没有唯一的bean
1.5 在XML方式中有三种方式来实例化bean
  • 反射模式
  • 工厂方法模式:静态工厂类不需要实例化,实例工厂类需要实例化
静态工厂类:
  1. 创建一个目标类对应的静态工厂类,写一个静态方法
  2. 在目标类对应的配置文件中
<?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 id="car" class="com.zyh.factory.StaticCarFactory" factory-method="getCar">
        <constructor-arg  name="num" value="1"></constructor-arg>
    </bean>

</beans>

                factory-method 指向静态方法

                constructor-arg的name、value属性是调用静态方法传入的参数

  • 静态工厂方法创建对象,不需要实例化工厂对象,因为静态工厂的静态方法,不需要创建对象就可以调用了
实例工厂类:
  1. ​​​​​​​创建一个目标类对应的实例工厂类,写一个方法
  2. 在目标类对应的配置文件中
<!--    实例工厂类-->
    <bean id="instanceCarFactory" class="com.zyh.factory.InstanceCarFactory"></bean>
<!--    通过实例工厂获取Car-->
    <bean id="car1"  factory-bean="instanceCarFactory" factory-method="getCar">
        <constructor-arg value="2"></constructor-arg>
    </bean>
  • 实例工厂方法创建对象,需要实例化工厂对象,因为方法是非静态的,就必须通过实例化对象才能调用,所以必须创建工厂对象,spring.xml需要配置两个bean,一个是工厂类bean,一个是方法Bean

  • FactoryBean模式

2. 基于注解:两种方式(配置类、扫包+注解)

2.1 配置类:用一个java文件(配置类)替代xml文件,将xml中的配置内容放在配置类中

在类前加@Configuration即为配置类,整个配置类可以类比为xml文件;在类中写一个方法,方法前加@Bean,返回一个对象存入IOC容器中,类比为bean。

package com.circle.configuration;

import com.circle.ioc.DataConfig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

// 基于注解
// 1. 配置类:用一个java类替代xml文件,把在xml中配置的内容放在配置类中
// 2. 扫包 + 注解
@Configuration    // 配置类
public class BeanConfiguration {
    // 整个BeanConfiguration类对应spring.xml文件
    // 方法返回的对象对应xml中的bean
    // 加载配置类时需调用这个方法,把返回的对象存入ioc
    // value或name取别名,但不能再使用原方法名了,id唯一
    @Bean(value = "config")
    public DataConfig dataConfig(){
        DataConfig dataConfig = new DataConfig();
        dataConfig.setDriverName("Driver");
        dataConfig.setUrl("localhost::3306/dbname");
        dataConfig.setUsername("root");
        dataConfig.setPassword("root");
        return dataConfig;
    }
}
 2.2 测试
package com.circle.ioc;

import com.circle.configuration.BeanConfiguration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import javax.xml.crypto.Data;

public class Test {
    public static void main(String[] args) {
        // 基于注解:配置类
        // 读取配置类初始化IOC容器
        ApplicationContext context = new AnnotationConfigApplicationContext(BeanConfiguration.class);
//        System.out.println(context.getBean("dataConfig"));  // 方法名作为id
        System.out.println(context.getBean("config"));   // @Bean后加上value或name赋值,也可用value的值作为id,但取了value后,不能再用原方法名了,因为只有一个id
    }
}
存在问题:new哪行代码BeanConfiguration.class只能传一个类,实际应用中会有很多配置类。 
解决:扫包(配置类的包)
package com.circle.ioc;

import com.circle.configuration.BeanConfiguration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import javax.xml.crypto.Data;

public class Test {
    public static void main(String[] args) {
        // 扫包:配置类的包
        ApplicationContext context = new AnnotationConfigApplicationContext("com.circle.configuration");
        System.out.println(context.getBean("dataConfig"));
    }
}

2.2 扫包+注解:直接将Bean的创建交给目标类-DataConfig,在目标类中添加注解@Component来创建
@Component注解告诉Spring框架,这个类需要创建对象注入到IOC容器
@value注解赋值
package com.circle.ioc;

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

@Data
@Component
public class DataConfig {
    @Value("localhost:3306")
    private String url;
    @Value("Drive")
    private String driverName;
    @Value("root")
    private String username;
    @Value("root")
    private String password;
}
测试:
package com.circle.ioc;

import com.circle.configuration.BeanConfiguration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import javax.xml.crypto.Data;

public class Test {
    public static void main(String[] args) {
        // 扫包:目标类的包
        ApplicationContext context = new AnnotationConfigApplicationContext("com.circle.ioc");
        System.out.println(context.getBean(DataConfig.class));
    }
}

3. 依赖注入:两个类A和B,A中有B的对象,创建AB两个对象,自动将B装入A

A~GlobalConfig  B~DataConfig
1. @Autowired 自动装载注解,自动去ioc中找DataConfig类型的Bean,默认通过类型注入(ByType),找到了就拿过来赋值(DataConfig类也一定要有@Component注解)。
2. 如果想通过名字注入(ByName),使用@Qualifier注解
 1. 类型注入@Autowired
package com.circle.ioc;

import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.security.SecureRandom;
@Data
@Component
public class GlobalConfig {
    @Value("8080")
    private String port;
    @Value("/")
    private String path;
    @Autowired
    private DataConfig dataConfig;
}
package com.circle.ioc;

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

@Data
@Component
public class DataConfig {
    @Value("localhost:3306")
    private String url;
    @Value("Drive")
    private String driverName;
    @Value("root")
    private String username;
    @Value("root")
    private String password;
}
测试:
package com.circle.ioc;

import com.circle.configuration.BeanConfiguration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import javax.xml.crypto.Data;

public class Test {
    public static void main(String[] args) {
        // 扫包:目标类的包
        ApplicationContext context = new AnnotationConfigApplicationContext("com.circle.ioc");
        System.out.println(context.getBean(DataConfig.class));
    }
}

2.  使用名字注入:@Qualifier,注意DataConfig类中要取别名,与@Qualifier一致
package com.circle.ioc;

import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.security.SecureRandom;
@Data
@Component
public class GlobalConfig {
    @Value("8080")
    private String port;
    @Value("/")
    private String path;
//    @Autowired
//    private DataConfig dataConfig;  // 类型注入
    @Qualifier("config")
    private DataConfig dataConfig; // 名字注入
}
package com.circle.ioc;

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

@Data
@Component(value = "config")
public class DataConfig {
    @Value("localhost:3306")
    private String url;
    @Value("Drive")
    private String driverName;
    @Value("root")
    private String username;
    @Value("root")
    private String password;
}

二、AOP:以IOC为基础,面向切面编程,是抽象的面向对象。

        多个方法在相同位置有相同的操作,切一刀,将切面抽象为一个对象,把相同的操作代码写进对象,对对象进行编程,底层使用动态代理机制。
        可以打印日志、事务、权限管理。

1. 原代码:代码维护性、复用性差

接口:

package com.circle.aop;

public interface cal {
    public int add(int num1, int num2);
    public int sub(int num1, int num2);
    public int mul(int num1, int num2);
    public int div(int num1, int num2);

}

实现接口的类:

package com.circle.aop;

public class calculate implements cal{
    @Override
    public int add(int num1, int num2) {
        System.out.println("add方法的参数为:" + num1 + "、" + num2);
        int result = num1 + num2;
        System.out.println("add方法的结果为:" + result);
        return result;
    }

    @Override
    public int sub(int num1, int num2) {
        System.out.println("sub方法的参数为:" + num1 + "、" + num2);
        int result = num1 - num2;
        System.out.println("sub方法的结果为:" + result);
        return result;
    }

    @Override
    public int mul(int num1, int num2) {
        System.out.println("mul方法的参数为:" + num1 + "、" + num2);
        int result = num1 * num2;
        System.out.println("mul方法的结果为:" + result);
        return result;
    }

    @Override
    public int div(int num1, int num2) {
        System.out.println("div方法的参数为:" + num1 + "、" + num2);
        int result = num1 / num2;
        System.out.println("div方法的结果为:" + result);
        return result;
    }
}

把参数和结果部分的日志代码抽离出业务代码,统一处理,使核心业务代码与非业务代码解耦合。

2. 使用AOP

AOP的优点:
  • 可以降低模块之间的耦合性
  • 提供代码的复用性
  • 提高代码的维护性
  • 集中管理非业务代码,便于维护
  • 业务代码不受非业务代码影响,逻辑更加清晰

2.1 在pom.xml中引入依赖

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>5.3.15</version>
        </dependency>

        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.7</version>
        </dependency>

2.2 创建切面类

将切面对象注入IOC容器,目标类对象也注入IOC,目标类对象与切面对象整合形成一个代理对象(动态代理机制),操作代理对象

package com.circle.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

import java.util.Arrays;

// 切面类
@Component
@Aspect
public class LoggerAspect {
    @Before("execution(public int com.circle.aop.calculate.*(..))")
    public void before(JoinPoint joinPoint){  // 切面对象与方法之间有个连接点对象Joinpoint,需要被横切的位置,即通知要插入业务代码的具体位置
        String name = joinPoint.getSignature().getName();
        System.out.println(name + "方法的参数是:" + Arrays.toString(joinPoint.getArgs()));
    }

    @AfterReturning(value = "execution(public int com.circle.aop.calculate.*(..))", returning = "result")
    public void afterReturning(JoinPoint joinPoint, Object result){
        String name = joinPoint.getSignature().getName();
        System.out.println(name + "方法的结果是:" + result);
    }
}
  • @Before,表示方法的执行时机是在业务方法之前,execution表达式表示切入点是calculate中的所有方法
  • @AfterReturning,表示方法的执行时机是在业务方法返回结果后,execution表达式表示切入点是calculate类中的方法,returning是把业务方法的返回值和切面类方法的形参进行绑定
  • @AfterThrowing,表示方法的执行时机是在业务方法抛出异常后,execution表达式表示切入点是calculate类中的方法,throwing是把业务方法的异常和切面类方法的形参进行绑定
  • @After,表示方法的执行时机是在业务方法结束以后,execution表达式表示切入点是calculate类中的方法

2.3 实现类

package com.circle.aop;

import org.springframework.stereotype.Component;
// 目标类
@Component
public class calculate implements cal{
    @Override
    public int add(int num1, int num2) {
        int result = num1 + num2;
        return result;
    }

    @Override
    public int sub(int num1, int num2) {
        int result = num1 - num2;
        return result;
    }

    @Override
    public int mul(int num1, int num2) {
        int result = num1 * num2;
        return result;
    }

    @Override
    public int div(int num1, int num2) {
        int result = num1 / num2;
        return result;
    }
}

2.4 配置自动扫包,开启自动生成代理对象

在spring.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"
       xmlns:context="http://www.springframework.org/schema/context"
       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/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">

<!--    自动扫包-->
    <context:component-scan base-package="com.circle.aop"></context:component-scan>
    
<!--    开启自动生成代理对象-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

2.5 测试

package com.circle.aop;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
        cal bean = context.getBean(cal.class);  // 代理对象和目标类对象都是实现了接口的类
        bean.add(9, 8);
        bean.sub(9, 8);
        bean.mul(9, 8);
        bean.div(9, 8);
    }
}

当有多个实现类,会报错,因为切面对象不知道与谁整合成代理对象,目标类对象和切面对象和代理对象是一对一对一的关系。

参考:http://t.csdnimg.cn/EOXh8 

        b站楠哥教你学java-1、什么是IoC和AOP_哔哩哔哩_bilibili

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/486143.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于springboot+vue的家政服务平台

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…

代码随想录阅读笔记-栈与队列【逆波兰表达式求值】

题目 根据 逆波兰表示法&#xff0c;求表达式的值。 有效的运算符包括 , - , * , / 。每个运算对象可以是整数&#xff0c;也可以是另一个逆波兰表达式。 说明&#xff1a; 整数除法只保留整数部分。 给定逆波兰表达式总是有效的。换句话说&#xff0c;表达式总会得出有…

力扣669 修剪二叉搜索树 Java版本

文章目录 题目描述代码 题目描述 给你二叉搜索树的根节点 root &#xff0c;同时给定最小边界low 和最大边界 high。通过修剪二叉搜索树&#xff0c;使得所有节点的值在[low, high]中。修剪树 不应该 改变保留在树中的元素的相对结构 (即&#xff0c;如果没有被移除&#xff0…

Linux--动静态库的原理和使用详解

本文介绍了Linux系统中动态库与静态库的概念、原理以及使用方法。通过深入讲解动态库与静态库的区别和优劣势&#xff0c;帮助读者更好地理解并选择合适的库类型来进行软件开发。 动态库和静态库的概念 动态库&#xff08;Dynamic Link Library&#xff0c;简称DLL&#xff09…

加速新能源汽车产品迭代:融合前沿科技的重要性

新能源汽车新质生产力提升咨询方案 一、新能源汽车企业行业目前发展现状及特点&#xff1a; 1、快速增长 2、技术迭代快 3、竞争加剧 二、新能源汽车企业发展新质生产力面临的痛点&#xff1a; 1、技术创新压力巨大 2、市场竞争激烈 3、供应链稳定性欠缺 4、成本控制压…

【Linux】网络编程套接字一

网络编程套接字一 1.预备知识1.1理解源IP地址和目的IP地址1.2认识端口号1.3认识TCP协议1.4认识UDP协议1.5网络字节序 2.socket编程接口3.UDP网络程序3.1UDP Server服务器端3.2UDP Client客户端 4.根据UDP客户端服务端做的设计4.1字典热加载4.2shell命令行4.3聊天室 5.windows客…

疲劳检测YOLOV8

疲劳检测YOLOV8&#xff0c;只需要OPENCV&#xff0c;采用YOLOV8训练得到PT模型&#xff0c;然后转换成ONNX&#xff0c;OPENCV调用&#xff0c;支持C/PYTHON/ANDROID开发疲劳检测YOLOV8

HCIP —— 生成树 (下)

目录 STP&#xff08;生成树&#xff09;的角色选举 根网桥 根端口 选举规则&#xff1a; 指定端口 生成树的端口状态 STP的接口状态&#xff1a;禁用、阻塞、侦听、学习、转发 五种状态 禁用状态 阻塞状态 侦听状态 学习状态 转发状态 当生成树拓扑结构发生变化 …

Http中Host,Referer,Origin和Access-Control-Allow-Origin

Http中Host&#xff0c;Referer&#xff0c;Origin和Access-Control-Allow-Origin 文章目录 Http中Host&#xff0c;Referer&#xff0c;Origin和Access-Control-Allow-OriginHost定义特性作用 Referer定义特性作用 Origin定义特性作用 Access-Control-Allow-Origin定义特性作用…

003- AutoCoder 使用Web版大模型,性感的Human As Model 模式

这是下面这篇文章的继续。 002- 用 AutoCoder 添加和修改代码 前面我们提到&#xff0c;如何解决你没有API版大模型&#xff0c;或者你的API版大模型太弱&#xff0c;而你只有Web版本的诸如 Kimi/GPT4 的情况下&#xff0c;改如何让AutoCoder帮助你完成编程&#xff1f; 我们有…

2024,淘天六大升级,电商人都准备好了吗?|淘天商品API数据采集接口

电商进入存量时代&#xff0c; 淘天仍是电商重心和基本盘 我们说现在的电商仍有红利&#xff0c;只是竞争愈发激烈&#xff0c;从增量时代发展到存量时代。 进入存量竞争时代&#xff0c;全平台布局已成行业共识。 电商淘天官方订单及商品详情API数据采集接口 但无论如何&…

删除数组中的指定元素(了解如何删除数组中的指定元素,并返回一个新的数组,看这一篇就足够了!)

前言&#xff1a;有时候我们会遇到要在数组中删除指定元素&#xff0c;但是不能创建新的数组&#xff0c;那么这个时候应该如何操作呢&#xff1f; ✨✨✨这里是秋刀鱼不做梦的BLOG ✨✨✨想要了解更多内容可以访问我的主页秋刀鱼不做梦-CSDN博客 废话不多讲&#xff0c;让我们…

Go——指针和内存逃逸

区别于C/C中的指针&#xff0c;Go语言中的指针不能进行偏移和运算&#xff0c;是安全指针。 要搞明白Go语言中的指针概念需要先知道3个概念&#xff1a;指针地址&#xff0c;指针类型和指针取值。 一. Go语言的指针 Go语言中的函数传参都是值拷贝&#xff0c;当我们想修改某个…

页面router路由设计

Vue命名视图 命名视图 | Vue Router 如果要在 如何要在main区域里使用路由的话&#xff0c;整体区域是Layout&#xff0c;内涵Header和Nav以及Main path: /index,name: index,component: Layout, 若要只修改main区域的话&#xff0c;则取要加上v-if判断&#xff0c;来确实是…

Redis I/O多路复用

I/O多路复用 Redis的I/o多路复用中&#xff0c;将多个连接放到I/O复用程序中&#xff0c;这个复用程序具体是什么&#xff0c;是Redis的主线程吗 在Redis的I/O多路复用机制中&#xff0c;“复用程序”实际上指的是操作系统提供的系统调用接口&#xff0c;如Linux下的epoll、sel…

【办公类-16-07-07】“2023下学期 中班户外游戏2(有场地和无场地版,每天不同场地)”(python 排班表系列)

作品展示 背景需求&#xff1a; 2024年2月教务组发放的是“每周五天内容相同&#xff0c;两周10天内容相同”的户外游戏安排 【办公类-16-07-05】合并版“2023下学期 大班户外游戏&#xff08;有场地和无场地版&#xff0c;两周一次&#xff09;”&#xff08;python 排班表系…

论文导读 | 漫谈图神经网络

本文主要介绍图神经网络相关内容&#xff0c;包括图神经网络的基本结构以及近期研究进展。 背景 在实际生活中&#xff0c;许多数据都可以用图的形式表达&#xff0c;比如社交网络、分子模型、知识图谱、计算机网络等。图深度学习旨在&#xff0c;显式利用这些数据中的拓扑结…

【VALL-E-01】环境搭建

本系列文章系本人知乎账号迁移 本文系个人知乎专栏文章迁移 VALL-E 网络是GPT-SOVITS很重要的参考 知乎专栏地址&#xff1a; 语音生成专栏 相关文章链接&#xff1a; 【VALL-E-01】环境搭建 【VALL-E-02】核心原理 1、环境包使用 从效果看没有GPT-SOVITS 来的好 环境安装…

C#宿舍信息管理系统

简介 功能 1.发布公告 2.地理信息与天气信息的弹窗 3.学生信息的增删改查 4.宿舍信息的增删改查 5.管理员信息的增删改查 6.学生对宿舍物品的报修与核实 7.学生提交请假与销假 8.管理员对保修的审批 9.管理员对请假的审批 技术 1.采用C#\Winform开发的C\S系统 2.采用MD5对数据…

Java异常类型及异常处理方式

本章学习内容&#xff1a;使用异常处理机制&#xff0c;对程序运行过程中出现的异常情况进行捕捉并处理. 目录 &#x1f4cc; Java异常概述 &#x1f4cc; Java异常体系结构 &#x1f4cc; 常见的异常 &#x1f4cc; 异常处理 &#x1f4cc; Java异常概述 ○ 异常的概念&…