Spring框架(一)
Spring框架是Java开发中最为流行的框架之一,它以其强大的功能和灵活的设计,极大地简化了企业级应用的开发。本文将详细介绍Spring框架的核心概念、核心技术、依赖注入、多配置文件方式、开发程序的方式、IOC注解方式以及Spring与JUnit的整合。
目录
一、Spring框架概述
1.1 Spring框架的概述
1.2 Spring框架的优点
二、Spring的IOC核心技术
2.1 什么是IOC
2.2 IOC的程序入门
2.3 IOC技术总结
2.4 实例化Bean对象的三种方式
三、DI依赖注入
3.1 依赖注入的概述
3.2 DI的两种方式
3.3 复杂类型注入(数组,集合,Properties)
四、多配置文件管理
五、Spring框架开发程序的方式
六、IOC注解开发
6.1 半注解方式(XML + 注解)
6.2 纯注解方式(零XML)
6.3 对比分析
七、Spring 框架整合 JUnit 单元测试
7.1 基于XML配置的Spring整合JUnit测试
7.2 纯注解方式的Spring整合JUnit测试
7.3 对比分析
总结
一、Spring框架概述
1.1 Spring框架的概述
Spring是一个开源的Java平台,提供了一个轻量级的框架来解决企业应用开发的复杂性。Spring框架的核心优势在于其分层架构,允许开发者选择使用特定的组件,同时为J2EE应用程序开发提供集成的解决方案。
Spring框架的主要特点包括:
-
控制反转(IoC):将对象的创建和依赖关系的管理交给Spring容器。
-
面向切面编程(AOP):通过AOP实现权限拦截、运行监控等功能。
-
声明式事务管理:通过配置文件实现事务管理,无需手动编写事务代码。
-
方便程序测试:支持JUnit4,便于对Spring程序进行单元测试。
-
集成优秀框架:如Struts2、Hibernate、MyBatis、Quartz等。
-
降低JavaEE API的使用难度:对JDBC、JavaMail等复杂API进行了封装。
1.2 Spring框架的优点
-
方便解耦,简化开发:Spring通过IoC容器管理对象的创建和依赖关系,开发者无需手动管理对象的生命周期和依赖关系。
-
AOP编程的支持:Spring提供了AOP编程的支持,可以方便地实现权限拦截、运行监控等功能。
-
声明式事务的支持:通过配置文件即可完成事务管理,无需手动编写事务管理代码。
-
方便程序的测试:Spring对JUnit4提供了良好的支持,可以通过注解方便地测试Spring程序。
-
方便集成各种优秀框架:Spring内部提供了对Struts2、Hibernate、MyBatis、Quartz等框架的直接支持。
-
降低JavaEE API的使用难度:Spring对JDBC、JavaMail、远程调用等复杂API进行了封装,降低了使用难度。
二、Spring的IOC核心技术
2.1 什么是IOC
IOC(Inverse of Control,控制反转)是一种设计原则,通过将对象的创建权反转给Spring框架,降低了代码之间的耦合度。Spring的工厂通过读取配置文件来管理对象的创建和依赖关系。
2.2 IOC的程序入门
以下是一个简单的Spring IOC入门示例:
1. 创建mavenJava项目,导入坐标依赖(pom.xml)
<dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.0.2.RELEASE</version></dependency><dependency><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId><version>1.2</version></dependency><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.12</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency></dependencies>
2. 编写接口和实现类
package com.qcby.service;public interface UserService {public void hello();
}
package com.qcby.service;public class UserServiceImpl implements UserService{public void hello() {System.out.println("Hello IOC!");}
}
3. 编写 Spring 核心的配置文件
在src/main/resources文件夹下创建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"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><!--IOC 管理 bean--><bean id="userService" class="com.qcby.service.UserServiceImpl"/></beans>
4. 编写测试方法
import com.qcby.service.UserService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class Demo1 {/*** 入门程序*/@Testpublic void run1(){// 使用 Spring 的工厂ApplicationContext applicationContext = newClassPathXmlApplicationContext("spring.xml");// 通过工厂获得类:UserService userService = (UserService)applicationContext.getBean("userService");userService.hello();}}
2.3 IOC技术总结
-
ApplicationContext接口:工厂的接口,用于获取具体的Bean对象。常用的实现类有
ClassPathXmlApplicationContext
和FileSystemXmlApplicationContext
。 -
Bean管理:通过
id
、class
、scope
等属性配置Bean对象。 -
Bean对象的创建和销毁:通过
init-method
和destroy-method
属性配置Bean的生命周期方法。
2.4 实例化Bean对象的三种方式
1. 默认无参数构造方法
<bean id="us" class="com.qcby.service.UserServiceImpl"/>
2. 静态工厂实例化方式
public class StaticFactory {public static UserService createUs() {System.out.println("通过静态工厂的方式创建 UserServiceImpl 对
象...");return new UserServiceImpl();}
}
<bean id="us" class="com.qcby.demo1.StaticFactory" factory-method="createUs"/>
3. 实例工厂实例化方式
public class Dfactory {public UserService createUs() {System.out.println("实例化工厂的方式...");return new UserServiceImpl();}
}
<bean id="dfactory" class="com.qcby.demo1.Dfactory" />
<bean id="us" factory-bean="dfactory" factory-method="createUs" />
三、DI依赖注入
3.1 依赖注入的概述
DI(Dependency Injection,依赖注入)是Spring框架负责创建Bean对象时,动态地将依赖对象注入到Bean组件中的过程。
3.2 DI的两种方式
1. Setter方法注入
//OrderDao
package com.qcby.dao;public interface OrderDao {public void saveOrder();
}//OrderDaoImpl
package com.qcby.dao;public class OrderDaoImpl implements OrderDao{public void saveOrder() {System.out.println("持久层:保存订单...");}
}//OrderService
package com.qcby.service;public interface OrderService {public void saveOrder();
}//OrderServiceImpl
package com.qcby.service;import com.qcby.dao.OrderDao;public class OrderServiceImpl implements OrderService{//编写成员属性,一定需要提供该属性的 set 方法private OrderDao orderDao;//一定需要提供该属性的 set 方法,IOC 容器底层就通过属性的 set 方法方式注入值public void setOrderDao(OrderDao orderDao) {this.orderDao = orderDao;}//消息private String msg;//年龄private int age;public void setMsg(String msg) {this.msg = msg;}public void setAge(int age) {this.age = age;}public void saveOrder() {System.out.println("业务层:保存订单..."+msg+" - "+age);//调用orderDao.saveOrder();}
}
<!--DI:依赖注入--><bean id="os" class="com.qcby.service.OrderServiceImpl"><property name="orderDao" ref="od" /><property name="msg" value="你好" /><property name="age" value="30" /></bean><bean id="od" class="com.qcby.dao.OrderDaoImpl"></bean>
import com.qcby.service.OrderService;
import com.qcby.service.UserService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class Demo1 {@Testpublic void run3(){ApplicationContext applicationContext = newClassPathXmlApplicationContext("spring.xml");OrderService orderService = (OrderService)applicationContext.getBean("os");orderService.saveOrder(); //业务层:保存订单...你好 - 30 持久层:保存订单...}}
2. 构造器注入
package com.qcby.demo2;public class Car {// 名称private String cname;// 金额private Double money;public Car(String cname, Double money) {this.cname = cname;this.money = money;}@Overridepublic String toString() {return "Car{" +"cname='" + cname + '\'' +", money=" + money +'}';}
}
<!-- 属性构造方法方式注入值 --><bean id="car" class="com.qcby.demo2.Car"><constructor-arg name="cname" value="大奔" /><constructor-arg name="money" value="400000" /></bean>
@Testpublic void run4(){ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");Car car = (Car) context.getBean("car");System.out.println(car); //Car{cname='大奔', money=400000.0}}
3.3 复杂类型注入(数组,集合,Properties)
package com.qcby.demo3;import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Properties;public class CollectionBean {// 数组private String [] strs;public void setStrs(String[] strs) {this.strs = strs;}private List<String> list;public void setList(List<String> list) {this.list = list;}private Map<String,String> map;public void setMap(Map<String, String> map) {this.map = map;}private Properties properties;public void setProperties(Properties properties) {this.properties = properties;}@Overridepublic String toString() {return "CollectionBean{" +"strs=" + Arrays.toString(strs) +", list=" + list +", map=" + map +", properties=" + properties +'}';}
}
<!--给集合属性注入值--><bean id="collectionBean" class="com.qcby.demo3.CollectionBean"><property name="strs"><array><value>美美</value><value>小凤</value></array></property><property name="list"><list><value>熊大</value><value>熊二</value></list></property><property name="map"><map><entry key="aaa" value="老王"/><entry key="bbb" value="小王"/></map></property><property name="properties"><props><prop key="username">root</prop><prop key="password">123456</prop></props></property></bean>
@Testpublic void run5(){ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");CollectionBean collectionBean = (CollectionBean) context.getBean("collectionBean");System.out.println(collectionBean);//CollectionBean{strs=[美美, 小凤], list=[熊大, 熊二], map={aaa=老王, bbb=小王}, properties={password=123456, username=root}}}
四、多配置文件管理
通过<import>
标签或加载多个配置文件实现模块化配置:
<!-- 在主配置文件中配置 -->
<import resource="applicationContext2.xml" />
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml", "applicationContext2.xml"
);
五、Spring框架开发程序的方式
Spring框架开发方式:
以下是一个使用Spring框架开发程序的完整示例:
1. 创建Maven工程,导入开发的jar包
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.qcby</groupId><artifactId>spring02</artifactId><version>1.0-SNAPSHOT</version><dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.0.2.RELEASE</version></dependency><dependency><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId><version>1.2</version></dependency><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.12</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency><!--连接池--><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.10</version></dependency><!--mysql 驱动包--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.47</version></dependency></dependencies></project>
2. 创建数据库,创建表结构
create database spring_db;
use spring_db;
create table account(
id int primary key auto_increment,
name varchar(40),
money double
)character set utf8 collate utf8_general_ci;
insert into account(name,money) values('aaa',1000);
insert into account(name,money) values('bbb',1000);
insert into account(name,money) values('ccc',1000);
3. 编写JavaBean的类
package com.qcby.domain;import java.io.Serializable;public class Account implements Serializable{private static final long serialVersionUID = 7355810572012650248L;private Integer id;private String name;private Double money;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Double getMoney() {return money;}public void setMoney(Double money) {this.money = money;}@Overridepublic String toString() {return "Account{" +"id=" + id +", name='" + name + '\'' +", money=" + money +'}';}
}
4. 编写AccountDao的接口和实现类
package com.qcby.dao;import com.qcby.domain.Account;import java.util.List;public interface AccountDao {public List<Account> findAll();
}
package com.qcby.dao;import com.alibaba.druid.pool.DruidDataSource;
import com.qcby.domain.Account;import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;public class AccountDaoImpl implements AccountDao{// 注入连接池对象private DataSource dataSource;public void setDataSource(DataSource dataSource) {this.dataSource = dataSource;}/*** 查询所有的数据* @return*/public List<Account> findAll() {/*DruidDataSource dataSource = new DruidDataSource();dataSource.setDriverClassName("com.mysql.jdbc.Driver");dataSource.setUrl("jdbc:mysql:///spring_db");dataSource.setUsername("root");dataSource.setPassword("12345");*/List<Account> list=new ArrayList<Account>();Connection connection = null;PreparedStatement stmt = null;ResultSet rs = null;try {// 获取连接connection = dataSource.getConnection();// 编写 sql 语句String sql = "select * from account";// 预编译stmt = connection.prepareStatement(sql);// 查询rs = stmt.executeQuery();// 遍历,封装数据while (rs.next()){Account account = new Account();account.setId(rs.getInt("id"));account.setName(rs.getString("name"));account.setMoney(rs.getDouble("money"));list.add(account);}} catch (SQLException e) {e.printStackTrace();}finally {try {connection.close();} catch (SQLException e) {e.printStackTrace();}try {stmt.close();} catch (SQLException e) {e.printStackTrace();}try {rs.close();} catch (SQLException e) {e.printStackTrace();}}return list;}
}
5. 编写AccountService的接口和实现类
package com.qcby.service;import com.qcby.domain.Account;import java.util.List;public interface AccountService {public List<Account> findAll();
}
package com.qcby.service;import com.qcby.dao.AccountDao;
import com.qcby.domain.Account;import java.util.List;public class AccountServiceImpl implements AccountService{// 依赖注入private AccountDao accountDao;public void setAccountDao(AccountDao accountDao) {this.accountDao = accountDao;}/*** 查询所有的数据* @return*/public List<Account> findAll() {return accountDao.findAll();}
}
6. 编写配置文件
<?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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><!--配置连接池--><bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="driverClassName" value="com.mysql.jdbc.Driver"/><property name="url" value="jdbc:mysql:///spring_db" /><property name="username" value="root" /><property name="password" value="12345" /></bean><!--管理 bean--><bean id="accountService" class="com.qcby.service.AccountServiceImpl"><property name="accountDao" ref="accountDao" /></bean><bean id="accountDao" class="com.qcby.dao.AccountDaoImpl"><property name="dataSource" ref="dataSource" /></bean></beans>
7. 编程测试程序
import com.qcby.domain.Account;
import com.qcby.service.AccountService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;import java.util.List;public class Demo1 {@Testpublic void run1(){ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");AccountService accountService = (AccountService) ac.getBean("accountService");// 调用方法List<Account> list = accountService.findAll();for (Account account : list) {System.out.println(account);}}
}
六、IOC注解开发
6.1 半注解方式(XML + 注解)
1. 核心思想
在XML配置文件中开启注解扫描,结合代码中的注解(如@Component
、@Autowired
)管理Bean,部分配置仍依赖XML文件。
2. 实现步骤
-
开启注解扫描:在XML中配置
<context:component-scan>
,指定扫描的包路径。<beans xmlns:context="http://www.springframework.org/schema/context"><context:component-scan base-package="com.qcby"/> </beans>
-
定义Bean:在类上使用
@Component
及其衍生注解(@Service
,@Repository
,@Controller
)。@Service("userService") public class UserServiceImpl implements UserService {// ... }
-
依赖注入:
-
普通类型:使用
@Value
注入。@Value("Hello") private String message;
-
引用类型:使用
@Autowired
按类型注入,或@Qualifier
按名称注入。@Autowired @Qualifier("userDao") private UserDao userDao;
-
3. 常用注解
注解 | 作用 |
---|---|
@Component | 通用Bean注解,标识类为Spring管理的组件。 |
@Service | 标识业务层组件。 |
@Repository | 标识持久层组件(自动处理DAO层异常)。 |
@Autowired | 按类型自动注入依赖(默认按类型,可配合@Qualifier 按名称)。 |
@Scope | 定义Bean作用域(如singleton 、prototype )。 |
@PostConstruct | 初始化方法注解,等同于init-method 。 |
@PreDestroy | 销毁方法注解,等同于destroy-method 。 |
4. 示例
@Service("accountService")
public class AccountServiceImpl implements AccountService {@Autowiredprivate AccountDao accountDao;@Value("1000")private int initialBalance;
}
6.2 纯注解方式(零XML)
1. 核心思想
完全通过Java配置类(@Configuration
)和注解替代XML文件,实现全注解驱动的开发。
2. 实现步骤
-
定义配置类:使用
@Configuration
标识配置类,@ComponentScan
指定扫描包路径。@Configuration @ComponentScan("com.qcby") public class SpringConfig {}
-
注册Bean:
-
自动扫描:通过
@ComponentScan
自动注册标记了@Component
的类。 -
手动注册:在配置类中使用
@Bean
方法显式定义Bean。@Bean public DataSource dataSource() {DruidDataSource ds = new DruidDataSource();ds.setUrl("jdbc:mysql:///spring_db");return ds; }
-
-
加载配置类:通过
AnnotationConfigApplicationContext
加载配置类。ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
3. 常用注解
注解 | 作用 |
---|---|
| 标识当前类为配置类,替代XML文件。 |
| 指定扫描包路径,自动注册Bean。 |
| 在方法上定义Bean,方法返回值作为Bean实例(常用于第三方库的集成)。 |
| 引入其他配置类,实现模块化配置。 |
| 加载外部配置文件(如 |
4. 示例
@Configuration
@ComponentScan("com.qcby.demo4")
@Import(DataSourceConfig.class)
public class AppConfig {@Beanpublic DataSource dataSource() {DruidDataSource ds = new DruidDataSource();ds.setDriverClassName("com.mysql.jdbc.Driver");ds.setUrl("jdbc:mysql:///spring_db");return ds;}
}
6.3 对比分析
特性 | 半注解方式 | 纯注解方式 |
---|---|---|
配置文件 | 需要XML文件(开启扫描) | 完全无需XML,使用Java配置类 |
灵活性 | 适合遗留项目迁移或部分注解改造 | 适合新项目,完全面向注解开发 |
代码侵入性 | 较低(仅需少量注解) | 较高(需编写配置类) |
典型场景 | 逐步替换XML中的Bean定义 | 微服务、Spring Boot项目 |
依赖注入 | 支持 | 完全通过注解实现 |
七、Spring 框架整合 JUnit 单元测试
在传统的单元测试中,每次测试都需要手动创建Spring容器、加载配置文件,这不仅增加了代码量,还降低了测试效率。Spring框架针对这一问题提供了整合JUnit的解决方案,使得单元测试更加简洁高效。
7.1 基于XML配置的Spring整合JUnit测试
1. 环境准备
首先确保项目中已导入JUnit和Spring-test依赖:
<dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope>
</dependency>
<dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>5.0.2.RELEASE</version><scope>test</scope>
</dependency>
2. 编写类和方法,把该类交给 IOC 容器进行管理
package com.qcby.demo5;public class User {public void sayHello() {System.out.println("Hello....");}
}
3. 编写配置文件
<?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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><!--整合单元测试--><bean id="user" class="com.qcby.demo5.User"/>
</beans>
4. 编写测试类
package com.qcby.test;import com.qcby.demo5.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;/*** Spring整合JUnit单元测试(XML配置方式)*/
@RunWith(SpringJUnit4ClassRunner.class) // 使用Spring的测试运行器
@ContextConfiguration(value = "classpath:spring.xml") // 加载Spring配置文件
public class Demo5 {@Autowired // 自动注入User对象private User user;@Testpublic void run1() {user.sayHello(); // 调用被测试方法}
}
关键点说明:
-
@RunWith(SpringJUnit4ClassRunner.class)
:指定使用Spring的测试运行器 -
@ContextConfiguration
:指定Spring配置文件位置 -
@Autowired
:自动注入被测试对象
7.2 纯注解方式的Spring整合JUnit测试
1. 编写类和方法
package com.qcby.demo6;import org.springframework.stereotype.Component;@Component
public class Customer {public void save() {System.out.println("保存客户...");}
}
2. 编写配置类
package com.qcby.demo6;import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;/*** Spring配置类(替代XML配置)*/
//声明
@Configuration
@ComponentScan(value = "com.qcby.demo6") // 扫描指定包下的组件
public class SpringConfig6 {
}
3. 编写测试类
package com.qcby.test;import com.qcby.demo6.Customer;
import com.qcby.demo6.SpringConfig6;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;/*** Spring整合JUnit单元测试(纯注解方式)*/
@RunWith(SpringJUnit4ClassRunner.class)
//加载配置类
@ContextConfiguration(classes = SpringConfig6.class) // 指定配置类
public class Demo6 {//按类型注入@Autowiredprivate Customer customer;@Testpublic void run1() {customer.save(); // 调用被测试方法}
}
关键点说明:
-
使用
@Configuration
和@ComponentScan
替代XML配置 -
@ContextConfiguration(classes = ...)
指定配置类 -
其余部分与XML方式类似
7.3 对比分析
特性 | XML配置方式 | 纯注解方式 |
---|---|---|
配置方式 | 使用XML文件 | 使用Java配置类 |
灵活性 | 较低,修改需修改XML文件 | 较高,可直接修改Java代码 |
可读性 | 结构清晰,适合复杂配置 | 简洁,适合简单配置 |
维护性 | 配置分散,维护成本较高 | 配置集中,维护成本较低 |
适用场景 | 大型项目,需要精细控制Bean创建 | 中小型项目,快速开发和迭代 |
总结
Spring框架通过IOC和AOP机制,彻底改变了Java企业级开发的方式。无论是基础的Bean管理,还是复杂的多数据源配置,Spring都提供了优雅的解决方案。掌握这些核心技术与高级特性,不仅能提升代码质量,还能大幅提高开发效率。在实际项目中,建议结合Spring Boot进一步简化配置,快速构建微服务应用。
相关文章:
Spring框架(一)
Spring框架是Java开发中最为流行的框架之一,它以其强大的功能和灵活的设计,极大地简化了企业级应用的开发。本文将详细介绍Spring框架的核心概念、核心技术、依赖注入、多配置文件方式、开发程序的方式、IOC注解方式以及Spring与JUnit的整合。 目录 一、…...
Redis 基础详解:从入门到精通
在当今互联网应用开发领域,数据存储与处理的性能和效率至关重要。Redis(Remote Dictionary Server)作为一款开源的、基于内存的键值存储系统,凭借其出色的性能和丰富的功能,被广泛应用于数据库、缓存、消息中间件等场景…...
24、TypeScript:预言家之书——React 19 类型系统
一、预言家的本质 "TypeScript是魔法世界的预言家之书,用静态类型编织代码的命运轨迹!" 霍格沃茨符文研究院的巫师挥动魔杖,类型注解与泛型的星轨在空中交织成防护矩阵。 ——基于《国际魔法联合会》第12号类型协议,Ty…...
RabbitMQ--进阶篇
RabbitMQ 客户端整合Spring Boot 添加相关的依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId> </dependency> 编写配置文件,配置RabbitMQ的服务信息 spri…...
【GESP真题解析】第 19 集 GESP 二级 2025 年 3 月编程题 1:等差矩阵
大家好,我是莫小特。 这篇文章给大家分享 GESP 二级 2025 年 3 月编程题第 1 题:等差矩阵。 题目链接 洛谷链接:B4259 等差矩阵 一、完成输入 根据题意,一行,两个正整数 n,m。 n 和 m的数据范围…...
电池单元和电极性能
电芯设计中的挑战 对于电池制造商来说,提高电池能量和功率密度至关重要。在高功率密度和长循环寿命之间取得平衡是电池设计中的关键挑战,通常需要仔细优化材料、电极结构和热管理系统。另一个关键挑战是通过优化重量体积比来降低电池单元的总体成本。 工…...
MATLAB 矩阵与数组操作基础教程
文章目录 前言环境配置一、创建矩阵与数组(一)直接输入法(二)特殊矩阵生成函数(三)使用冒号表达式创建数组 二、矩阵与数组的基本操作(一)访问元素(二)修改元…...
理解 Token 索引 vs 字符位置
以下是对“理解 Token 索引与字符位置的区别”的内容整理,条理清晰,结构完整,保持技术细节,方便阅读,无多余解释: 🔍 理解 Token 索引 vs 字符位置 文本分块方法中返回的索引是 token 索引&…...
【RAG】11种Chunking Strategies分块策略介绍和选择
【今日鸡汤】学习之路上,勤奋是比 “聪明” 远远更珍贵的品质。 参考原文地址:https://masteringllm.medium.com/11-chunking-strategies-for-rag-simplified-visualized-df0dbec8e373 在构建强大的检索增强生成(RAG)系统时&…...
中继器:网络中的“血包”与“加时器”
在探讨网络技术时,我们往往会遇到各种专业术语和设备,中继器便是其中之一。然而,对于非技术人员或初学者来说,这些概念可能显得抽象且难以理解。今天,我将通过一个生动的比喻——将中继器比作网络中的“血包”与“加时…...
证明当||x||=1时,Ax=0的最小二乘解是的最小特征值对应的特征向量
问题:证明当||x||1时,Ax0的最小二乘解是的最小特征值对应的特征向量。 证明: 上个命题等同于:的最小特征值所对应的特征向量可使得||Ax||最小。以下分别对x为的特征向量和不为的特征向量这两种情况进行证明。 情况1: 若x为的特征…...
AI大模型学习十八、利用Dify+deepseekR1 +本地部署Stable Diffusion搭建 AI 图片生成应用
一、说明 最近在学习Dify工作流的一些玩法,下面将介绍一下Dify Stable Diffusion实现文生图工作流的应用方法 Dify与Stable Diffusion的协同价值 Dify作为低代码AI开发平台的优势:可视化编排、API快速集成 Stable Diffusion的核心能力:高效…...
linux基础操作4------(权限管理)
一.前言 今天我们来讲讲linux的权限管理,比如文件的权限,如果大家看过前面说的app逆向的frida,我们在手机里要给frida,我们都要设置一下chomd 777 frida ,这样就给了可执行权限,这就是这一章要讲的&#x…...
Linux数据库篇、第零章_MySQL30周年庆典活动
MySQL考试报名网站 Oracle Training and Certification | Oracle 中国 活动时间 2025年 MySQL的30周年庆典将于2025年举行。MySQL于1995年首次发布,因此其30周年纪念日是2025年。为了庆祝这一里程碑,MySQL将提供免费的课程和认证考试,活动…...
HVV面试题汇总合集
应急响应的命令 Linux ps -aux 查看进程 netstat -antlp 查看端口 top查看 cpu使用情况 Windows tasklist 查看进程 netstat -an 查看端口struts2原理特征 原理: 045:默认的content-type解析器会把用户传来的数据直接当成代码执行,造成rce 特征:ognl表达式&…...
Mac下Robotframework + Python3环境搭建
1.安装python3 1.0安装XCODE 1.打开浏览器,登陆苹果开发者网站:https://developer.apple.com/download/more/ 2.登陆你的apple账号,授权访问。 3.查看mac系统版本 需要下载与系统版本对应的Xcode 4.在搜索框中输入: 如果Mac 系统…...
stm32实战项目:无刷驱动
目录 系统时钟配置 PWM模块初始化 ADC模块配置 霍尔接口配置 速度环定时器 换相逻辑实现 主控制循环 系统时钟配置 启用72MHz主频:RCC_Configuration()设置PLL外设时钟使能:TIM1/ADC/GPIO时钟 #include "stm32f10x.h"void RCC_Configu…...
MNIST 手写数字分类
转自我的个人博客: https://shar-pen.github.io/2025/05/04/torch-distributed-series/1.MNIST/ 基础的单卡训练 本笔记本演示了训练一个卷积神经网络(CNN)来对 MNIST 数据集中的手写数字进行分类的过程。工作流程包括: 数据准备ÿ…...
【RuntimeError: Directory ‘static/‘ does not exist 】
背景 File “/root/miniforge3/lib/python3.10/site-packages/starlette/staticfiles.py”, line 56, in init raise RuntimeError(f"Directory ‘{directory}’ does not exist") RuntimeError: Directory ‘static/’ does not exist 运行读取pdf时候,…...
SQL:SELF JOIN(自连接)与CROSS JOIN(交叉连接)
目录 SELF JOIN(自连接) CROSS JOIN(交叉连接 / 笛卡尔积) 示例: SELF JOIN CROSS JOIN 如果没有 DATEDIFF() 函数怎么办? 🔍 SELF JOIN vs CROSS JOIN 对比总结 SELF JOIN(自…...
Linux网络基础 -- 局域网,广域网,网络协议,网络传输的基本流程,端口号,网络字节序
目录 1. 计算机网络背景 1.1 局域网 1.1.2 局域网的组成 1.2 广域网 1.1.2 广域网的组成 2. 初始网络协议 2.1 网络协议的定义和作用 2.2 网络协议的分层结构 2.2.1 OSI七层模型 2.2.2 TCP/IP 五层(四层)模型 3. 再识网络协议 3.1 为什么要有…...
当 Manus AI 遇上 OpenAI Operator,谁能更胜一筹?
自主智能体通过实现任务自动化,改变了我们与技术交互的方式,让我们的生活变得更加便捷。去年,OpenAI 为人工智能聊天机器人引入了定时任务和操作智能体,赋予了其代理功能,而 Anthropic 则在 Claude 上实现了类似的功能…...
iOS实名认证模块的具体实现过程(swift)
实名认证是当前APP的一个基础功能了,今天我集成了实名认证模块在iOS应用中的具体实现步骤,结合技术细节与最佳实践: 一、手机号验证 1. 发送短信验证码 技术实现:// 使用Alamofire调用第三方短信API AF.request("https://s…...
UE5定序器中摇臂挂载摄像机 让摄像机始终朝向目标
1. 搭建摄像机摇臂并加入 Sequencer 在关卡中: Cinematics → Add Level Sequence,新建并打开一个 Level Sequence。 在视口里 右键 → Cinematic → Cine Camera Actor Rig → Crane,放一个 CameraRig_Crane。 默认 Crane 自带一个 CineCa…...
Redis BigKey 问题是什么
BigKey 问题是什么 BigKey 的具体表现是 redis 中的 key 对应的 value 很大,占用的 redis 空间比较大,本质上是大 value 问题。 BigKey怎么找 redis-cli --bigkeysscanBig Key 产生的原因 1.redis数据结构使用不恰当 2.未及时清理垃圾数据 3.对业务预…...
硬件中断请求号和lspci命令查看到的device id有关系吗?
这是我忽然想到的一个人问题 硬件中断请求号(IRQ)与lspci命令查看到的设备ID(Device ID)没有直接对应关系,但两者在系统硬件管理中通过以下方式间接关联: 一、硬件层面的独立标识 Device ID的本质…...
Qt 中 QWidget涉及的常用核心属性介绍
欢迎来到干货小仓库 一匹真正的好马,即使在鞭子的影子下,也能飞奔 1.enabled API说明isEnabled()获取到控件的可用状态setEnabled()设置控件是否可使用.true:可用,false:禁用 禁用:指该控件不能接收任何用…...
编程日志5.3
串的习题 1.Problem - 2030 #include<iostream> using namespace std; int main() { char s[500]; int n; cin >> n; getchar();//去掉空格部分 while (n--) { gets(s);//老式写法 vs显示错误题目解答正确 int cnt 0; …...
sql的性能分析
慢查询日志:通过慢查询日志需要优化的sql语句。 慢查询日志记录了所有执行时间超过指定参数的所有sql语句。 开启慢日志查询开关:show_query_log1 设置慢查询日志的时间:long_query_time?。 show variables like ‘slow_query_log’&…...
JAVA 锁—— synchronized
32 位机器上java对象头中,markWord 示意图如上所示,64 位机器扩展前面标识位数,如 hashcode(25 -> 31),线程ID(23 -> 54) 如果启用了偏向锁: synchronized添加偏向锁:只有1个线程加锁的情况下&#…...
游戏引擎学习第274天:基于弹簧的动态动画
回顾前一天内容,并为今天的工作设定目标 我们昨天展示了一些内容,现在先回顾一下昨天的进展。我们目前正在处理的是角色跳跃的动画——特别是身体部分的跳跃。 现在角色的动画状态如下: 正在实现角色的移动和跳跃。跳跃中已经加入了一些预备…...
【英语笔记(二)】句子成分、基本句型;简单描述十大词类与从句的分类、助动词和非谓语动词的使用
1. 介词 at, in, on 的用法区别 1.1 表示时间的区别 1. 表示时间的某一点、某一时刻或年龄等用 at。如: I get up at six in the morning. 我早上六点钟起床。He got married at the age of 25. 他 25 岁结婚。 2. 泛指一般意义的上午、下午或晚上以及月或年等较…...
TAPIP3D:持久3D几何中跟踪任意点
简述 在视频中跟踪一个点(比如一个物体的某个特定位置)听起来简单,但实际上很复杂,尤其是在3D空间中。传统方法通常在2D图像上跟踪像素,但这忽略了物体的3D几何信息和摄像机的运动,导致跟踪不稳定…...
RabbitMQ的工作队列模式和路由模式有什么区别?
RabbitMQ 的工作队列模式(Work Queues)和路由模式(Routing)是两种不同的消息传递模式,主要区别在于消息的分发逻辑和使用场景。以下是它们的核心差异: 1. 工作队列模式(Work Queues)…...
armv7 backtrace
ref: ARM Cortex-M3/M4/M7 Hardfault异常分析_arm hardfault-CSDN博客...
Python并发编程:开启性能优化的大门(7/10)
1.引言 在当今数字化时代,Python 已成为编程领域中一颗璀璨的明星,占据着编程语言排行榜的榜首。无论是数据科学、人工智能,还是 Web 开发、自动化脚本编写,Python 都以其简洁的语法、丰富的库和强大的功能,赢得了广大…...
泰勒展开式
常用的 泰勒展开式(Taylor series expansion)是指把一个函数在某点的邻域内展开成幂级数的形式。以函数 f ( x ) f(x) f(x) 在点 a a a 处展开为例,其泰勒展开式为: f ( x ) f ( a ) f ′ ( a ) ( x − a ) f ′ ′ ( a ) 2 …...
深入理解 Polly:.NET Core 中的健壮错误处理策略
在现代软件开发中,错误处理是构建高可用、健壮系统的关键之一。尤其是当应用依赖外部服务(如 API、数据库或其他网络资源)时,临时的服务中断、超时或其他不可预见的错误都会影响应用的稳定性。为了提升系统的容错能力,…...
【Bootstrap V4系列】学习入门教程之 组件-巨幕(Jumbotron)和列表组(List group)
Bootstrap V4系列 学习入门教程之 组件-巨幕(Jumbotron)和列表组(List group) 一、巨幕(Jumbotron)1.1 带有圆角1.2 全宽且无圆角 二、列表组(List group)2.1 Basic example2.2 Acti…...
02.three官方示例+编辑器+AI快速学习webgl_animation_skinning_blending
本实例主要讲解内容 这个示例展示了Three.js中骨骼动画混合(Skeletal Animation Blending)的实现方法,通过加载一个士兵模型,演示了如何在不同动画状态(如站立、行走、跑步)之间进行平滑过渡。核心技术包括动画混合器(AnimationM…...
华为云Flexus+DeepSeek征文|DeepSeek-V3/R1商用服务开通教程以及模型体验
在当今数字化浪潮迅猛推进的时代,云计算与人工智能技术的深度融合正不断催生出众多创新应用与服务,为企业和个人用户带来了前所未有的便利与发展机遇。本文将重点聚焦于在华为云这一行业领先的云计算平台上,对 DeepSeek-V3/R1 商用服务展开的…...
大语言模型通过MCP控制STM32-支持Ollama、DeepSeek、openai等
MCP控制STM32 MCP部分 1.下载源码 git clone https://github.com/ana52070/MCP_Control_STM32.git cd MCP_Control_STM32 cd mcp-led_oled2. 创建并激活虚拟环境 为了避免不同项目之间的依赖冲突,建议使用虚拟环境。根据你的操作系统和 Python 版本,…...
Linux-Ubuntu安装Stable Diffusion Forge
SD Forge在Win上配置起来相对简单且教程丰富,而在Linux平台的配置则稍有门槛且教程较少。本文提供一个基于Ubuntu24.04发行版(对其他Linux以及SD分支亦有参考价值)的Stable Diffusion ForgeUI安装配置教程,希望有所帮助 本教程以N…...
LoRA(Low-Rank Adaptation)原理详解
LoRA(Low-Rank Adaptation)原理详解 LoRA(低秩适应)是一种参数高效微调(Parameter-Efficient Fine-Tuning, PEFT)技术,旨在以极低的参数量实现大模型在特定任务上的高效适配。其核心思想基于低秩分解假设,即模型在适应新任务时,参数更新矩阵具有低秩特性,可用少量参…...
分享一个可以用GPT打标的傻瓜式SD图片打标工具——辣椒炒肉图片打标助手
一、打标效果展示 请参考下图,了解最终的打标效果: 打标速度提升百分之300; 打标成本: gpt4o每百张图约5毛rmb; gpt4o-mini价格更低; 更有claude,grok,gemini,豆包等…...
实战项目2(03)
目录 任务场景一【重点】 【sw1配置】 【sw2配置】 任务场景二【重点】 【sw1配置】 【sw2配置】 【sw3配置】 任务场景一【重点】 掌握基于SVI实现跨VLAN通信——某公司网络为了减少广播包对网络的影响,网络管理员对网络进行了VLAN划分,完成VLA…...
PyCharm软件下载和配置Python解释器
以下是详细的PyCharm下载及解释器环境配置步骤: 有什么问题可以留评论(看见会回复的) 一、PyCharm下载 1. 访问官网 进入JetBrains官网:https://www.jetbrains.com/pycharm/ 2. 选择版本 Community版(免费&…...
《从零构建一个简易的IOC容器,理解Spring的核心思想》
大家好呀!今天我们要一起探索Java开发中最神奇的魔法之一 —— Spring框架的IOC容器!🧙♂️ 我会用最最最简单的方式,让你彻底明白这个看似高深的概念。准备好了吗?Let’s go! 🚀 一、什么是IOC容器&…...
差分与位移算子
差分与位移算子是数值分析和离散数学中处理序列或离散函数的重要工具。它们通过算子代数简化差分的计算和分析,以下是关键概念和关系的总结: 1. 位移算子(Shift Operator) 定义: 位移算子 ( E ) 将函数 ( f(x) ) 沿自变…...
Robot之VideoMimic:《Visual Imitation Enables Contextual Humanoid Control》翻译与解读
Robot之VideoMimic:《Visual Imitation Enables Contextual Humanoid Control》翻译与解读 导读:这篇论文介绍了VIDEOMIMIC,一个基于视觉模仿的真实到模拟到真实流水线,用于训练人形机器人执行上下文相关的全身动作。该方法通过分…...