Spring Framework技术学习

导语

 在Java开发领域,Spring Framework无疑是一个里程碑式的存在。它提供了全面的编程和配置模型,帮助开发者解决企业级应用开发的复杂性。本文将引导读者深入了解Spring Framework的核心概念、主要特性和使用方法,并通过示例代码展示其在实际项目中的应用。

一、Spring IoC(Inversion of Control,控制反转)

Spring IoC(Inversion of Control,控制反转)是一种设计原则,它帮助我们构建松耦合的应用程序。在传统的编程模式下,对象通常负责管理和创建它的依赖对象。但在IoC模式下,对象不再自行创建和管理依赖对象,而是由容器(如Spring IoC容器)来负责创建和维护对象之间的依赖关系。
以下是一个简单示例,展示Spring IoC如何通过XML配置和注解配置两种方式进行依赖注入(Dependency Injection,DI):

XML 配置方式


1.定义一个接口和其实现类:

public interface MessageService {String getMessage();
}public class SimpleMessageService implements MessageService {@Overridepublic String getMessage() {return "Hello from SimpleMessageService!";}
}

2.创建一个依赖于MessageService的WelcomeController:

public class WelcomeController {private MessageService service;public void setMessageService(MessageService service) {this.service = service;}public String printMessage() {return this.service.getMessage();}
}

3.使用Spring XML配置文件进行Bean定义和依赖注入:

<!-- spring-config.xml -->
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><!-- 定义MessageService Bean --><bean id="messageService" class="com.example.SimpleMessageService"/><!-- 定义WelcomeController Bean,并注入MessageService依赖 --><bean id="welcomeController" class="com.example.WelcomeController"><property name="messageService" ref="messageService"/></bean>
</beans>

4.使用Spring容器读取配置并获取Bean:

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class MainApp {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");WelcomeController controller = context.getBean(WelcomeController.class);System.out.println(controller.printMessage());  // 输出:"Hello from SimpleMessageService!"}
}

注解配置方式

  • 同样定义MessageService接口和SimpleMessageService实现类。
  • 使用@Autowired注解进行自动注入:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;@Component
public class WelcomeController {private final MessageService service;@Autowiredpublic WelcomeController(MessageService service) {this.service = service;}public String printMessage() {return this.service.getMessage();}
}

  • 使用@ComponentScan注解开启自动扫描,并在主类中创建Spring应用上下文:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;@SpringBootApplication
@ComponentScan(basePackages = "com.example") // 替换为你自己的包名
public class MainApp {public static void main(String[] args) {ApplicationContext context = SpringApplication.run(MainApp.class, args);WelcomeController controller = context.getBean(WelcomeController.class);System.out.println(controller.printMessage());  // 输出:"Hello from SimpleMessageService!"}
}

通过以上示例,可以看到无论是XML配置还是注解配置,WelcomeController都不再直接创建MessageService对象,而是由Spring IoC容器自动注入所需的服务对象,实现了控制反转。这样做的好处在于降低耦合度,提高代码的可测试性和可维护性。

二、Spring Core Container

Spring Core Container是Spring框架的核心部分,它负责创建、配置、组装和管理Bean(即Java对象)。这部分主要包括BeanFactory和ApplicationContext两大核心接口以及它们的实现。

BeanFactory

  • BeanFactory是Spring IoC容器的基本实现,它负责读取配置元数据(如XML、注解或Java配置类),根据这些元数据创建Bean,并管理Bean的生命周期。

由于BeanFactory的使用已经逐渐被功能更强大的ApplicationContext所替代,这里不做具体示例,仅做概念上的介绍。


ApplicationContext

