Spring依赖注入方式

 写在前面:大家好!我是晴空๓。如果博客中有不足或者的错误的地方欢迎在评论区或者私信我指正,感谢大家的不吝赐教。我的唯一博客更新地址是:https://ac-fun.blog.csdn.net/。非常感谢大家的支持。一起加油,冲鸭!
用知识改变命运,用知识成就未来!加油 (ง •̀o•́)ง (ง •̀o•́)ง

文章目录

  • 前言
  • 依赖注入方式
    • 基于构造法方法的注入
    • 基于Setter方法的注入
    • 基于字段注入
    • 基于方法注入
  • 配置方式
    • 示例代码
    • 基于XML文件的配置注入
      • pom依赖
      • 相关标签
        • bean标签
        • constructor-arg标签
        • property标签
      • XML实现构造器注入
      • XML实现Setter方法注入
    • 基于注解的配置注入
      • 将一个类声明为Bean的注解
      • 可注入依赖的注解
      • 基于XML和注解混合方式
    • 基于Java类的配置注入
        • @ComponentScan
        • @Bean

前言

Spring 框架对于 Java 服务端开发无疑是一个举足轻重的存在,它以简洁、高效、灵活的特性为我们开发提供了强大的支持,极大的提高了我们的开发效率和代码质量。Spring 解决了一个非常重要的问题,它可以通过 XML 或者 注解 来管理对象之间的依赖关系,也就是 Spring 的依赖注入机制。

依赖注入(Dependency Injection,DI) 作为 Spring 核心理念之一,贯穿于整个框架的使用之中。通过依赖注入Spring容器在创建一个对象时,会自动将这个对象的依赖注入进去,就不需要程序员主动通过 new对象 的方式进行对象创建。Spring 通过依赖注入机制打破了传统编程中对象之间紧密耦合的局面,让各个组件能够更加独立、灵活地进行开发、测试和维护,为构建复杂而稳定的软件系统奠定了坚实的基础。Spring 框架提供了多种依赖注入方式,本文主要介绍一下 Spring 框架中各种依赖注入的方式。

依赖注入方式

Spring 主要有三种常见的注入方式,分别是基于构造方法的注入、基于Setter方法的注入、基于字段注入。还有不经常使用的基于方法注入、接口回调注入
依赖注入示意图

基于构造法方法的注入

 所谓基于构造方法注入,就是通过构造方法将依赖项传递给对象。在对象实例化时,Spring IoC 容器会根据构造方法的参数类型,从容器中查找并注入匹配的依赖项。

public class MyService {  
    private final MyDependency myDependency;  

