Spring6
- Study notes: Spring 6 basics_ljtxy.love’s blog-CSDN blog
- Study Notes: Spring 6 Advanced Chapter_ljtxy.love’s Blog-CSDN Blog
Article directory
- 7. Unit testing: JUnit
- 8. Affairs
-
- 8.1 Overview
- 8.2 Annotation-based declarative transactions
-
- 8.2.1 Basic use case-implementing annotated declarative transactions
- 8.2.2 Transaction attributes: read-only
- 8.2.3 Transaction attributes: timeout
- 8.2.4 Transaction attributes: rollback strategy
- 8.2.5 Transaction attributes: isolation level
- 8.2.6 Transaction attributes: propagation behavior
- 8.2.7 Full annotation configuration transactions (key points)
- 8.2.8 Underlying principles
- 8.3 XML-based declarative transactions (understanding)
- 9. Resource operations: Resources
- 10. Internationalization: i18n
- 11. Data verification: Validation
- 12. Ahead of time compilation: AOT
- knowledge gas station
7. Unit testing: JUnit
Summary of notes:
Overview: JUnit is a unit testing framework for the Java programming language
Basic use case:
Step 1: Introduce dependencies: Junit support dependencies, Junit5 tests
Step 2: Configuration file: configure basic class scanning
Step 3: Demonstration: Use the **@SpringJUnitConfig(locations = “classpath:beans.xml”)** annotation to automatically load the configuration file and create the class
7.1 Overview
JUnit is a unit testing framework for the Java programming language. It was created by Erich Gamma and Kent Beck and has gradually become one of the standard unit testing frameworks for the Java language. JUnit provides some annotations and assertion methods to help developers write and run test cases. It can also integrate with build tools such as Maven and Gradle to facilitate continuous integration and automated testing
7.2 Basic use cases
Step 1: Introduce dependencies
<!--spring对junit的支持相关依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>6.0.2</version>
</dependency>
<!--junit5测试-->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.9.0</version>
</dependency>
Step 2: Configuration file
<?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.atguigu.spring6.bean"/>
</beans>
illustrate:
Configuration class scanning for automatically assembling beans
Step 3: Create the class
@Component
public class User {
public User() {
System.out.println("run user");
}
}
Step 4: Demonstrate
@SpringJUnitConfig(locations = "classpath:beans.xml")
public class SpringJUnit5Test {
@Autowired
private User user;
@Test
public void testUser(){
System.out.println(user);
}
}
illustrate:
The @SpringJUnitConfig annotation is used to specify Spring's configuration file. Before the test method is run, Spring will first create the required beans based on the configuration file and then inject them into the test class. In this way, you can directly use Spring's beans in the test class for testing.
The class is:
ApplicationContext context = new ClassPathXmlApplicationContext("xxx.xml"); Xxxx xxx = context.getBean(Xxxx.class);
This code is loaded through
ApplicationContext
the classpath xml context of the interfaceClassPathXmlApplicationContext
8. Affairs
Summary of notes:
- Overview:
- Definition: A transaction is one or more data operations that either succeed or fail
- characteristic:
- Atomicity : either all succeed or all fail
- Consistency : After the transaction execution fails, the data in the database does not change
- Isolation : Multiple transactions are isolated from each other
- Durability : After the transaction is completed, the data in the database should be stored normally and persistently
- Programmatic transactions: use code to process transactions
- Declarative transactions: Use annotations to process transactions. Annotation **@Transactional**
- Annotation-based declarative transactions: please read this section in detail
- XML-based declarative transactions (understanding): defining and applying aspects through XML
8.1 Overview
8.1.1 Definition
A transaction refers to a logical unit of work consisting of one or more sequences of operations. These operations either all succeed or all fail and are rolled back. In the database, a transaction contains one or more data operations, such as adding, deleting, modifying, etc. At the same time, these operations must either all succeed or all fail. Only some operations cannot succeed or fail.
8.1.2 Features
- Atomicity: A transaction is an indivisible unit of work that either all succeeds or all fails. Partial success and partial failure are not allowed.
- Consistency: The state of the database should remain consistent before and after a transaction is executed. If a transaction fails to execute, the database should be restored to the state before execution.
- Isolation: Multiple transactions should be isolated from each other, and transactions cannot interfere with each other to avoid problems such as dirty reads, non-repeatable reads, and phantom reads.
- Durability: After the transaction is completed, the modifications to the database should be persisted. Even if the system fails or crashes, the data should not be lost.
8.2.3 Programmatic Transactions
Programmatic transactions are implemented by writing transaction management code in the code. It is necessary to manually control the start, submission and rollback of transactions. It is necessary to write relevant code in each method that requires transaction management, so that the code coupling is high and The transaction management code appears repeatedly and is inconvenient to maintain.
Connection conn = ...;
try {
// 开启事务:关闭事务的自动提交
conn.setAutoCommit(false);
// 核心操作
// 提交事务
conn.commit();
}catch(Exception e){
// 回滚事务
conn.rollBack();
}finally{
// 释放数据库连接
conn.close();
}
8.2.4 Declarative transactions
Declarative transactions are implemented through AOP, which separates transaction management code from business logic. By declaring transaction management in the configuration file, automatic management of transactions is achieved. Developers only need to add methods that require transaction management. Just annotate or configure it, which greatly simplifies code writing and maintenance work.
public interface UserService {
void updateUser(User user);
}
@Service
@Transactional
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao;
@Override
public void updateUser(User user) {
userDao.update(user);
}
}
illustrate:
- In this example,
@Transactional
annotations are used at the class level of the service implementation class. This means that whenupdateUser
the method is called, Spring will create a transaction, and when the method execution ends, the transaction will be committed or rolled back (if an exception occurs)- In this way, when calling
updateUser
the method, we do not need to explicitly open and commit the transaction, the Spring framework will automatically handle the transaction submission and rollback
8.2 Annotation-based declarative transactions
Note section:
Basic use case:
Step 1: Add tx namespace , add transaction manager , and enable transaction annotation driver
Step 2: Add transaction annotation : @Transactional
Transaction attributes:
- Read-only : @Transactional( readOnly = true), tells the database that this operation can only be read and not rewritten.
- Timeout : @Transactional( timeout = 3), when this operation times out, prompt
- Rollback strategy :
- rollbackFor attribute: When the transaction method throws an exception of the specified type, the transaction will be rolled back
- rollbackForClassName attribute: similar to the rollbackFor attribute, but uses a string when specifying the exception type
- noRollbackFor attribute: Specifies that the transaction will not be rolled back when the transaction method throws an exception of the specified type.
- noRollbackForClassName attribute: Similar to the noRollbackFor attribute, but uses a string when specifying the exception type
- Isolation level :
READ_UNCOMMITTED
: Indicates that a transaction can read data from another uncommitted transaction. Dirty reads, non-repeatable reads, and phantom reads may occur at this level, and are generally not recommended.READ_COMMITTED
: Indicates that a transaction can only read the data of another committed transaction, which can avoid dirty read problems, but non- repeatable read and phantom read problems may still occur.REPEATABLE_READ
: Indicates that a transaction can read the same row of data multiple times during execution, which can avoid dirty read and non-repeatable read problems, but phantom read problems may still occur .SERIALIZABLE
: Indicates that a transaction locks all data involved during execution, avoiding the problems of dirty reads, non-repeatable reads, and phantom reads, but the concurrency performance is very poor .- Propagation behavior : The propagation behavior of a transaction refers to the rules that control how transactions propagate and affect each other's behavior when multiple transaction methods call each other.
- Full annotation configuration transaction : @EnableTransactionManagement turns on annotation transaction management
8.2.1 Basic use case-implementing annotated declarative transactions
Step 1: Add the tx namespace and configuration in the configuration file
<?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:tx="http://www.springframework.org/schema/tx"
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
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!--事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="druidDataSource"/>
</bean>
<!--
开启事务的注解驱动。通过注解@Transactional所标识的方法或标识的类中所有的方法,都会被事务管理器管理事务-->
<!-- transaction-manager属性的默认值是transactionManager,如果事务管理器bean的id正好就是这个默认值,则可以省略这个属性 -->
<tx:annotation-driven transaction-manager="transactionManager" />
</beans>
illustrate:
- Add tx namespace
- Add transaction manager
- Enable transaction annotation driver
Step 2: Add transaction annotations
@Transactional
public void buyBook(Integer bookId, Integer userId) {
//查询图书的价格
Integer price = bookDao.getPriceByBookId(bookId);
//更新图书的库存
bookDao.updateStock(bookId);
//更新用户的余额
bookDao.updateBalance(userId, price);
//System.out.println(1/0);
}
illustrate:
- The Service layer represents the business logic layer. Annotations are usually added to the functions of the business layer to achieve the purpose of transaction management.
- The @Transactional annotation marked on the method will only affect the method to be managed by the transaction management tool. The @Transactional annotation is marked on a class, which will affect all methods in the class to be managed by the transaction management tool.
Step 3: Demo
illustrate:
If an error occurs during the operation transaction, the Spring framework will help us automatically roll back the data
8.2.2 Transaction attributes: read-only
For a query operation, if we set it to read-only, we can clearly tell the database that this operation does not involve write operations. This allows the database to be optimized for query operations
@Transactional(readOnly = true)
public void buyBook(Integer bookId, Integer userId) {
//查询图书的价格
Integer price = bookDao.getPriceByBookId(bookId);
//更新图书的库存
bookDao.updateStock(bookId);
//更新用户的余额
bookDao.updateBalance(userId, price);
//System.out.println(1/0);
}
illustrate:
At this time, the transaction read-only attribute has been added to the transaction, so adding, deleting, and modifying operations will throw an exception:
Caused by: java.sql.SQLException: Connection is read-only. Queries leading to data modification are not allowed
8.2.3 Transaction attributes: timeout
During the execution of a transaction, certain problems may be encountered, causing the program to get stuck, thus occupying database resources for a long time. If resources are occupied for a long time, it is most likely because there is a problem with the program running (it may be a Java program or a MySQL database or a network connection, etc.). At this time, the program that is likely to have problems should be rolled back, the operations it has done should be undone, the transaction should be ended, and the resources should be released so that other normal programs can be executed.
//超时时间单位秒
@Transactional(timeout = 3)
public void buyBook(Integer bookId, Integer userId) {
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
//查询图书的价格
Integer price = bookDao.getPriceByBookId(bookId);
//更新图书的库存
bookDao.updateStock(bookId);
//更新用户的余额
bookDao.updateBalance(userId, price);
//System.out.println(1/0);
}
illustrate:
At this time, the transaction timeout attribute has been added to the transaction, so if the check and modification operation exceeds the unit time, an exception will be thrown:
org.springframework.transaction.TransactionTimedOutException: Transaction timed out: deadline was Fri Jun 04 16:25:39 CST 2022
8.2.4 Transaction attributes: rollback strategy
The rollback strategy in the transaction attributes refers to how to handle the commit or rollback of the transaction when an exception occurs in the transaction
Attribute classification:
-
rollbackFor attribute: When the transaction method throws an exception of the specified type, the transaction will be rolled back
@Transactional(rollbackFor = { SQLException.class, IOException.class})
-
rollbackForClassName attribute: similar to the rollbackFor attribute, but uses a string when specifying the exception type
@Transactional(rollbackForClassName = { "java.sql.SQLException", "java.io.IOException"})
-
noRollbackFor attribute: Specifies that the transaction will not be rolled back when the transaction method throws an exception of the specified type.
@Transactional(noRollbackFor = { NullPointerException.class, IllegalArgumentException.class})
-
noRollbackForClassName attribute: Similar to the noRollbackFor attribute, but uses a string when specifying the exception type
@Transactional(noRollbackForClassName = { "java.lang.NullPointerException", "java.lang.IllegalArgumentException"})
Basic use case:
@Transactional(noRollbackFor = ArithmeticException.class)
//@Transactional(noRollbackForClassName = "java.lang.ArithmeticException")
public void buyBook(Integer bookId, Integer userId) {
//查询图书的价格
Integer price = bookDao.getPriceByBookId(bookId);
//更新图书的库存
bookDao.updateStock(bookId);
//更新用户的余额
bookDao.updateBalance(userId, price);
System.out.println(1/0);
}
illustrate:
At this time, the attribute configured by the @Transactional annotation is
noRollbackFor
, so whenArithmeticException.class
such an exception occurs, the transaction will not be rolled back
8.2.5 Transaction attributes: isolation level
Transaction isolation level refers to an isolation mechanism adopted by the database in order to ensure data consistency between transactions when multiple transactions are executed concurrently.
isolation level | dirty read | non-repeatable read | phantom reading |
---|---|---|---|
READ UNCOMMITTED | have | have | have |
READ COMMITTED | none | have | have |
REPEATABLE READ | none | none | have |
SERIALIZABLE | none | none | none |
illustrate:
- READ_UNCOMMITTED: Indicates that a transaction can read data from another uncommitted transaction. Dirty reads, non-repeatable reads, and phantom reads may occur at this level, and are generally not recommended.
- READ_COMMITTED: Indicates that a transaction can only read the data of another committed transaction, which can avoid dirty read problems, but non-repeatable read and phantom read problems may still occur.
- REPEATABLE_READ: Indicates that a transaction can read the same row of data multiple times during execution, which can avoid dirty read and non-repeatable read problems, but phantom read problems may still occur.
- SERIALIZABLE: Indicates that a transaction locks all data involved during execution, avoiding the problems of dirty reads, non-repeatable reads, and phantom reads, but the concurrency performance is very poor.
Basic usage
@Transactional(isolation = Isolation.DEFAULT)//使用数据库默认的隔离级别
@Transactional(isolation = Isolation.READ_UNCOMMITTED)//读未提交
@Transactional(isolation = Isolation.READ_COMMITTED)//读已提交
@Transactional(isolation = Isolation.REPEATABLE_READ)//可重复读
@Transactional(isolation = Isolation.SERIALIZABLE)//串行化
8.2.6 Transaction attributes: propagation behavior
Transaction propagation behavior refers to the rules that control how transactions propagate and affect each other's behavior when multiple transaction methods call each other. In the Spring framework, transaction propagation behavior Propagation
is defined by enumeration classes. Commonly used propagation behaviors include the following:
- REQUIRED (default): If a transaction currently exists, join the transaction; if there is no current transaction, create a new transaction. In other words, if it doesn’t exist, create a new one, and if it exists, add it.
- SUPPORTS: If there is currently a transaction, join the transaction; if there is no transaction, continue running in a non-transactional manner. In other words, if you have it, join it; if you don’t have it, leave it alone.
- MANDATORY: If there is currently a transaction, join the transaction; if there is no transaction, throw an exception. In other words, if it exists, add it, if not, throw an exception.
- REQUIRES_NEW: Create a new transaction. If a transaction currently exists, suspend the current transaction. In other words, whether there is or not, a new transaction is opened directly. There is no nesting relationship between the new transaction and the previous transaction, and the previous transaction is suspended.
- NOT_SUPPORTED: Run in non-transactional mode. If a transaction currently exists, the current transaction will be suspended. In other words, transactions are not supported and will be suspended if they exist.
- NEVER: Run in non-transactional mode and throw an exception if a transaction currently exists. In other words, if transactions are not supported, an exception will be thrown if they exist.
- NESTED: If there is currently a transaction, it will be executed in a nested transaction; if there is no current transaction, it will be executed according to PROPAGATION_REQUIRED. In other words, if there is a transaction, a completely independent transaction can be nested in this transaction, and the nested transaction can be committed and rolled back independently. No transaction is the same as REQUIRED
@Transactional(propagation = Propagation.REQUIRED)
public void transactionalMethod() {
// ...
}
8.2.7 Full annotation configuration transactions (key points)
Step 1: Add configuration class
package com.atguigu.spring6.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
@Configuration // 表示该类为配置类
@ComponentScan("com.atguigu.spring6") // 开启组件扫描,扫描com.atguigu.spring6包下的组件
@EnableTransactionManagement // 开启注解式事务管理
public class SpringConfig {
@Bean // 声明一个Bean对象
public DataSource getDataSource(){
DruidDataSource dataSource = new DruidDataSource(); // 创建Druid连接池
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver"); // 配置驱动类名
dataSource.setUrl("jdbc:mysql://localhost:3306/spring?characterEncoding=utf8&useSSL=false"); // 配置数据库URL
dataSource.setUsername("root"); // 配置数据库用户名
dataSource.setPassword("root"); // 配置数据库密码
return dataSource; // 返回配置好的数据源对象
}
@Bean(name = "jdbcTemplate") // 声明一个Bean对象并命名为"jdbcTemplate"
public JdbcTemplate getJdbcTemplate(DataSource dataSource){
JdbcTemplate jdbcTemplate = new JdbcTemplate(); // 创建JdbcTemplate对象
jdbcTemplate.setDataSource(dataSource); // 设置JdbcTemplate的数据源
return jdbcTemplate; // 返回配置好的JdbcTemplate对象
}
@Bean // 声明一个Bean对象
public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource){
DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager(); // 创建DataSourceTransactionManager对象
dataSourceTransactionManager.setDataSource(dataSource); // 设置数据源
return dataSourceTransactionManager; // 返回配置好的DataSourceTransactionManager对象
}
}
illustrate:
When using full annotations to configure transactions, you need to declare a transaction manager and use the annotation @EnableTransactionManagement to enable the transaction manager
Step 2: Demonstration
@Test
public void testTxAllAnnotation(){
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
BookController accountService = applicationContext.getBean("bookController", BookController.class);
accountService.buyBook(1, 1);
}
8.2.8 Underlying principles
In Java, using @Transactional
annotations to implement method-level transaction management is based on the characteristics of the Spring framework and the principles of AOP (aspect-oriented programming).
The underlying principle is as follows:
@Transactional
Spring intercepts the execution of methods with annotations through AOP functionality .- When a method is called, Spring creates a proxy object for the method at runtime.
- The proxy object will insert transaction-related logic before and after method execution.
- At the beginning of the method, the transaction manager starts a new database transaction.
- If the method executes successfully (no exception is thrown), the transaction manager will commit the transaction and persist the modifications to the database.
- If an exception occurs during method execution, the transaction manager will roll back the transaction, undo modifications to the database, and restore to the state before the transaction started.
- After the method execution is completed, the transaction manager closes the transaction.
Through AOP, Spring can control transactions before and after method execution. It starts a transaction before the method is executed and commits or rolls back the transaction after the method is executed, thus ensuring the consistency and integrity of the data.
It should be noted that @Transactional
the effectiveness of annotations also depends on the configuration of the transaction manager and the support of the usage environment. The Spring framework provides a variety of transaction manager implementations, such as JDBC-based transaction managers and JTA-based transaction managers. You can choose the appropriate transaction manager according to specific needs. At the same time, Spring needs to enable the transaction manager in the configuration file and ensure that @Transactional
the method modified by the annotation is called through the proxy object obtained by the Spring container. Only in this way can the transaction annotations take effect and the transaction management functions can be applied correctly.
8.3 XML-based declarative transactions (understanding)
<aop:config>
<!-- 配置事务通知和切入点表达式 -->
<aop:advisor advice-ref="txAdvice" pointcut="execution(* com.atguigu.spring.tx.xml.service.impl.*.*(..))"></aop:advisor>
</aop:config>
<!-- tx:advice标签:配置事务通知 -->
<!-- id属性:给事务通知标签设置唯一标识,便于引用 -->
<!-- transaction-manager属性:关联事务管理器 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- tx:method标签:配置具体的事务方法 -->
<!-- name属性:指定方法名,可以使用星号代表多个字符 -->
<tx:method name="get*" read-only="true"/>
<tx:method name="query*" read-only="true"/>
<tx:method name="find*" read-only="true"/>
<!-- read-only属性:设置只读属性 -->
<!-- rollback-for属性:设置回滚的异常 -->
<!-- no-rollback-for属性:设置不回滚的异常 -->
<!-- isolation属性:设置事务的隔离级别 -->
<!-- timeout属性:设置事务的超时属性 -->
<!-- propagation属性:设置事务的传播行为 -->
<tx:method name="save*" read-only="false" rollback-for="java.lang.Exception" propagation="REQUIRES_NEW"/>
<tx:method name="update*" read-only="false" rollback-for="java.lang.Exception" propagation="REQUIRES_NEW"/>
<tx:method name="delete*" read-only="false" rollback-for="java.lang.Exception" propagation="REQUIRES_NEW"/>
</tx:attributes>
</tx:advice>
Note: Declarative transactions implemented based on xml must introduce aspectJ dependencies
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>6.0.2</version> </dependency>
9. Resource operations: Resources
Summary of notes:
- Overview: In the Spring framework,
org.springframework.core.io.Resource
interfaces and their implementation classes are abstraction layers used to handle resources (such as files, classpath resources, URLs, etc.)- Resources interface: The Resource interface is an abstraction of the Spring resource access strategy. It does not provide any resource access implementation itself, and the specific resource access is completed by the implementation class of the interface . The Resource interface is used to abstract access to low-level resources
- Resources implementation class:
UrlResource
: This class is used to represent URL type resources, which can be used to access network resources.ClassPathResource
: ClassPath Resource is used to represent resources under the class path and can be instantiated by specifying the relative path or absolute path of the resource.FileSystemResource
: FileSystem Resource class is used to access file system resourcesServletContextResource
:slightlyInputStreamResource
:slightlyByteArrayResource
:slightly- ResourceLoader interface: It defines a unified access method for loading resources.
- ResourceLoader implementation class:
DefaultResourceLoader
: The default resource loader, which can be used to load classpath, file system and URL resources .FileSystemResourceLoader
: Used to load resources in the file system .ClassPathResourceLoader
: Used to load resources under the classpath .ServletContextResourceLoader
: Used to load resources in the context of a web application .- ResourceLoaderAware interface: used to inject ResourceLoader instances into Beans that implement this interface.
- Dynamically obtain Resource resources: directly use dependency injection to simplify Spring resource access to the greatest extent
- Determine the resource access path:
- Implement class-specified access path
- ClassPathXML ApplicationContext: Corresponds to using ClassPathResource for resource access.
- FileSystemXml ApplicationContext: Corresponds to using FileSystemResource for resource access.
- XmlWeb ApplicationContext: Corresponds to using ServletContextResource for resource access.
- The prefix specifies the access path:
- classpath prefix
- classpath wildcard
- Other uses of wildcards
9.1 Overview
In the Spring framework, org.springframework.core.io.Resource
interfaces and their implementation classes are abstraction layers used to handle resources (such as files, classpath resources, URLs, etc.). It provides a unified way to access and manipulate different types of resources, whether they are accessed in the file system, under the classpath, or through URLs
9.2Resources interface
9.2.1 Overview
Spring's Resource interface is located org.springframework.core.io
in . Intended to be a more powerful interface for abstracting access to low-level resources.
InterfacesResource
do inherit InputStreamSource
interfaces in Spring and provide more methods. The interface has only InputStreamSource
one method
9.2.2 Common methods
boolean exists()
: Check whether the resource exists.boolean isReadable()
: Check whether the resource is readable.boolean isOpen()
: Check whether the resource is open.URL getURL()
: Get the URL of the resource.URI getURI()
: Get the URI of the resource.File getFile()
: Get the file corresponding to the resource.long contentLength()
: Get the length of the resource.long lastModified()
: Get the last modification time of the resource.Resource createRelative(String relativePath)
: Create a relative resource relative to the current resource.String getFilename()
: Get the file name of the resource.String getDescription()
: Get the description information of the resource.InputStream getInputStream()
: Get the input stream of the resource.
9.3Resources implementation class
9.3.1 Overview
The Resource interface is an abstraction of Spring's resource access strategy. It does not itself provide any resource access implementation. Specific resource access is completed by the implementation class of this interface. Each implementation class represents a resource access strategy. Resource generally includes these implementation classes:UrlResource、ClassPathResource、FileSystemResource、ServletContextResource、InputStreamResource、ByteArrayResource
9.3.2UrlResource class
This class is used to represent URL type resources, which can be instantiated through the URL path of URL
the object or type and used to access network resources.String
Basic use case:
public class UrlResourceDemo {
public static void loadAndReadUrlResource(String path){
// 创建一个 Resource 对象
UrlResource url = null;
try {
url = new UrlResource(path);
// 获取资源名
System.out.println(url.getFilename());
System.out.println(url.getURI());
// 获取资源描述
System.out.println(url.getDescription());
//获取资源内容
System.out.println(url.getInputStream().read());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
//1 访问网络资源
//loadAndReadUrlResource("http://www.atguigu.com");
//2 访问文件系统资源
loadAndReadUrlResource("file:atguigu.txt");
}
}
illustrate:
When accessing file system resources, the file needs to be read based on the root path of the current project.
Replenish:
- http:------This prefix is used to access network resources based on HTTP protocol
- ftp:------This prefix is used to access network resources based on FTP protocol
- file: ------This prefix is used to read resources from the file system
9.3.3ClassPathResource class
ClassPathResource is used to represent resources under the class path, and can be instantiated by specifying the relative path or absolute path of the resource. Compared with other Resource implementation classes, its main advantage is to facilitate access to resources in the class loading path, especially for Web applications. , ClassPathResource can automatically search for resource files under classes without using absolute path access.
Basic use case:
public class ClassPathResourceDemo {
public static void loadAndReadUrlResource(String path) throws Exception{
// 创建一个 Resource 对象
ClassPathResource resource = new ClassPathResource(path);
// 获取文件名
System.out.println("resource.getFileName = " + resource.getFilename());
// 获取文件描述
System.out.println("resource.getDescription = "+ resource.getDescription());
//获取文件内容
InputStream in = resource.getInputStream();
byte[] b = new byte[1024];
while(in.read(b)!=-1) {
System.out.println(new String(b));
}
}
public static void main(String[] args) throws Exception {
loadAndReadUrlResource("atguigu.txt");
}
}
illustrate:
When accessing the file resource system, the file needs to be read based on the class path of the current project.
9.3.4FileSystemResource class
The FileSystemResource class provided by Spring is used to access file system resources. There is not much advantage in using FileSystemResource to access file system resources, because the File class provided by Java can also be used to access file system resources.
public class FileSystemResourceDemo {
public static void loadAndReadUrlResource(String path) throws Exception{
//相对路径
FileSystemResource resource = new FileSystemResource("atguigu.txt");
//绝对路径
//FileSystemResource resource = new FileSystemResource("C:\\atguigu.txt");
// 获取文件名
System.out.println("resource.getFileName = " + resource.getFilename());
// 获取文件描述
System.out.println("resource.getDescription = "+ resource.getDescription());
//获取文件内容
InputStream in = resource.getInputStream();
byte[] b = new byte[1024];
while(in.read(b)!=-1) {
System.out.println(new String(b));
}
}
public static void main(String[] args) throws Exception {
loadAndReadUrlResource("atguigu.txt");
}
}
9.3.5ServletContextResource class
This is ServletContext
the Resource implementation of the resource, which interprets relative paths in the root directory of the associated web application. It always supports stream access and URL access, but only allows java.io.File access if the web application archive is extended and the resource is actually on the file system. Whether it's expanded on the file system or accessed directly from a JAR or elsewhere (like a database) is really dependent on the Servlet container.
9.3.6InputStreamResource class
IsInputStreamResource
the Resource implementation of the given input stream. Its usage scenario is used when there is no specific resource implementation (it feels very similar to the applicable scenario of @Component). Compared to other Resource implementations, this is a descriptor of the opened resource. Therefore, its isOpen()
methods return true. Do not use it if you need to keep the resource descriptor somewhere or if you need to read the stream multiple times.
9.6.7ByteArrayResource class
Resource implementation class of byte array. Creates one from the given array ByteArrayInputStream
. It's useful for loading content from any given byte array without having to resort to single-use ones InputStreamResource
.
9.4ResourceLoader interface
9.4.1 Overview
InterfaceResourceLoader
is a core interface in the Spring framework, which defines a unified access method for loading resources. It provides a unified method to load various types of resources, such as files, classpath resources, URL resources, etc.
9.4.2 Common methods
Resource getResource(String location)
Resource
: Get an object based on the given resource location (location) . A resource location can be a file path, class path, URL, etc. The specific resource loading strategyResourceLoader
is determined by the specific implementation class.ClassLoader getClassLoader()
: Gets the object used to load the classClassLoader
. This is useful for loading resources on the classpath.
9.4.3 Implementation class
The Spring framework provides several ResourceLoader
classes that implement interfaces, including:
DefaultResourceLoader
: The default resource loader, which can be used to load classpath, file system and URL resources.FileSystemResourceLoader
: Used to load resources from the file system.ClassPathResourceLoader
: Used to load resources under the classpath.ServletContextResourceLoader
: Used to load resources in the context of a web application.
9.4.4 Basic use cases
public static void main(String[] args) {
// 创建Spring应用上下文,从类路径中加载配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext();
// 通过ApplicationContext访问资源
// ApplicationContext实例获取Resource实例时,
// 默认采用与ApplicationContext相同的资源访问策略
Resource res = ctx.getResource("atguigu.txt");
System.out.println(res.getFilename());
}
illustrate:
Spring will use the same strategy as ApplicationContext to access resources. In other words, if ApplicationContext is ClassPathXmlApplicationContext, res is the ClassPathResource instance
public static void main(String[] args) {
// 创建Spring应用上下文,指定文件系统路径加载配置文件
ApplicationContext ctx = new FileSystemXmlApplicationContext();
Resource res = ctx.getResource("atguigu.txt");
System.out.println(res.getFilename());
}
illustrate:
Spring will use the same strategy as ApplicationContext to access resources. In other words, if ApplicationContext is FileSystemXmlApplicationContext, res is a FileSystemResource instance;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.Resource;
public class ResourceLoaderExample {
public static void main(String[] args) {
// 创建一个ApplicationContext容器对象,该对象会读取classpath(类路径)下的名为applicationContext.xml的配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// 使用 classpath: 前缀指定使用 ClassPathResource 实现类
Resource resource1 = context.getResource("classpath:config.properties");
System.out.println("Resource 1: " + resource1.getClass().getSimpleName());
// 使用 file: 前缀指定使用 FileSystemResource 实现类
Resource resource2 = context.getResource("file:/path/to/file.txt");
System.out.println("Resource 2: " + resource2.getClass().getSimpleName());
// 使用 http: 前缀指定使用 UrlResource 实现类
Resource resource3 = context.getResource("http://www.example.com");
System.out.println("Resource 3: " + resource3.getClass().getSimpleName());
}
}
illustrate:
Use the getResource() method of ApplicationContext to obtain three different types of resources, and use different prefixes to specify the use of different Resource implementation classes.
9.5ResourceLoaderAware interface
9.5.1 Overview
9.5.1.1 Meaning
ResourceLoaderAware is a Spring Bean interface used to inject ResourceLoader instances into beans that implement this interface. It defines a setResourceLoader(ResourceLoader resourceLoader) method to which the Spring container passes a ResourceLoader instance as a parameter at startup.
9.5.1.2 Function
Classes that implement the ResourceLoaderAware interface can obtain the ResourceLoader instance of the Spring container, thereby utilizing the resource loading function provided by the Spring container.
9.5.2 Basic use cases
Step 1: Create Bean
package com.atguigu.spring6.resouceloader;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.core.io.ResourceLoader;
public class TestBean implements ResourceLoaderAware {
private ResourceLoader resourceLoader;
//实现ResourceLoaderAware接口必须实现的方法
//如果把该Bean部署在Spring容器中,该方法将会有Spring容器负责调用。
//SPring容器调用该方法时,Spring会将自身作为参数传给该方法。
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
//返回ResourceLoader对象的应用
public ResourceLoader getResourceLoader(){
return this.resourceLoader;
}
}
illustrate:
- To implement the ResourceLoaderAware interface, you must implement
setResourceLoader
methods,
Step 2: Configure Bean
<?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="testBean" class="com.atguigu.spring6.resouceloader.TestBean"></bean>
</beans>
Step 3: Demo
public static void main(String[] args) {
//Spring容器会将一个ResourceLoader对象作为该方法的参数传入
ApplicationContext ctx = new ClassPathXmlApplicationContext("bean.xml");
TestBean testBean = ctx.getBean("testBean",TestBean.class);
//获取ResourceLoader对象
ResourceLoader resourceLoader = testBean.getResourceLoader();
System.out.println("Spring容器将自身注入到ResourceLoaderAware Bean 中 ? :" + (resourceLoader == ctx));
//加载其他资源
Resource resource = resourceLoader.getResource("atguigu.txt");
System.out.println(resource.getFilename());
System.out.println(resource.getDescription());
}
illustrate:
Because
ApplicationContext
the implementation class of the interfaceClassPathXmlApplicationContext
implementsResourceLoader
the interface,ClassPathXmlApplicationContext
the instance object also has the function of "ResourceLoader". Therefore, objects that implementResourceLoaderAware
this interface can use the resource loading function provided by the Spring container
9.6 Dynamically obtain Resource resources
9.6.1 Overview
9.6.1.1 Meaning
The Spring framework not only makes full use of the strategy pattern to simplify resource access, but also fully combines the strategy pattern with IoC to simplify Spring resource access to the greatest extent. When bean instances in the application need to access resources, Spring has a better solution: directly using dependency injection
9.6.1.2 Function
For obtaining Resource instances in code, when the program obtains Resource instances, it is always necessary to provide the location of the Resource, whether creating an instance through FileSystemResource, creating an instance through ClassPathResource, or obtaining an instance through the getResource() method of ApplicationContext. Provide resource location. This means: the physical location of the resource is coupled into the code, and if the location of the resource changes, the program must be rewritten. Therefore, it is generally recommended to adopt the method of dependency injection and let Spring inject resources for Bean instances .
9.6.2 Basic use cases
Step 1: Create a dependency injection class, define properties and methods
public class ResourceBean {
private Resource res;
public void setRes(Resource res) {
this.res = res;
}
public Resource getRes() {
return res;
}
public void parse(){
System.out.println(res.getFilename());
System.out.println(res.getDescription());
}
}
Step 2: Create a spring configuration file and configure dependency injection
<?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="resourceBean" class="com.atguigu.spring6.resouceloader.ResourceBean" >
<!-- 可以使用file:、http:、ftp:等前缀强制Spring采用对应的资源访问策略 -->
<!-- 如果不采用任何前缀,则Spring将采用与该ApplicationContext相同的资源访问策略来访问资源 -->
<property name="res" value="classpath:atguigu.txt"/>
</bean>
</beans>
Step 3: Demo
public static void main(String[] args) {
ApplicationContext ctx =
new ClassPathXmlApplicationContext("bean.xml");
ResourceBean resourceBean = ctx.getBean("resourceBean",ResourceBean.class);
resourceBean.parse();
}
9.7 Determine resource access paths
9.7.1 Overview
No matter how you create an ApplicationContext instance, you need to specify a configuration file for the ApplicationContext. Spring allows the use of one or more XML configuration files. When a program creates an ApplicationContext instance, it usually accesses the configuration file in the form of Resource, so ApplicationContext fully supports resource access methods such as ClassPathResource, FileSystemResource, and ServletContextResource.
9.7.2 Implementing classes to specify access paths
(1) ClassPathXMLApplicationContext: Corresponds to using ClassPathResource for resource access.
(2) FileSystemXmlApplicationContext: Corresponds to using FileSystemResource for resource access.
(3) XmlWebApplicationContext: Corresponds to using ServletContextResource for resource access.
For detailed steps, please view the implementation class of Resources
9.7.3 Prefix specifies access path
9.7.3.1classpath prefix
public class Demo1 {
public static void main(String[] args) {
/*
* 通过搜索文件系统路径下的xml文件创建ApplicationContext,
* 但通过指定classpath:前缀强制搜索类加载路径
* classpath:bean.xml
* */
ApplicationContext ctx =
new ClassPathXmlApplicationContext("classpath:bean.xml");
System.out.println(ctx);
Resource resource = ctx.getResource("atguigu.txt");
System.out.println(resource.getFilename());
System.out.println(resource.getDescription());
}
}
illustrate:
When using ApplicationContext, when specifying the path, use **classpath:** as the prefix
9.7.3.2classpath wildcard
ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath*:bean.xml");
illustrate:
When using the ApplicationContext, when specifying the path, use classpath* as the prefix, which means that Spring will search for all configuration files that meet this rule in the class loading path. For example: bean.xml, beans.xml
9.7.3.3 Other uses of wildcards
ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:bean*.xml");
illustrate:
How to load multiple configuration files at once: use wildcards when specifying configuration files
ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath*:bean*.xml");
illustrate:
Spring allows the combination of classpath*: prefixes and wildcards
10. Internationalization: i18n
Summary of notes:
Overview: Designing software, applications, or websites to adapt to the needs of different languages , cultures, and regions
Java internationalization:
ResourceBundle class: It is an internationalization tool class used to load and manage resource files in different language environments.
Configuration file naming rules:
basename_language_country.properties
, for examplemessages_en_CB.properties
Basic use case:
Create resource configuration file
Obtained through ResourceBundle class
public static void main(String[] args) { ResourceBundle resourceBundle = ResourceBundle.getBundle("messages", new Locale("en", "GB")); String string = resourceBundle.getString("test"); System.out.println(string); }
Spring6 internationalization
Step 1: Create properties resource configuration file
Step 2: Create spring configuration file and configure MessageSource
Step 3: Get the keys in the resource configuration file by injecting it into the Spring6 configuration file
public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); //传递动态参数,使用数组形式对应{0} {1}顺序 Object[] objs = new Object[]{ "atguigu",new Date().toString()}; //www.atguigu.com为资源文件的key值, //objs为资源文件value值所需要的参数,Local.CHINA为国际化为语言 String str=context.getMessage("www.atguigu.com", objs, Locale.CHINA); System.out.println(str); }
10.1 Overview
Internationalization, often abbreviated as i18n (i + 18 letters + n), refers to the design of software, applications or websites to be able to adapt to the needs of different languages, cultures and regions. Generally speaking, internationalization in software is achieved through configuration files. If two languages are to be supported, then two versions of configuration files are required.
10.2Java internationalization
10.2.1 createConstant method
illustrate:
java.util.Locale is used to specify information such as the locale to which the current user belongs, and java.util.ResourceBundle is used to find the resource file corresponding to the binding. Locale contains language information and country information, the static method used by Locale to create the default locale object:
10.2.2ResourceBundle class
ResourceBundle is a tool class provided by Java for internationalization, which is used to load and manage resource files in different language environments.
10.2.3 Configuration file naming rules
basename_language_country.properties
illustrate:
The above naming rules must be followed for java to recognize it. Among them, basename is required, language and country are optional. There is a priority concept here. If both messages.properties and messages_zh_CN.propertes are provided at the same time, and if the locale provided conforms to en_CN, then the messages_en_CN.propertes configuration file will be searched first. If not found, the messages.properties configuration will be searched. document. Finally, as a reminder, all configuration files must be placed in the classpath, usually in the resources directory
10.3 Basic use cases
Step 1: In the resources resource file, create a configuration file
illustrate:
Resource Bundle'messages'is automatically generated by the system, because the created properties files conform to the Java internationalization naming rules
Step 2: Write configuration files in different languages
test=123
//
test=456
Step 3: Demo
public class ResourceBundleExample {
public static void main(String[] args) {
// 获取名为 "messages" 的资源包,使用英国地区设置(Locale)
ResourceBundle resourceBundle = ResourceBundle.getBundle("messages", new Locale("en", "GB"));
// 从资源包中获取名为 "test" 的字符串
String string = resourceBundle.getString("test");
System.out.println(string);
}
}
illustrate:
The ResourceBundle class is used to manage resource files in different language environments in internationalization, and Locale is used to specify the locale to which the current user belongs
10.4Spring6 internationalization
Step 1: Create resource files
Internationalization file naming format: basename_language_country.properties
Contents like {0},{1} are dynamic parameters.
(1) Create atguigu_en_US.properties
www.atguigu.com=welcome {0},时间:{1}
(2) Create atguigu_zh_CN.properties
www.atguigu.com=欢迎 {0},时间:{1}
Step 2: Create a spring configuration file and configure MessageSource
<?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="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basenames">
<list>
<value>atguigu</value>
</list>
</property>
<property name="defaultEncoding">
<value>utf-8</value>
</property>
</bean>
</beans>
illustrate:
In Spring 6, naming the id of ResourceBundleMessageSource as messageSource can reduce unnecessary configuration and explicit references and allow Spring 6 to achieve automatic injection.
Step 3: Create test class
package com.atguigu.spring6.javai18n;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.Date;
import java.util.Locale;
public class Demo2 {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
//传递动态参数,使用数组形式对应{0} {1}顺序
Object[] objs = new Object[]{
"atguigu",new Date().toString()};
//www.atguigu.com为资源文件的key值,
//objs为资源文件value值所需要的参数,Local.CHINA为国际化为语言
String str=context.getMessage("www.atguigu.com", objs, Locale.CHINA);
System.out.println(str);
}
}
11. Data verification: Validation
Summary of notes:
Overview: Data validation (Validation) is the process of validating user-entered data in an application to ensure that the data conforms to expected rules and constraints.
Verification is implemented through the Validator interface:
Step 1: Import
hibernate-validator
andjakarta.el
dependencyStep 2: Create entity class
Step 3: Implement the Validator interface
Step 4: Implement
DataBinder
the validatorImplement verification through Bean Validation annotation (recommended):
Step 1: Create configuration file class
Step 2: Create an entity class and use annotations to define verification rules
Step 3: Create a validator service (using @Autowired)
Step 4: Verification
Verification is implemented through methods:
Step 1: Create configuration file class
Step 2: Create an entity class and use annotations to define verification rules
Step 3: Create the validator service (using @Valid)
Pass custom verification (supplementary):
Step 1: Customize verification annotations
Step 2: Write the implemented verification class
For more annotations: please refer to, spring-boot request parameter verification: use of annotation @Validated, manual verification, custom verification_validate annotation verification_sayyy's blog-CSDN blog
11.1 Overview
Data validation (Validation) is the process of validating user input data in the application to ensure that the data conforms to the expected rules and constraints. In Java, the commonly used data validation framework is Validation API, which is part of Java EE and also integrated and supported in the Spring framework.
11.2 Basic use case-verification through Validator interface
illustrate:
Implementing data verification through
Validator
interfaces is another way to use the Validation API for data verification.Validator
The interface provides a more flexible verification mechanism, and you can customize verification logic and error messages.
Step 1: Introduce relevant dependencies
<dependencies>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>7.0.5.Final</version>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>jakarta.el</artifactId>
<version>4.0.1</version>
</dependency>
</dependencies>
Step 2: Create entity class
package com.atguigu.spring6.validation.method1;
public class Person {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
Step 3: Implement the Validator interface
public class PersonValidator implements Validator {
// supports方法用来表示此校验用在哪个类型上
@Override
public boolean supports(Class<?> clazz) {
return Person.class.equals(clazz);
}
// validate是设置校验逻辑的地点
@Override
public void validate(Object object, Errors errors) {
ValidationUtils.rejectIfEmpty(errors, "name", "name.empty");
Person p = (Person) object;
if (p.getAge() < 0) {
errors.rejectValue("age", "error value < 0");
} else if (p.getAge() > 110) {
errors.rejectValue("age", "error value too old");
}
}
}
illustrate:
- Implement the Validator interface, rewrite the supports and validate methods, and implement the logic
- ValidationUtils is a validation tool class encapsulated by Spring to help quickly implement validation
Step 4: Demonstrate
public static void main(String[] args) {
// 创建person对象
Person person = new Person();
person.setName("lucy");
person.setAge(-1);
// 创建Person对应的DataBinder
DataBinder binder = new DataBinder(person);
// 绑定校验
binder.setValidator(new PersonValidator());
// 开始校验
binder.validate();
// 输出结果
BindingResult results = binder.getBindingResult();
System.out.println(results.getAllErrors());
}
illustrate:
By using
DataBinder
the validator, you can easily perform data validation on the object and obtain the validation result
11.3 Basic use case-verification through Bean Validation annotation
illustrate:
Bean Validation is an annotation-based data validation specification in Java. Data validation rules can be defined by adding corresponding annotations to the properties of entity classes
Commonly used annotations:
@NotNull
: Check that the field value is not null.@NotEmpty
: Checks that the value of a string, collection or array is not empty.@NotBlank
: Checks that the value of a string is not empty or does not contain only whitespace characters.@Min(value)
: Checks that the field value is greater than or equal to the specified minimum value.@Max(value)
: Checks that the field value is less than or equal to the specified maximum value.@Size(max, min)
: Checks that the size of the field value is within the specified range.@Email
: Checks that the field value meets the format requirements of the email.@Pattern(regex)
: Checks that the field value matches the specified regular expression.
Step 1: Create configuration file class
@Configuration
@ComponentScan("org.example")
public class ValidationConfig {
@Bean
public LocalValidatorFactoryBean validator() {
return new LocalValidatorFactoryBean();
}
}
illustrate:
LocalValidatorFactoryBean
It is a class provided by the Spring framework that implementsValidatorFactory
the interface and is used to create and manageValidator
instances.- Configuring ComponentScan scanning rules is to enable package scanning and facilitate Bean injection of the Spring framework.
Step 2: Create an entity class and use annotations to define verification rules
@Data
public class User {
@NotNull
private String name;
@Min(0)
@Max(120)
private int age;
}
Notice:
@Max and @Min annotations require importing dependencies before data verification. For dependencies, please check through the Validator interface.
Step 3: Create the validator
1. Use jakarta.validation.Validator to verify
@Service
public class ValidatorServiceOne {
// 导入 jakarta.validation.Validator
@Autowired
Validator validator;
public Boolean vailAge(Person person) {
// 使用Validator的vaildate方法进行数据验证
Set<ConstraintViolation<Person>> validate = validator.validate(person);
return validate.isEmpty();
}
}
illustrate:
During the verification process,
Validator
each attribute of the user object will be checked in turn to verify whether it meets the specified constraints. If the value of an attribute does not meet the constraint conditions, anConstraintViolation
object will be generated, which contains detailed information about the constraint violation, such as the attribute name, the type of constraint violated, error message, etc. Finally, theseConstraintViolation
objects are collected into aSet
collection and returned.
2. Use org.springframework.validation.Validator to verify
@Service
public class ValidatorServiceTwo {
// 导入 org.springframework.validation.Validator;
@Autowired
private Validator validator;
public boolean validaPersonByValidator(User user) {
// 创建 BindException 对象,用于收集校验错误信息
BindException bindException = new BindException(user, user.getName());
// 使用 Validator 对象对用户对象进行校验,将校验结果收集到 bindException 中
validator.validate(user, bindException);
// 判断 bindException 中是否存在校验错误信息
return bindException.hasErrors();
}
}
illustrate:
BindException
isorg.springframework.validation
a class in the package, which inherits fromorg.springframework.validation.Errors
the interface and is used to collect verification error information. By creatingBindException
an object, the verification results can be collected into it to facilitate subsequent processing of error information.
Notice:
When using Validator, you need to import dependencies, the same as through the Validator interface.
Step 4: Demonstrate
1. Use jakarta.validation.Validator to verify
@Test
public void testMyService1() {
ApplicationContext context = new AnnotationConfigApplicationContext(ValidationConfig.class);
MyService1 myService = context.getBean(MyService1.class);
User user = new User();
user.setAge(-1);
boolean validator = myService.validator(user);
System.out.println(validator);
}
2. Use org.springframework.validation.Validator to verify
@Test
public void testMyService2() {
ApplicationContext context = new AnnotationConfigApplicationContext(ValidationConfig.class);
MyService2 myService = context.getBean(MyService2.class);
User user = new User();
user.setName("lucy");
user.setAge(130);
user.setAge(-1);
boolean validator = myService.validaPersonByValidator(user);
System.out.println(validator);
}
11.4 Basic use cases - verification through methods
illustrate:
Method-based verification refers to using verification annotations on a specific method to verify the method’s input parameters, return value, or status during method execution. Spring provides
@Validated
annotations and validation annotations (eg@NotNull
,@NotBlank
,@Min
,@Max
etc.) to implement method-based validation.
Step 1: Create configuration file class
@Configuration
@ComponentScan("org.example")
public class ValidationConfig {
@Bean
public MethodValidationPostProcessor validationPostProcessor() {
return new MethodValidationPostProcessor();
}
}
illustrate:
is
MethodValidationPostProcessor
a post-processor provided by Spring for parameter verification when calling methods. It can automatically intercept@Validated
the methods marked by annotations and verify the parameters of the methods.
Step 2: Create an entity class and use annotations to define verification rules
@Data
public class User {
@NotNull
private String name;
@Min(0)
@Max(120)
private int age;
@Pattern(regexp = "^1(3|4|5|7|8)\\d{9}$",message = "手机号码格式错误")
@NotBlank(message = "手机号码不能为空")
private String phone;
}
Step 3: Create the validator
@Service
@Validated
public class MyService {
// 使用 @Valid 注解标记了 User 参数,表示对该参数进行校验、使用 @NotNull 注解标记了 User 参数,表示该参数不能为空。
public String testParams(@NotNull @Valid User user) {
return user.toString();
}
}
illustrate:
If the verification fails, a ConstraintViolationException will be thrown. If the verification passes, other business logic will be executed.
Step 4: Demonstrate
@Test
public void testMyService1() {
ApplicationContext context = new AnnotationConfigApplicationContext(ValidationConfig.class);
MyService myService = context.getBean(MyService.class);
User user = new User();
user.setAge(-1);
myService.testParams(user);
}
11.5 Basic use case-pass custom verification
Step 1: Customize verification annotations
@Target({
ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
// @Target 和 @Retention 来定义注解的使用范围和生命周期
@Documented
// @Constraint 标记该注解为校验注解,并指定对应的校验器类
@Constraint(validatedBy = {
CannotBlankValidator.class})
public @interface CannotBlank {
//默认错误消息
String message() default "不能包含空格";
//分组
Class<?>[] groups() default {
};
//负载
Class<? extends Payload>[] payload() default {
};
//指定多个时使用
@Target({
ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@interface List {
CannotBlank[] value();
}
}
illustrate:
For the content implementation of this annotation, you can refer to the part that comes with the existing annotation.
Replenish:
@Target
Annotations are used to specify the usage scope of annotations, including methods, fields, annotation types, constructors, and parameters.@Retention
Annotations are used to specify the life cycle of annotations, that is, the annotation information is still retained during runtime.@Documented
An annotation is used to indicate that the annotation should be included in the generated documentation.@Constraint
The annotation marks the annotation as a validation annotation and specifies the corresponding validator classCannotBlankValidator
.message()
method defines a default error message to use when validation fails.groups()
The method is used for group verification, and you can specify which group the validator takes effect.payload()
Method specifies the payload type, which can be used in custom validators.@List
Annotation is used when specifying multiple@CannotBlank
annotations, multiple annotations can be combined.
Notice:
The annotation itself does not implement specific verification logic, but
CannotBlankValidator
implements the specific verification logic through the validator class.
Step 2: Write the verification class
public class CannotBlankValidator implements ConstraintValidator<CannotBlank, String> {
// initialize() 方法用于初始化校验器,在校验之前进行一些初始化操作。可以获取注解中的属性值,并进行相应的处理
@Override
public void initialize(CannotBlank constraintAnnotation) {
}
// isValid() 方法是校验的核心逻辑,用于判断被校验的值是否符合自定义的校验规则
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
//null时不进行校验
if (value != null && value.contains(" ")) {
//获取默认提示信息
String defaultConstraintMessageTemplate = context.getDefaultConstraintMessageTemplate();
System.out.println("default message :" + defaultConstraintMessageTemplate);
//禁用默认提示信息
context.disableDefaultConstraintViolation();
//设置提示语
context.buildConstraintViolationWithTemplate("can not contains blank").addConstraintViolation();
return false;
}
return true;
}
}
illustrate:
- Create a custom validator class: implement the ConstraintValidator interface, and specify the annotation type to be validated and the value type to be validated. In the verification logic, implement custom verification rules and return verification results as needed
- In
isValid()
the method, there are two parameters:
value
: The value to be verified, that is, the value of the field or method parameter that needs to be verified.context
: The context object of the validator, used to control some behaviors and settings during the validation process.- When implementing
isValid()
the method, according to the customized verification rules, you can usevalue
the parameter to obtain the verified value, and verify it according to the business logic. If the verification is successful, it returnstrue
to indicate that the verification is passed; if the verification fails, it returnsfalse
to indicate that the verification is not passed.
Step 3: Demo
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(ValidationConfig.class);
ValidatorService bean = (ValidatorService) applicationContext.getBean("validatorService");
Person person = new Person();
person.setAge(12);
person.setMessage("fd s f");
String s = bean.vailAge(person);
System.out.println(s);
}
illustrate:
This step is only to implement custom rules through custom annotations for verification. How to implement verification also needs to refer to
实现
the method of verification
12. Ahead of time compilation: AOT
Summary of notes:
- Overview:
- Meaning: Ahead of Time Compilation (AOT) is a technology that compiles program code into machine code before it runs . Contrary to traditional just-in-time compilation (JIT), just-in-time compilation interprets program code line by line into machine code and executes it at runtime.
- Graalvm: The AOT technology supported by Spring6, this GraalVM is the underlying support, and Spring also provides first-class support for GraalVM native images. GraalVM is a high-performance JDK designed to accelerate the execution of applications written in Java and other JVM languages, while also providing runtimes for JavaScript, Python, and many other popular languages.
- Native Image: In addition to this solution of AOT in JVM, there is another way to implement Java AOT in the industry, which is to directly abandon the JVM and directly compile the code into machine code through a compiler like C/C++, and then run. This is undoubtedly an idea that directly subverts Java language design, that is GraalVM Native Image.
- Native Image building process
- GraalVM installation
- Install the C++ compilation environment
- Write code and build Native Image
12.1 Overview
12.1.1 Meaning
Ahead of Time Compilation (AOT) is a technology that compiles program code into machine code before running . Contrary to traditional just-in-time compilation (JIT), just-in-time compilation interprets program code line by line into machine code and executes it at runtime.
AOT advantages
- Faster startup time : Since the code has been compiled into machine code, there is no need to compile and interpret it at runtime, so it can be executed directly, reducing startup time.
- Higher execution performance : AOT compilation can perform comprehensive static optimization, including code optimization, inlining, eliminating unnecessary checks, etc. These optimizations are performed at compile time and can provide higher execution performance .
- Better security : AOT compilation can compile source code into machine code, hiding the logic of the source code and providing better security.
Disadvantages of AOT
- Larger compilation output: AOT compilation completely compiles the source code or intermediate code into machine code, so the compilation output is usually larger than the source code or bytecode and takes up more storage space.
- Compilation time delay: AOT compilation needs to occur before the program can be run, thus increasing development and build time costs, especially for larger code bases or complex projects.
- Lack of runtime optimization: Since AOT compilation is performed before the program is run, it cannot be optimized based on the actual runtime context information and cannot dynamically adapt to the changing execution environment.
12.1.2 The difference between JIT and AOT
JIT, Just-in-time, dynamic (just-in-time) compilation, compilation while running;
When the program is running, the hot code is calculated based on the algorithm, and then JIT real-time compilation is performed. This method has high throughput, has a runtime performance bonus, can run faster, and can dynamically generate code , etc., but is relatively The startup speed is slow , and it takes a certain amount of time and calling frequency to trigger the JIT's layering mechanism. The disadvantage of JIT is that compilation needs to occupy runtime resources, which will cause the process to freeze.
AOT, Ahead Of Time, refers to pre-run compilation, pre-compilation;
AOT compilation can directly convert source code into machine code, with low memory usage and fast startup speed . It can run without runtime and directly statically link the runtime into the final program. However, there is no runtime performance bonus and it cannot be based on the running status of the program. For further optimization, the disadvantage of AOT is that compiling before the program is run will increase the program installation time.
In general: JIT just-in-time compilation refers to the process of converting bytecode into machine code that can be run directly on the hardware during the running process of the program and deploying it to the hosting environment. AOT compilation refers to the process of converting bytecode into machine code before the program is run.
illustrate:
.java -> .class -> (using jaotc compilation tool) -> .so (program function library, that is, compiled code and data that can be used by other programs)
12.1.3Graalvm
GraalVM is the underlying support for the AOT technology supported by Spring 6. Spring also provides first-class support for GraalVM native images. GraalVM is a high-performance JDK designed to accelerate the execution of applications written in Java and other JVM languages, while also providing runtimes for JavaScript, Python, and many other popular languages. GraalVM provides two ways to run Java applications: using the Graal just-in-time (JIT) compiler on the HotSpot JVM or as a native executable compiled ahead of time (AOT). GraalVM's multilingual capabilities make it possible to mix multiple programming languages in a single application while eliminating the cost of foreign language calls. GraalVM adds an advanced just-in-time (JIT) optimizing compiler written in Java to the HotSpot Java virtual machine.
GraalVM has the following features:
(1) An advanced optimizing compiler that generates faster, leaner code that requires fewer computing resources
(2) AOT native image compilation compiles Java applications into native binaries in advance, starts immediately, and achieves maximum performance without preheating
(3) Polyglot programming leverages the best features and libraries of popular languages in a single application without additional overhead
(4) Advanced tools to debug, monitor, analyze and optimize resource consumption in Java and multiple languages
Generally speaking, the requirements for cloud native are not high. You can continue to use the 2.7.X version and JDK8 in the short term, but Spring has officially released Spring6.
12.1.4Native Image
At present, in the industry, in addition to this solution of performing AOT in the JVM, there is another way to implement Java AOT, which is to directly abandon the JVM , and directly compile the code into machine code through a compiler like C/C++, and then run it. This is undoubtedly an idea that directly subverts the design of the Java language, that is, GraalVM Native Image. It implements an ultra-miniature runtime component through C language - Substrate VM, which basically implements various features of the JVM, but is lightweight enough and can be easily embedded, which allows the Java language and engineering to get rid of the limitations of the JVM. It can truly realize the same AOT compilation as C/C++. After a long period of optimization and accumulation, this solution has achieved very good results and has basically become the first Java AOT solution officially recommended by Oracle.
Native Image is an innovative technology that compiles Java code into a stand-alone native executable or a native shared library . The Java bytecode processed during building a native executable includes all application classes, dependencies, third-party dependent libraries, and any required JDK classes. The resulting self-contained native executables are specific to each individual operating system and machine architecture that does not require a JVM.
12.2Native Image construction process
12.2.1GraalVM installation
Step 1: Download GraalVM
Enter the official website to download: https://www.graalvm.org/downloads/
Step 2: Configure environment variables
Add GRAALVM_HOME
Change JAVA_HOME to the location of graalvm
Change the Path to the bin location of graalvm
Use the command to check whether the installation is successful
Step 3: Install the native-image plugin
Use the command gu install native-image to download and install
12.2.2 Install the C++ compilation environment
Step 1: Download the Visual Studio installation software
https://visualstudio.microsoft.com/zh-hans/downloads/
Step 2: Install Visual Studio
Step 3: Add Visual Studio environment variables
Configure INCLUDE, LIB and Path
Step 4: Open the tool and operate in the tool
12.2.3 Write code and build Native Image
Step 1: Write Java code
public class Hello {
public static void main(String[] args) {
System.out.println("hello world");
}
}
Step 2: Copy the file to the directory and perform compilation
Step 3: Build Native Image
Step 4: View the built files
Step 5: Execute the built file
You can see that the size of the binary file finally packaged by Hello is 11M. This is the size after including various libraries of SVM and JDK. Although it is larger than the binary file of C/C++, it is still smaller than the complete JVM. It can be said that it is already very small.
Compared with running using JVM, Native Image is much faster and has lower CPU usage. It can also be seen from various official experimental data provided that Native Image greatly improves startup speed and memory usage. obviously:
knowledge gas station
1.The difference between ResourceLoader and Resource implementation classes
ResourceLoader
The main differences from Resource
the implementation class of the interface are as follows:
ResourceLoader
The implementation class is mainly used to load resources and provides methods for loading resources, such asClassPathResourceLoader
loading resources under the class path,UrlResourceLoader
loading URL resources,FileSystemResourceLoader
loading resources in the file system, etc.Resource
The implementation class is mainly used to access and operate resources, and provides specific operation methods for resources, such asClassPathResource
accessing resources under the class path,UrlResource
accessing URL resources,FileSystemResource
accessing resources in the file system, etc.ResourceLoader
The implementation class is usually used internally by the Spring framework to provide resource loading functions and is not used directly in the application.Resource
The implementation class of can be used in the application , through which the information and content of the resource can be obtained, read and manipulated.
In general, ResourceLoader
the implementation class of is mainly responsible for loading resources, while Resource
the implementation class of is mainly responsible for accessing and manipulating resources. They play different roles in the framework, but all are used to handle and manage resources in the application.
illustrate:
The Resource interface is an abstraction for accessing resources in Spring. The Resource interface itself only provides regulations, and there are many implementation classes below. Both are resource descriptors abstracted from the actual system underlying resources. Generally speaking, in Spring, resources are described as resource addresses in URL format and Ant style with wildcards.
illustrate:
Interface
ResourceLoader
, as the name suggests, is designed to quickly return (that is, load) the object of the Resource instance
Detailed reference document: Spring Framework Source Code Analysis (IoC): Relationship between Resource, ResourceLoader and Container - Tencent Cloud Developer Community - Tencent Cloud (tencent.com)