  • ApplicationContext是BeanFactory的超集,提供了更多的高级特性,如AOP支持、事件发布、国际化资源访问等。常见的ApplicationContext实现有ClassPathXmlApplicationContext、AnnotationConfigApplicationContext等。

XML配置示例

// applicationContext.xml
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><!-- 定义一个Bean --><bean id="myBean" class="com.example.MyBean"><!-- 设置属性 --><property name="someProperty" value="someValue"/></bean></beans>// Java代码
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class MainApp {public static void main(String[] args) {// 加载并初始化ApplicationContextApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");// 从容器中获取BeanMyBean myBean = context.getBean(MyBean.class);System.out.println(myBean.getSomeProperty()); // 输出:"someValue"}
}// MyBean.java
package com.example;public class MyBean {private String someProperty;public void setSomeProperty(String someProperty) {this.someProperty = someProperty;}public String getSomeProperty() {return someProperty;}
}

注解配置示例

// 使用@Configuration标注的配置类
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class AppConfig {// 使用@Bean注解定义一个Bean@Beanpublic MyBean myBean() {MyBean bean = new MyBean();bean.setSomeProperty("configured using annotation");return bean;}
}// 主类
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.example.MyBean;public class MainApp {public static void main(String[] args) {// 初始化AnnotationConfigApplicationContext并注册配置类AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);// 从容器中获取BeanMyBean myBean = context.getBean(MyBean.class);System.out.println(myBean.getSomeProperty()); // 输出:"configured using annotation"}
}// MyBean.java 保持不变

 

在上述示例中,Spring Core Container负责解析配置信息并据此创建Bean。当从容器中获取Bean时,若Bean尚未创建,则会按需实例化并注入所需的依赖。此外,Spring容器还会管理Bean的生命周期,如初始化回调方法(如@PostConstruct)和销毁回调方法(如@PreDestroy)。

三、Spring AOP(Aspect Oriented Programming,面向切面编程)

Spring AOP(面向切面编程)允许开发者将横切关注点(如日志记录、事务管理、性能监控等)与业务逻辑分离,通过预定义的“切面”来统一处理这些通用功能。下面是一个简单的Spring AOP使用示例,我们将创建一个日志切面来记录方法的执行时间。

首先,定义一个自定义的切面注解:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LogExecutionTime {
}

接下来,创建一个切面类,该类包含一个通知(advice),即在方法执行前后进行操作的逻辑:

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;@Aspect
@Component
public class LoggingAspect {@Around("@annotation(LogExecutionTime)")public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {long start = System.currentTimeMillis();// 执行原方法Object result = joinPoint.proceed();long executionTime = System.currentTimeMillis() - start;// 打印方法执行时间System.out.println(joinPoint.getSignature() + " executed in " + executionTime + "ms");return result;}
}

然后,在业务类中使用自定义注解:

import org.springframework.stereotype.Service;@Service
public class BusinessService {@LogExecutionTimepublic void doSomethingTimeConsuming() {// 假设这是耗时的操作try {Thread.sleep(1000);} catch (InterruptedException e) {Thread.currentThread().interrupt();}}
}

 最后,确保在Spring配置中启用了AOP代理,如果是Spring Boot项目则默认已启用AOP,如果不是,可以通过XML或Java配置启用:

<!-- spring-context.xml -->
<aop:aspectj-autoproxy />

// JavaConfig
@EnableAspectJAutoProxy
public class AppConfig {}

现在,每次调用BusinessService的doSomethingTimeConsuming方法时,LoggingAspect切面中的logExecutionTime方法都会在其前后执行,打印出方法的执行时间。


通过这种方式,我们无需修改业务类本身的代码,就可以为其添加日志记录这一横切关注点。这就是Spring AOP的工作原理,它通过代理机制在方法执行的前后插入额外逻辑,实现功能的解耦和复用。

四、Spring MVC

Spring MVC是Spring框架的一部分,用于构建web应用程序,它遵循模型-视图-控制器(MVC)设计模式。下面是一个简化的Spring MVC示例,包括控制器(Controller)、模型(Model)和视图(View)的配置和使用。

1. 创建Controller类

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;@Controller
public class HelloWorldController {@GetMapping("/hello")public String helloWorld(Model model) {// 设置模型数据model.addAttribute("message", "Hello, World!");// 返回视图名称,Spring MVC将会查找对应的视图解析策略来渲染视图return "hello"; // 这里假设有一个名为hello的jsp/html模板}
}

在这个例子中,我们创建了一个名为HelloWorldController的控制器类,使用@Controller注解标识为一个Spring MVC控制器。helloWorld方法通过@GetMapping("/hello")注解映射到"/hello"这个HTTP GET请求路径上。当用户访问"http://example.com/hello"时,这个方法会被调用。它将字符串"Hello, World!"放入模型对象中,并返回视图名称"hello",表示需要渲染名为"hello"的视图。

2. 创建视图模板(HTML/JSP)
假设在src/main/resources/templates目录下有一个名为hello.html或hello.jsp的视图文件:

<!-- hello.html 或 hello.jsp -->
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Hello World Example</title>
</head>
<body><h1>${message}</h1>
</body>
</html>

在这个视图模板中,${message}是Thymeleaf或JSP EL表达式,它会从模型对象中取出之前设置的"message"值并显示出来。


3. 配置Spring MVC
对于Spring Boot项目,通常不需要手动配置Spring MVC,因为它已经内嵌了自动配置功能。但如果不是Spring Boot项目,你需要在XML配置文件中配置DispatcherServlet和其他相关bean。

<!-- servlet-context.xml -->
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:mvc="http://www.springframework.org/schema/mvc"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc.xsd"><!-- 自动扫描@Controller注解的类 --><context:component-scan base-package="com.example.controller" /><!-- 视图解析器配置 --><bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="prefix" value="/WEB-INF/views/" /><property name="suffix" value=".jsp" /></bean></beans>

在这个配置中,context:component-scan标签告诉Spring扫描指定包下标记为@Controller的类,将其注册为Spring MVC控制器。同时,配置了一个InternalResourceViewResolver,设置前缀和后缀,使得Spring MVC能够根据Controller返回的视图名称找到对应的视图资源。

综上所述,当用户发送GET请求到"/hello"时,Spring MVC会调度HelloWorldController的helloWorld方法处理请求,将结果存入模型,并根据返回的视图名称"hello",结合视图解析器的配置,找到并渲染对应的视图文件,最终将渲染后的HTML页面返回给浏览器。

五、Spring Data Access

Spring Data Access是Spring框架的一个重要组成部分,它为简化数据访问层的开发提供了多种解决方案,包括但不限于对JDBC、JPA、Hibernate、MyBatis等多种持久化技术的支持。下面以使用Spring Data JPA为例,演示如何通过Spring Data访问数据库。

示例代码:Spring Data JPA实体类

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;@Entity
public class User {@Id@GeneratedValue(strategy = GenerationType.AUTO)private Long id;private String username;private String password;// getters and setters// ...
}

示例代码:Spring Data JPA Repository接口

import org.springframework.data.jpa.repository.JpaRepository;public interface UserRepository extends JpaRepository<User, Long> {// Spring Data JPA可以自动生成基本CRUD操作// 如findAll(), findById(), save(), deleteById()// 也可以自定义查询方法List<User> findByUsername(String username);
}

示例代码:配置Spring Data JPA

// application.properties
spring.datasource.url=jdbc:mysql://localhost:3306/mydb
spring.datasource.username=root
spring.datasource.password=yourpassword
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
// Spring Boot主启动类配置
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;@SpringBootApplication
@EnableJpaRepositories(basePackageClasses = UserRepository.class) // 激活JPA仓库
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}
}

使用示例

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class UserService {private final UserRepository userRepository;@Autowiredpublic UserService(UserRepository userRepository) {this.userRepository = userRepository;}public User createUser(String username, String password) {User user = new User();user.setUsername(username);user.setPassword(password);return userRepository.save(user);}public User getUserByUsername(String username) {return userRepository.findByUsername(username).orElse(null);}
}

在这个例子中,我们首先定义了一个JPA实体类User,其中@Entity注解表明这是一个数据库表的映射实体,@Id和@GeneratedValue标明了主键生成策略。


然后我们定义了一个继承自JpaRepository的接口UserRepository,Spring Data JPA可以根据这个接口自动生成一系列的CRUD操作,如保存、删除、查找等。同时,我们也定义了一个自定义的查询方法findByUsername。


在配置方面,我们在application.properties中配置了数据库连接信息,并在Spring Boot主启动类中激活了JPA仓库。


最后,我们创建了一个服务类UserService,它依赖注入了UserRepository,并通过这个repository完成对数据库的增删查改操作。

六、Spring Test

Spring Test模块提供了对Spring应用的集成测试支持,使得开发者可以在模拟Spring环境(例如,模拟ApplicationContext)中对组件进行测试。以下是一个使用Spring Boot和JUnit5进行单元测试和集成测试的示例代码和详细讲解:

单元测试(针对单个服务类的方法)

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;@SpringBootTest(classes = YourApplication.class)
class UserServiceTest {@Autowiredprivate UserService userService;@Testvoid testFindUserById() {// 假设我们有一个找寻用户的findById方法User mockUser = new User(1L, "username", "password");// 可以通过Mockito等工具模拟数据源行为when(userRepository.findById(1L)).thenReturn(Optional.of(mockUser));// 调用待测试方法Optional<User> foundUser = userService.findById(1L);// 断言验证assertTrue(foundUser.isPresent());assertEquals("username", foundUser.get().getUsername());}
}

在上述单元测试示例中,我们使用@SpringBootTest注解加载整个Spring Boot应用上下文,以便测试类可以注入实际服务类的实例。我们通过模拟数据源行为来测试UserService的findById方法。

 

集成测试(针对多个组件协作)

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.test.annotation.Rollback;
import org.springframework.transaction.annotation.Transactional;@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) // 使用真实数据库
class UserAndRoleIntegrationTest {@Autowiredprivate UserRepository userRepository;@Autowiredprivate RoleRepository roleRepository;@Autowiredprivate UserService userService;@Test@Transactional@Rollback(false) // 不回滚事务,测试后保留数据变化void testAssignRoleToUser() {// 创建用户和角色User user = new User("test-user");Role role = new Role("test-role");roleRepository.save(role);userRepository.save(user);// 测试方法userService.assignRoleToUser(user.getId(), role.getId());// 验证用户是否成功分配了角色User fetchedUser = userRepository.findById(user.getId()).orElseThrow();Set<Role> roles = fetchedUser.getRoles();assertTrue(roles.contains(role));}
}

在集成测试示例中,我们使用@DataJpaTest注解只加载JPA相关的组件(如EntityManagerFactory、DataSource等),这样可以专注于数据库相关的集成测试。通过@Transactional和@Rollback注解来控制事务的行为,便于在测试结束后检查数据库的实际状态。

总结起来,Spring Test模块通过各种注解和配置,使开发者能够在接近生产环境的情况下,对应用程序的不同层次进行单元测试和集成测试,从而保证代码质量。

七、Spring WebFlux(反应式编程)

Spring WebFlux是Spring Framework 5引入的新模块,它支持非阻塞、反应式编程模型,特别适合处理高并发场景。WebFlux主要基于Reactor项目,使用Flux和Mono作为响应式序列类型,用于处理0至N个元素或者0至1个元素的数据流。


以下是一个简单的Spring WebFlux控制器示例及其详细讲解:

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;import java.time.Duration;
import java.util.stream.IntStream;@RestController
public class ReactiveController {@GetMapping("/stream")public Flux<Integer> streamNumbers() {// 生成一个无限序列,每秒输出一个数字,直到客户端取消请求return Flux.interval(Duration.ofSeconds(1)).map(l -> IntStream.rangeClosed(1, l.intValue()).findFirst().orElse(0));}@GetMapping("/single")public Mono<String> getSingleValue() {// 返回Mono,代表可能产生0个或1个值return Mono.just("Hello, WebFlux!");}@GetMapping("/async-processing")public Mono<String> asyncProcessing() {// 异步处理,模拟耗时操作return Mono.fromCallable(() -> {Thread.sleep(2000); // 模拟耗时操作return "Processed Asynchronously!";});}
}

详细讲解:


1.streamNumbers方法:

  • 使用Flux.interval()生成一个按照指定间隔(这里是每秒)发出整数序列的Flux。这可以用来模拟实时更新的数据流,比如股票价格变化、消息队列消费等。
  • map操作符用于转换每个发出的Long值为范围内的整数序列。

2.getSingleValue方法:

  • 返回的是Mono类型,表示预期最多有一个值。在这里,我们立即发出一个字符串常量。

3.asyncProcessing方法:

  • 使用Mono.fromCallable()包装一个耗时的计算任务,使其异步执行。
  • 当客户端发起请求时,不会阻塞线程,而是立刻返回一个Mono实例,客户端收到的是一个未完成的任务表示,只有当任务完成后,客户端才会接收到实际的结果。

通过这样的方式,Spring WebFlux利用Reactor提供的背压(Backpressure)机制,可以有效地处理大量并发请求,而不会因为同步阻塞导致线程资源浪费。并且,WebFlux完全兼容非阻塞IO(NIO),可以充分利用现代操作系统和服务器硬件的能力。

八、Spring Security

Spring Security是Spring框架中提供身份验证(Authentication)和授权(Authorization)的模块。下面是一个简单的Spring Security示例,展示如何配置一个基础的登录认证流程,并保护REST API资源。

首先,我们需要配置Spring Security的入口点(entry point)和用户详情服务(UserDetailsService):

import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests()// 允许任何人访问主页.antMatchers("/", "/home").permitAll()// 所有其他API需要经过身份验证.anyRequest().authenticated().and()// 登录表单配置.formLogin().loginPage("/login").permitAll().and()// 登出功能配置.logout().permitAll();}@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.inMemoryAuthentication().withUser("user").password(passwordEncoder().encode("password")).roles("USER").and().withUser("admin").password(passwordEncoder().encode("adminPass")).roles("USER", "ADMIN");}@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}// 如果你想从数据库加载用户信息,需要实现UserDetailsService接口/*@Beanpublic UserDetailsService userDetailsService() {return new CustomUserDetailsService(); // 自定义的UserDetailsService实现}*/
}

在上述代码中:

  • configure(HttpSecurity http) 方法用于配置Spring Security对HTTP请求的处理规则,包括哪些URL需要身份验证、哪些可以公开访问以及如何处理登录和登出请求。
  • configure(AuthenticationManagerBuilder auth) 方法用于配置身份验证管理器,这里我们使用内存中的用户存储,创建两个用户(user和admin),并使用BCryptPasswordEncoder加密他们的密码。
  • passwordEncoder() 方法返回一个PasswordEncoder实例,用于密码的加密处理。


如果你想从数据库加载用户信息,可以注释掉内存用户配置的部分,改为注入一个实现了UserDetailsService接口的自定义服务类,该类从数据库加载用户信息并验证用户凭据。
接下来,如果你想要处理登录和登出请求,还需要在应用中创建相应的登录表单页面和处理登录请求的控制器方法。
例如,登录表单可能会提交到 /login URL,Spring Security会自动处理登录过程,如果用户名和密码匹配,就会创建一个代表已认证用户的SecurityContext,并在后续请求中维护这个上下文。
要保护特定的REST API资源,只需在configure(HttpSecurity http)方法中进一步细化规则,例如:

http.authorizeRequests().antMatchers("/api/**").hasRole("USER").antMatchers("/admin/api/**").hasRole("ADMIN");

这段配置意味着所有以/api/开头的请求需要拥有"USER"角色,而以/admin/api/开头的请求则需要拥有"ADMIN"角色。

 

总结

通过上面的示例,我们了解了Spring Framework在Web开发中的应用。当然,Spring的功能远不止于此,它还提供了丰富的扩展和集成方案,如Spring Boot、Spring Cloud等。掌握Spring Framework对于Java开发者来说是非常有价值的,它能够帮助我们构建高效、稳定的企业级应用。希望本文能为您的Spring学习之旅提供帮助。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

将rgb图像加mask变差rgba图像(透明背景)

我们做demo的时候经常需要把人物或者物体分割出来&#xff0c;一个比较好的展示效果就是用分割mask把背景变成透明的&#xff0c;于是就需要将原本的rgb图像通过mask的指导变成rgba。 一个简单的脚本&#xff1a; import cv2 import os import os.path as osp import numpy a…

​打破牙医恐惧 从牙一齿科开始——记杭州资深口腔专家武建潮博士与他的牙科品牌

生机勃勃的绿植花卉&#xff0c;温馨亲切的原木装修&#xff0c;卡通乐园般的儿童诊室&#xff0c;一应俱全的先进设备……走进位于浙江省杭州市余杭区荆长路590-1-A的牙一齿科&#xff0c;温暖的气息扑面而来&#xff0c;细致热情的服务更让人如沐春风&#xff0c;任谁都很难想…

zuul的性能调优

文章目录 zuul的性能调优Zuul参数剖析semaphore(信号量)ribbonhystrix高并发下常见Zuul异常熔断 zuul 1.x 与2.x的区别与总结 zuul的性能调优 在项目实践中&#xff0c;使用jemeter多线程并发访问微服务中的接口时候&#xff0c;在Zuul层出现异常、超时等&#xff0c;从而导致整…

1.8 python 模块 time、random、string、hashlib、os、re、json

ython之模块 一、模块的介绍 &#xff08;1&#xff09;python模块&#xff0c;是一个python文件&#xff0c;以一个.py文件&#xff0c;包含了python对象定义和pyhton语句 &#xff08;2&#xff09;python对象定义和python语句 &#xff08;3&#xff09;模块让你能够有逻辑地…

Redis 全景图(2)---- 关于 Redis 的三“高”

前言 我们继续写第一篇文章没写完的。其实我也不想将我写的一篇 Redis 文章分成几篇中短文来写&#xff0c;但是没办法&#xff0c;我一次写个1万字&#xff0c;会限流&#xff0c;所以将就一下吧。 上篇文章我用了 Redis 的6大模块这个思路来描绘我脑子中的 Redis。其实这6大…

密码算法概论

基本概念 什么是密码学&#xff1f; 简单来说&#xff0c;密码学就是研究编制密码和破译密码的技术科学 例题&#xff1a; 密码学的三个阶段 古代到1949年&#xff1a;具有艺术性的科学1949到1975年&#xff1a;IBM制定了加密标准DES1976至今&#xff1a;1976年开创了公钥密…

Golang | Leetcode Golang题解之第4题寻找两个正序数组的中位数

题目&#xff1a; 题解&#xff1a; func findMedianSortedArrays(nums1 []int, nums2 []int) float64 {if len(nums1) > len(nums2) {return findMedianSortedArrays(nums2, nums1)}m, n : len(nums1), len(nums2)left, right : 0, mmedian1, median2 : 0, 0for left <…

app自动化-Appium学习笔记

使用Appium&#xff0c;优点&#xff1a; 1、支持语言比较多&#xff0c;例如&#xff1a;Java、Python、Javascript、PHP、C#等语言 2、支持跨应用&#xff08;windows、mac、linux&#xff09; 3、适用平台Android、iOS 4、支持Native App(原生app)、Web App、Hybird App…

算法系列--递归,回溯,剪枝的综合应用(1)

&#x1f495;"对相爱的人来说&#xff0c;对方的心意&#xff0c;才是最好的房子。"&#x1f495; 作者&#xff1a;Lvzi 文章主要内容&#xff1a;算法系列–递归,回溯,剪枝的综合应用(1) 大家好,今天为大家带来的是算法系列--递归,回溯,剪枝的综合应用(1) 1.全排…

使用Redis集合List实现消息队列

系列文章目录 文章目录 系列文章目录前言前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,看懂了就去分享给你的码吧。 Redis是一个key-value存储系统。和Memcached类似,它支持存储的value类型…

Java学习32-Java 多线程Thread 线程的常用方法

线程构造器结构 1.线程中的构造器可以使用很多参数 public thread()&#xff1a;分配一个新的线程对象public Thread(String name)&#xff1a;分配一个指定名字的线程对象public Thread(Runnable target)&#xff1a;指定创建线程的目标对象&#xff0c;它实现了Runnable接口…

C语言学习笔记二

文章目录 进制的代码表示数字数据类型字符类型输出字符例子 进制的代码表示 #include <stdio.h> int main() {short a 0100; // 八进制int b -0x1; // 十六进制long c 720; //十进制unsigned short m 0xffff; //十六进制unsigned int n 0x80000000; //十…

高阶DS---AVL树详解(每步配图)

目录 前言&#xff1a; AVL树的概念: AVL树节点的定义&#xff1a; AVL树的插入&#xff08;重点&#xff09; AVL树的旋转&#xff1a; &#xff08;1&#xff09;新节点插入较高左子树的左侧---右单旋 &#xff08;2&#xff09;新节点插入较高右子树的右侧---左单旋 …

TCP网络编程实例

服务器端代码&#xff1a; #include<t_stdio.h> #include<sys/types.h> #include <sys/socket.h> #include<arpa/inet.h> #include <sys/socket.h> #include<ctype.h> #include<unistd.h> int main(void){struct sockadd…

unity双层滑动实现

实现功能&#xff1a; 当滑动列表中内容处于顶端的时候&#xff0c;向上滑动优先滑动整个滑动列表&#xff0c;当滑动列表移动到设置位置&#xff0c;即设定的最高处时&#xff0c;继续移动列表内内容。向下移动亦然&#xff0c;当内容处于滑动列表顶端时&#xff0c;移动整个滑…

9.包和工具【go】

在Go语言中,包是代码的组织单元,而工具链则是Go语言提供的命令行工具,用于构建、测试和调试Go代码。下面我将详细介绍如何导入和使用标准库中的包,如何编写自己的包,以及如何使用Go的工具链。 导入和使用标准库中的包 Go的标准库包含了许多预定义的包,你可以通过导入这…

2022-04-15_for循环等_作业

for循环 编写程序数一下 1到 100 的所有整数中出现多少个数字9计算1/1-1/21/3-1/41/5 …… 1/99 - 1/100 的值&#xff0c;打印出结果求10 个整数中最大值在屏幕上输出9*9乘法口诀表二分查找 编写程序数一下 1到 100 的所有整数中出现多少个数字9 #include <stdio.h>in…

深入解析Hadoop生态核心组件:HDFS、MapReduce和YARN

这里写目录标题 01HDFS02Yarn03Hive04HBase1&#xff0e;特点2&#xff0e;存储 05Spark及Spark Streaming关于作者&#xff1a;推荐理由&#xff1a;作者直播推荐&#xff1a; 一篇讲明白 Hadoop 生态的三大部件 进入大数据阶段就意味着进入NoSQL阶段&#xff0c;更多的是面向…

[游戏开发][UE5.3]代码生成蓝图文件并在代码中保存文件。

我看网上有人的做法比我更好&#xff0c;我这个更简单 UE5-GAS:读取Excel数据在蓝图创建并更新GE类 - 知乎 数据配表 测试编辑器API 创建编辑器蓝图文件&#xff0c;继承AssetActionUtility.h 创建在编辑器中显示的函数&#xff0c;可以用中文命名方便其他人使用。 右键任意…

从零开始学Python数据分析:菜鸟也能成高手(文末送书)

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…