    @Autowired  
    public MyService(MyDependency myDependency) {  
        this.myDependency = myDependency;  
    }  
}  

 相比于其他注入方式,Spring 官方更推荐构造函数注入。官方文档说明如下(https://docs.spring.io/spring-framework/reference/core/beans/dependencies/factory-collaborators.html#beans-setter-injection):
构造器还是Setter
官方推荐使用构造器注入的原因主要有以下几点:

  1. 依赖完整性:构造器注入可以确保在对象创建时,所有必需的依赖项都已经被注入,从而避免空指针异常。
  2. 实现不可变对象:构造器注入可以将对象实现为不可变对象,即对象的状态在创建后不能被修改。不可变对象在多线程环境中更安全,因为它们的状态不会被改变
  3. 初始化保证:通过构造器注入的组件总是以完全初始化的状态返回给客户端(调用方)代码。组件在使用前已完全初始化,减少了潜在的错误。
  4. 避免过多的构造器参数:构造器注入鼓励将类的设计保持简洁,避免过多的依赖项。如果一个类有过多的构造器参数,这通常是一个糟糕的设计,表明该类承担了过多的职责,应该进行重构。

基于Setter方法的注入

 通过类的 Setter 方法来注入依赖项。适用于可选依赖或易于变更的配置属性的场景,因为对象可以先创建一个默认状态,然后再通过 Setter 方法补充注入依赖。基于 Setter 方法注入的一个好处是,Setter 方法使得该类的对象便于以后重新配置或重新注入。

public class MyService {  
    private MyDependency myDependency;  

    @Autowired  
    public void setMyDependency(MyDependency myDependency) {  
        this.myDependency = myDependency;  
    }  
}

基于字段注入

 基于字段注入直接通过注解(@Autowired、@Resource、@Inject)将依赖项注入到目标类的字段中。这是最简洁的方式,但通常不推荐使用。

public class MyService {  
    @Autowired  
    private MyDependency myDependency;  
}

基于方法注入

 通过普通方法(非Setter方法)注入依赖项。这种方式较为灵活,但使用较少。

public class MyService {  
    public void performAction(@Autowired MyDependency myDependency) {  
        myDependency.doSomething();  
    }  
}

配置方式

 以上这些注入方式主要通过三种方式进行配置,分别是基于XML文件的配置、基于注解的配置和基于Java类的配置。其中基于XML文件的配置Spring 早期的配置方式,现在使用的比较少。目前我们常用的配置方式主要是后两种。但是第一种方式也是需要了解的,如果看一些老项目的话还是需要掌握一下。

示例代码

 为了方便展示写了一个简单的计算器,该计算器只实现了加减乘除操作,我们需要在计算器的 Controller 类中注入加减乘除服务的实现类 ServiceImpl
目录结构

// CalculatorApplication类
package com.qingkong.application;

import com.qingkong.calculator.CalculatorController;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class CalculatorApplication {

    public static void main(String[] args) {
        // 加载Spring的配置文件
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");

        // 获取 CalculatorController Bean
        CalculatorController calculatorController = context.getBean(CalculatorController.class);

        // 测试计算器的功能
        System.out.println(calculatorController.add(1, 2));

    }
}

---
// CalculatorService 接口
package com.qingkong.service;

public interface CalculatorService {

    double add(double a, double b);

    double subtract(double a, double b);

    double multiply(double a, double b);

    double divide(double a, double b);
}

---
// CalculatorService 接口实现类
package com.qingkong.service.impl;

import com.qingkong.service.CalculatorService;

public class CalculatorServiceImpl implements CalculatorService {

    public CalculatorServiceImpl() {
        System.out.println("CalculatorServiceImpl无参构造方法被调用了");
    }

    @Override
    public double add(double a, double b) {
        return a + b;
    }

    @Override
    public double subtract(double a, double b) {
        return a - b;
    }

    @Override
    public double multiply(double a, double b) {
        return a * b;
    }

    @Override
    public double divide(double a, double b) {
        if (b == 0) {
            throw new IllegalArgumentException("不能除以0!");
        }
        return a / b;
    }
}

基于XML文件的配置注入

pom依赖

 要想实现 Spring 的依赖注入功能,需要引入 spring-context 依赖。spring-context 模块是 Spring 框架的核心模块之一,它提供了支持 Spring 应用上下文和事件驱动模型的功能。它构建在 spring-corespring-beans 模块之上,提供了以下功能:

  • 依赖注入(DI):支持通过 XML 配置、注解或 Java 配置进行依赖注入。
  • 应用上下文(ApplicationContext):提供了更高级的上下文接口,如 ClassPathXmlApplicationContextFileSystemXmlApplicationContext,用于加载配置文件和管理 Bean
  • 事件支持:支持事件发布和监听。

 我们只在 pom.xml 中引入 spring-context 依赖,Maven 会根据 依赖传递 自动将 spring-core、spring-bean、spring-aop等spring-context依赖的其他 Spring 模块引入。这些模块是 spring 框架的核心模块,真实的开发场景下还会引入其他模块。

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.3.30</version>
</dependency>

依赖

相关标签

bean标签

 在 XML 中我们可以通过 <bean> 标签来配置一个bean,该标签主要的元素如下所示:

属性作用
idBean 的唯一标识符,用于在 Spring 容器中引用该 Bean
classBean 的全限定类名
scope定义 Bean 的作用域(如 singleton、prototype 等)
autowire指定自动装配的方式(如 byName、byType 等)
factory-bean指定一个工厂 Bean,用于创建当前 Bean
factory-method指定工厂 Bean 中用于创建当前 Bean 的方法,与 factory-bean 配合使用
parent指定当前 Bean 的父 Bean
lazy-init指定是否延迟初始化该 Bean
depends-on指定该 Bean 依赖的其他 Bean
primary标记当前 Bean 为优先选择的 Bean
init-method指定 Bean 初始化时执行的方法
destroy-method指定 Bean 销毁时执行的方法
constructor-arg标签

XML 配置文件使用 <constructor-arg/> 标签传入构造方法所需要的内容。该标签主要的属性如下:

属性作用
ref传给构造方法参数的Bean ID
value传给构造方法参数的值
type构造方法参数对应的类型
index构造方法参数对应的位置,从0开始计算
name构造方法参数对应的名称
property标签

 使用 <property/> 可以为 Bean 的属性赋值或注入其他 Bean。该标签主要的元素如下:

属性作用
name指定要设置的属性名称
value指定要注入的属性值
ref引用另一个 Bean 的 Bean ID

XML实现构造器注入

 对于 CalculatorController 类,先生成该类的构造方法,然后将其依赖的 CalculatorService 类作为构造方法的参数注入。完成之后在 XML 文件中进行配置,具体实现如下:

CalculatorController类:

public class CalculatorController {

    private final CalculatorService calculatorService;

    // 构造器注入
    public CalculatorController(CalculatorService calculatorService) {
        System.out.println("开始进行构造器注入");
        this.calculatorService = calculatorService;
    }

    public double add(double a, double b) {
        return calculatorService.add(a, b);
    }

    public double subtract(double a, double b) {
        return calculatorService.subtract(a, b);
    }

    public double multiply(double a, double b) {
        return calculatorService.multiply(a, b);
    }

    public double divide(double a, double b) {
        return calculatorService.divide(a, b);
    }
}

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

   <!-- 定义 CalculatorService 的 Bean -->
   <bean id="calculatorService" class="com.qingkong.service.impl.CalculatorServiceImpl"/>

   <!-- 定义 CalculatorController 的 Bean,使用构造器注入 -->
   <bean id="calculatorController" class="com.qingkong.calculator.CalculatorController" >
       <constructor-arg ref="calculatorService"/>
   </bean>

</beans>

XML实现Setter方法注入

 首先在 CalculatorController 类中设置 calculatorService 的类型的属性,然后生成 Set 方法。完成之后在 XML 文件中进行配置,具体实现如下:

CalculatorController类:

public class CalculatorController {

    private CalculatorService calculatorService;

    // Set方法
    public void setCalculatorService(CalculatorService calculatorService) {
        System.out.println("开始进行Setter方法注入");
        this.calculatorService = calculatorService;
    }

    public double add(double a, double b) {
        return calculatorService.add(a, b);
    }

    public double subtract(double a, double b) {
        return calculatorService.subtract(a, b);
    }

    public double multiply(double a, double b) {
        return calculatorService.multiply(a, b);
    }

    public double divide(double a, double b) {
        return calculatorService.divide(a, b);
    }
}

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

   <!-- 定义 CalculatorService 的 Bean -->
   <bean id="calculatorService" class="com.qingkong.service.impl.CalculatorServiceImpl"/>

   <!-- 定义 CalculatorController 的 Bean,使用Setter方法注入 -->
   <bean id="calculatorController" class="com.qingkong.calculator.CalculatorController" >
       <!-- name属性的值对应 calculatorController 方法中相关属性的名称 -->
       <property name="calculatorService" ref="calculatorService"/>
   </bean>

</beans>

基于注解的配置注入

 使用注解注入有两种方式,分别是基于XML和注解混合方式纯注解方式。第一种方式需要在 XML 文件中配置 context:component-scan 标签,而基于纯注解方式则不需要进行任何 XML 配置,只需要在配置类中加入 @ComponentScan 注解并执行扫描包路径即可。

将一个类声明为Bean的注解

 在 XML配置注入 中我们通过 <bean/> 配置一个 Bean,而在基于注解的配置时我们只需要在类上面添加如下四个注解中的任意一个都能让 Spring 容器把他们配置为 Bean

注解说明
@Component将类标识为普通的Bean
@Service用于标识服务层的类
@Controller用于标识控制器层(Controller)的类(后来针对REST服务又增加了一个@RestController注解)
@Repository用于标识数据访问层的类,与数据库进行交互

 这四个注解本质上没有区别,而且后面三个注解都是 @Component 注解的衍生注解,之所以这么做主要是为了在分层架构中提供更好的语义化支持和分层的明确性,提高代码的可读性和可维护性。

可注入依赖的注解

Spring 内置的 @Autowired 以及 JDK 内置的 @Resource@Inject 都可以用于注入 Bean。这里需要注意的是 @Autowired 默认的注入方式为 byType(根据类型进行匹配),如果一个接口存在多个实现类,Spring 会同时找到多个满足条件的选择,这种情况下,注入方式会变为 byName(根据名称进行匹配),这个名称通常就是类名(首字母小写)。

 如果一个接口有多个实现类一般建议使用 @Autowired@Qualifier 注解配合的方式来显式指定名称而不是依赖变量的名称来区分。@Qualifier 注解主要用来在依赖注入时消除歧义。当面对一个接口有多个实现类我们可以使用 @Qualifier(“类名”) 的方式使 Spring 在依赖注入时准确的找到依赖。

@Resource 默认注入方式为 byName。如果无法通过名称匹配到对应的 Bean 时,注入方式会变为 byType。 该注解 nametype 有两个重要的属性。如果仅指定 name 属性则注入方式为 byName,如果仅指定 type属性则注入方式为 byType,如果同时指定 nametype 属性(不建议这么做)则注入方式为byType + byName

基于XML和注解混合方式

CalculatorServiceImpl类

@Component
public class CalculatorServiceImpl implements CalculatorService {
	// 省略重复代码……
}

CalculatorController类

@Component
public class CalculatorController {

    @Autowired
    private CalculatorService calculatorService;

    public double add(double a, double b) {
        return calculatorService.add(a, b);
    }

    public double subtract(double a, double b) {
        return calculatorService.subtract(a, b);
    }

    public double multiply(double a, double b) {
        return calculatorService.multiply(a, b);
    }

    public double divide(double a, double b) {
        return calculatorService.divide(a, b);
    }
}

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"
       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">
    
    <!-- 开启注解并扫描指定包中带有注解的类   -->
    <context:component-scan base-package = "com.qingkong"/>

</beans>

基于Java类的配置注入

 从 Spring Framework 3.0 开始,我们可以使用 @Configuration 注解定义配置类,可以达到替换 XML 配置文件的效果。使用 @Configuration、@Bean、@ComponentScan 等一系列注解,基本可以满足日常开发所需。

我们只需要将原来的 XML 配置文件删除,再加上带有 @Configuration 注解的配置类即可。
目录结构

配置类代码:

@Configuration
@ComponentScan("com.qingkong")
public class Config {
}

 当使用时需要通过 AnnotationConfigApplicationContext 对象来加载我们定义的配置类。

// 加载Spring的配置类
ApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
// 获取 CalculatorController Bean
CalculatorController calculatorController = context.getBean(CalculatorController.class);
@ComponentScan

@ComponentScan 注解指定了类扫描的包名,作用与 XML 配置文件中的 <context:component-scan/> 类似。如果配置类的 @ComponentScan 没有指定扫描的基础包路径或者类,那么默认从该配置类的包开始扫描(最好还是指定路径,防止漏包)。该注解的 includeFiltersexcludeFilters 属性可以用来指定包含和排除组件。官网中也给出了相应的示例:

@Configuration
@ComponentScan(basePackages = "org.example",
        includeFilters = @Filter(type = FilterType.REGEX, pattern = ".*Stub.*Repository"),
        excludeFilters = @Filter(Repository.class))
public class AppConfig {
    ...
}

该配置类与以下 XML配置 等效:

<beans>
    <context:component-scan base-package="org.example">
        <context:include-filter type="regex"
                expression=".*Stub.*Repository"/>
        <context:exclude-filter type="annotation"
                expression="org.springframework.stereotype.Repository"/>
    </context:component-scan>
</beans>
@Bean

 我们也可以在配置类将 @Bean 注解放在方法上面,这样方法的返回对象就会被当做容器的一个 Bean。默认情况下,Bean 名称与方法名称相同。官网给出了使用例子:

@Configuration
public class AppConfig {

    @Bean
    public TransferService transferService() {
        return new TransferServiceImpl();
    }
}

该配置与以下 XML 中的配置是等价的:

<beans>
    <bean id="transferService" class="com.acme.TransferServiceImpl"/>
</beans>

 既然有了 @Component 等注解为什么还要用 @Bean 注解呢?@Component 注解作用于类,而 @Bean 注解作用于方法。当我们引用第三方库中的类需要装配到 Spring 容器时,只能用 @Bean 注解来实现,因为通常情况下我们是无法修改第三方类库的代码的。


  1. https://docs.spring.io/spring-framework/docs/5.2.x/spring-framework-reference/core.html#spring-core
  2. 《学透Spring 从入门到项目实战》
  3. JavaGuide

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

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

相关文章

Mysql索引失效的场景

对索引列使用函数或表达式&#xff0c;或参与计算&#xff08;优化方法&#xff1a;将计算移到条件右侧&#xff1a;&#xff09;例 优化 对索引列进行隐式类型转换&#xff0c;条件中的数据类型与索引列的数据类型不匹配&#xff0c;会进行隐式类型转换 以like 通配符开头索…

CTFHub-RCE系列wp

目录标题 引言什么是RCE漏洞 eval执行文件包含文件包含php://input读取源代码远程包含 命令注入无过滤过滤cat过滤空格过滤目录分隔符过滤运算符综合过滤练习 引言 题目共有如下类型 什么是RCE漏洞 RCE漏洞&#xff0c;全称是Remote Code Execution漏洞&#xff0c;翻译成中文…

算法学习笔记之并查集

简介 问题描述&#xff1a;将编号为1-N的N个对象划分为不相交集合&#xff0c;在每个集合中&#xff0c;选择其中的某个元素代表所在集合。 常见两种操作&#xff1a; 1.合并两个集合 2.查找某元素属于哪个集合 实现方法1 用编号最小的元素标记所在集合&#xff1b; 定义…

渗透利器工具:Burp Suite 联动 XRAY 图形化工具.(主动扫描+被动扫描)

Burp Suite 联动 XRAY 图形化工具.&#xff08;主动扫描被动扫描&#xff09; Burp Suite 和 Xray 联合使用&#xff0c;能够将 Burp 的强大流量拦截与修改功能&#xff0c;与 Xray 的高效漏洞检测能力相结合&#xff0c;实现更全面、高效的网络安全测试&#xff0c;同时提升漏…

菌贝:云南鸡枞菌走向世界的第一品牌

云南&#xff0c;这片神奇的土地&#xff0c;孕育了无数珍稀的野生菌&#xff0c;而鸡枞菌无疑是其中的佼佼者。它以其独特的口感和丰富的营养价值&#xff0c;被誉为“菌中之王”。在云南鸡枞菌的品牌化进程中&#xff0c;菌贝以其卓越的品质和广泛的影响力&#xff0c;成为云…

如何恢复使用 Command+Option+Delete 删除的文件:完整指南

在日常使用 Mac 时&#xff0c;我们经常会使用 CommandOptionDelete 组合键来快速删除文件。这种删除方式会将文件直接移出废纸篓&#xff0c;而不会经过废纸篓的中间步骤&#xff0c;因此文件看似被永久删除。然而&#xff0c;即使文件被这样删除&#xff0c;仍然有几种方法可…

windows生成SSL的PFX格式证书

生成crt证书: 安装openssl winget install -e --id FireDaemon.OpenSSL 生成cert openssl req -x509 -newkey rsa:2048 -keyout private.key -out certificate.crt -days 365 -nodes -subj "/CN=localhost" 转换pfx openssl pkcs12 -export -out certificate.pfx…

用户认证综合实验

实验需求 需求一&#xff1a;根据下表&#xff0c;完成相关配置 需求二&#xff1a;配置DHCP协议&#xff0c;具体要求如下 需求三&#xff1a;防火墙安全区域配置 需求四&#xff1a;防火墙地址组信息 需求五&#xff1a;管理员 为 FW 配置一个配置管理员。要求管理员可以通…

5.7.2 进度管理

文章目录 进度管理Gantt图PERT图 进度管理 进度安排&#xff1a;通过将项目分解成多个活动&#xff0c;分析活动间的依赖关系&#xff0c;估算工作量&#xff0c;分配资源&#xff0c;制定活动时序。 Gantt图 Gantt图横坐标表示时间&#xff0c;纵坐标表示不同任务。使用一条条…

MQTT(Message Queuing Telemetry Transport)协议(二)

下面为你详细介绍如何基于 TCP 协议对 MQTT 进行封装&#xff0c;包括实现思路、代码示例及代码解释。 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <arpa/inet.h> #include <sys/socket.h>…

b站——《【强化学习】一小时完全入门》学习笔记及代码(1-3 多臂老虎机)

问题陈述 我们有两个多臂老虎机&#xff08;Multi-Armed Bandit&#xff09;&#xff0c;分别称为左边的老虎机和右边的老虎机。每个老虎机的奖励服从不同的正态分布&#xff1a; 左边的老虎机&#xff1a;奖励服从均值为 500&#xff0c;标准差为 50 的正态分布&#xff0c;即…

Unity 接入Tripo 文生模型,图生模型

官方网站&#xff1a;https://www.tripo3d.ai/app/home自行注册账号并且登陆下载Unity插件&#xff1a;https://cdn-web.tripo3d.ai/plugin/tripo-unity.zip申请apikey&#xff1a; https://platform.tripo3d.ai/api-keys使用&#xff08;后续过程就按照第二步下载的插件里面的…

Arduino 第十一章:温度传感器

Arduino 第十一章&#xff1a;LM35 温度传感器 一、LM35 简介 LM35 是美国国家半导体公司&#xff08;现德州仪器&#xff09;生产的一款精密集成电路温度传感器。与基于热力学原理的传统温度传感器不同&#xff0c;LM35 能直接将温度转换为电压输出&#xff0c;且输出电压与…

【并发控制、更新、版本控制】.NET开源ORM框架 SqlSugar 系列

系列文章目录 &#x1f380;&#x1f380;&#x1f380; .NET开源 ORM 框架 SqlSugar 系列 &#x1f380;&#x1f380;&#x1f380; 文章目录 系列文章目录一、并发累计&#xff08;累加&#xff09;1.1 单条批量累计1.2 批量更新并且字段11.3 批量更新并且字段list中对应的…

5 分钟用满血 DeepSeek R1 搭建个人 AI 知识库(含本地部署)

最近很多朋友都在问&#xff1a;怎么本地部署 DeepSeek 搭建个人知识库。 老实说&#xff0c;如果你不是为了研究技术&#xff0c;或者确实需要保护涉密数据&#xff0c;我真不建议去折腾本地部署。 为什么呢&#xff1f; 目前 Ollama 从 1.5B 到 70B 都只是把 R1 的推理能力…

opc da 服务器数据 转 EtherCAT项目案例

目录 1 案例说明 2 VFBOX网关工作原理 3 应用条件 4 查看OPC DA服务器的相关参数 5 配置网关采集opc da数据 6 启动EtherCAT从站转发采集的数据 7 在服务器上运行仰科OPC DA采集软件 8 案例总结 1 案例说明 在OPC DA服务器上运行OPC DA client软件查看OPC DA服务器的相…

微信小程序地图开发总结-规划路线

在现代移动应用中&#xff0c;地图导航功能已成为必不可少的一部分。通过地图 API&#xff0c;我们可以轻松地在应用中集成位置服务和路径规划功能。本篇文章将带大家一起实现一个简单的路径导航功能&#xff0c;使用腾讯地图 API结合微信小程序&#xff0c;实现从当前位置到目…

【已解决】VSCode:“正在重新激活终端”

背景&#xff1a; 1、切换Python环境的时候有问题&#xff0c;然后一直显示“正在重新激活终端”。 2、此处电脑&#xff1a;MAC 解决方法&#xff1a; 打开命令面板&#xff08;按 CtrlShiftP 或 CmdShiftP&#xff09;。输入并选择 Python: Clear Cache and Reload Window…

Grafana-使用Button修改MySQL数据库

背景 众所周知&#xff0c;Grafana是一个用来展示数据的平台&#xff0c;但是有时候还是会有需求说能不能有一个按钮&#xff0c;点击的时候再对数据库进行修改&#xff0c;从而达到更新数据的效果 经过多方查证&#xff0c;终于实现了一个简单的&#xff0c;点击button执行sq…

Android 系统面试问题

一.android gki和非gki的区别 Android GKI&#xff08;Generic Kernel Image&#xff09;和非GKI内核的主要区别在于内核设计和模块化程度&#xff0c;具体如下&#xff1a; 1. 内核设计 GKI&#xff1a;采用通用内核设计&#xff0c;与设备硬件分离&#xff0c;核心功能统一…