Notas de estudio: Capítulo avanzado de Shang Silicon Valley Spring 6

primavera6

  1. Notas de estudio: blog-CSDN de Spring 6 basics_ljtxy.love
  2. Notas de estudio: Capítulo avanzado de primavera 6_Blog-CSDN de Blog-ljtxy.love

Directorio de artículos

7. Prueba unitaria: JUnit

Resumen de notas:

  1. Descripción general: JUnit es un marco de pruebas unitarias para el lenguaje de programación Java

  2. Caso de uso básico:

    Paso 1: Introducir dependencias: dependencias de soporte de Junit, pruebas de Junit5

    Paso 2: Archivo de configuración: configurar el escaneo de clases básico

    Paso 3: Demostración: utilice la anotación **@SpringJUnitConfig(locations = “classpath:beans.xml”)** para cargar automáticamente el archivo de configuración y crear la clase.

7.1 Descripción general

JUnit es un marco de prueba unitaria para el lenguaje de programación Java, fue creado por Erich Gamma y Kent Beck y gradualmente se ha convertido en uno de los marcos de prueba unitarios estándar para el lenguaje Java. JUnit proporciona algunas anotaciones y métodos de afirmación para ayudar a los desarrolladores a escribir y ejecutar casos de prueba. También puede integrarse con herramientas de compilación como Maven y Gradle para facilitar la integración continua y las pruebas automatizadas.

7.2 Casos de uso básicos

Paso 1: Introducir dependencias

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

Paso 2: archivo de configuración

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

ilustrar:

​Escaneo de clases de configuración para ensamblar beans automáticamente

Paso 3: crea una clase

@Component
public class User {
    
    

    public User() {
    
    
        System.out.println("run user");
    }
}

Paso 4: demostrar

@SpringJUnitConfig(locations = "classpath:beans.xml")
public class SpringJUnit5Test {
    
    

    @Autowired
    private User user;

    @Test
    public void testUser(){
    
    
        System.out.println(user);
    }
}

ilustrar:

  • La anotación @SpringJUnitConfig se utiliza para especificar el archivo de configuración de Spring. Antes de ejecutar el método de prueba, Spring primero creará los beans necesarios según el archivo de configuración y luego los inyectará en la clase de prueba. De esta manera, puede utilizar directamente los beans de Spring en la clase de prueba para realizar pruebas.

  • La clase es:

    ApplicationContext context = new ClassPathXmlApplicationContext("xxx.xml");
    Xxxx xxx = context.getBean(Xxxx.class);
    
  • Este código se carga a través ApplicationContextdel contexto xml classpath de la interfazClassPathXmlApplicationContext

8. Asuntos

Resumen de notas:

  1. Descripción general:
    1. Definición: Una transacción contiene una o más operaciones de datos, todas exitosas o todas fallidas.
    2. característica:
      • Atomicidad : o todos tienen éxito o todos fracasan
      • Consistencia : después de que falla la ejecución de la transacción, los datos en la base de datos no cambian
      • Aislamiento : múltiples transacciones están aisladas entre sí.
      • Durabilidad : una vez completada la transacción, los datos de la base de datos deben almacenarse de forma normal y persistente.
    3. Transacciones programáticas : use código para procesar transacciones
    4. Transacciones declarativas : utilice anotaciones para procesar transacciones. Anotación **@Transaccional**
  2. Transacciones declarativas basadas en anotaciones: lea esta sección en detalle
  3. Transacciones declarativas basadas en XML (comprensión): definir y aplicar aspectos a través de XML

8.1 Descripción general

8.1.1 Definición

​Una transacción (Transacción) se refiere a una unidad lógica de trabajo que consta de una o más secuencias de operaciones. Todas estas operaciones tienen éxito o todas fallan y se revierten. En una base de datos, una transacción incluye una o más operaciones de datos, como agregar, eliminar, modificar, etc. Al mismo tiempo, todas estas operaciones tienen éxito o todas fallan, y solo algunas operaciones no pueden tener éxito o fallar.

8.1.2 Funciones

  1. Atomicidad: una transacción es una unidad de trabajo indivisible en la que todo tiene éxito o todo fracasa. No se permiten éxitos ni fracasos parciales.
  2. Consistencia: antes y después de la ejecución de la transacción, el estado de la base de datos debe permanecer consistente. Si una transacción no se ejecuta, la base de datos debe restaurarse al estado anterior a la ejecución.
  3. Aislamiento: varias transacciones deben aislarse entre sí y las transacciones no deben interferir entre sí para evitar problemas como lecturas sucias, lecturas no repetibles y lecturas fantasma.
  4. Durabilidad: Una vez completada la transacción, las modificaciones a la base de datos deben persistir. Incluso si el sistema falla o falla, los datos no deben perderse.

8.2.3 Transacciones programáticas

​ Las transacciones programáticas se implementan escribiendo códigos de administración de transacciones en el código. Es necesario controlar manualmente el inicio, confirmación y reversión de las transacciones. Es necesario escribir códigos relevantes en cada método que requiere administración de transacciones, para que el código sea altamente acoplado, y El código de gestión de transacciones aparece repetidamente y es incómodo de mantener.

Connection conn = ...;
    
try {
    
    
    
    // 开启事务:关闭事务的自动提交
    conn.setAutoCommit(false);
    
    // 核心操作
    
    // 提交事务
    conn.commit();
    
}catch(Exception e){
    
    
    
    // 回滚事务
    conn.rollBack();
    
}finally{
    
    
    
    // 释放数据库连接
    conn.close();
    
}

8.2.4 Transacciones declarativas

Las transacciones declarativas se implementan a través de AOP, que separa el código de gestión de transacciones de la lógica empresarial. Al declarar la gestión de transacciones en el archivo de configuración, se realiza la gestión automática de transacciones. Los desarrolladores solo necesitan agregar Simplemente anotar o configurar, lo que simplifica enormemente la escritura del código. y trabajos de mantenimiento.

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);
    }
}

ilustrar:

  • En este ejemplo, @Transactionallas anotaciones se utilizan en el nivel de clase de la clase de implementación del servicio. Esto significa que cuando updateUserse invoca el método, Spring creará una transacción y cuando finalice la ejecución del método, la transacción se confirmará o revertirá (si ocurre una excepción).
  • De esta manera, al llamar updateUseral método, no necesitamos abrir y confirmar explícitamente la transacción, el marco Spring manejará automáticamente el envío y la reversión de la transacción.

8.2 Transacciones declarativas basadas en anotaciones

Sección de notas:

  1. Caso de uso básico:

    Paso 1: agregue el espacio de nombres tx , agregue el administrador de transacciones y habilite el controlador de anotaciones de transacciones

    Paso 2: Agregar anotación de transacción : @Transactional

  2. Atributos de transacción:

    1. Solo lectura : @Transactional ( readOnly = true), le dice a la base de datos que esta operación solo se puede leer y no reescribir.
    2. Tiempo de espera : @Transactional ( tiempo de espera = 3), cuando esta operación expire, solicite
    3. Estrategia de reversión :
      • Atributo rollbackFor: cuando el método de transacción genera una excepción del tipo especificado, la transacción se revertirá
      • Atributo rollbackForClassName: similar al atributo rollbackFor, pero utiliza una cadena al especificar el tipo de excepción.
      • Atributo noRollbackFor: especifica que la transacción no se revertirá cuando el método de transacción genere una excepción del tipo especificado.
      • Atributo noRollbackForClassName: similar al atributo noRollbackFor, pero utiliza una cadena al especificar el tipo de excepción.
    4. nivel de aislamiento :
      • READ_UNCOMMITTED: Indica que una transacción puede leer los datos de otra transacción no confirmada. Este nivel puede provocar lecturas sucias, lecturas no repetibles y lecturas fantasma y, en general, no se recomienda.
      • READ_COMMITTED: Indica que una transacción solo puede leer los datos de otra transacción confirmada, lo que puede evitar problemas de lectura sucia, pero aún pueden ocurrir problemas de lectura no repetible y lectura fantasma.
      • REPEATABLE_READ: Indica que una transacción puede leer la misma fila de datos varias veces durante la ejecución, lo que puede evitar problemas de lectura sucia y lectura no repetible, pero aún pueden ocurrir problemas de lectura fantasma .
      • SERIALIZABLE: Indica que una transacción bloquea todos los datos involucrados durante la ejecución, evitando los problemas de lecturas sucias, lecturas no repetibles y lecturas fantasmas, pero el rendimiento de concurrencia es muy pobre .
    5. Comportamiento de propagación : el comportamiento de propagación de una transacción se refiere a las reglas que controlan cómo las transacciones se propagan y afectan el comportamiento de cada una cuando varios métodos de transacción se llaman entre sí.
    6. Transacción de configuración de anotaciones completa : @EnableTransactionManagement activa la gestión de transacciones de anotaciones

8.2.1 Casos de uso básicos que implementan transacciones declarativas anotadas

Paso 1: agregue el espacio de nombres tx y la configuración en el archivo de configuración

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

ilustrar:

  1. Agregar espacio de nombres tx
  2. Agregar administrador de transacciones
  3. Habilitar controlador de anotación de transacciones

Paso 2: agregar anotaciones de transacciones

@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);
}

ilustrar:

  • La capa de servicio representa la capa de lógica empresarial y generalmente se agregan anotaciones a las funciones de la capa empresarial para lograr el propósito de la gestión de transacciones.
  • La anotación @Transactional marcada en el método solo afectará el método que será administrado por la herramienta de administración de transacciones. La anotación @Transactional marcada en la clase afectará a todos los métodos de la clase que serán administrados por la herramienta de administración de transacciones.

Paso 3: demostración

ilustrar:

Si hay un error en la transacción operativa, el marco Spring nos ayudará a revertir automáticamente los datos.

8.2.2 Atributos de transacción: solo lectura

Para una operación de consulta, si la configuramos en solo lectura, podemos decirle claramente a la base de datos que esta operación no implica operaciones de escritura. De esta manera, la base de datos se puede optimizar para operaciones de consulta.

@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);
}

ilustrar:

  1. En este momento, el atributo de solo lectura de la transacción se ha agregado a la transacción, por lo que agregar, eliminar y modificar operaciones generará una excepción:

  2. Caused by: java.sql.SQLException: Connection is read-only. Queries leading to data modification are not allowed
    

8.2.3 Atributos de transacción: tiempo de espera

Durante la ejecución de la transacción, se pueden encontrar algunos problemas que provocan que el programa se bloquee y ocupe recursos de la base de datos durante mucho tiempo. Sin embargo, si los recursos están ocupados durante mucho tiempo, existe una alta probabilidad de que haya un problema con la ejecución del programa (puede ser un programa Java o una base de datos MySQL o una conexión de red, etc.). En este momento, el programa que probablemente tenga problemas se debe revertir, se deben deshacer las operaciones que ha realizado, se debe finalizar la transacción y se deben liberar los recursos para que se puedan ejecutar otros programas normales.

//超时时间单位秒
@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);
}

ilustrar:

  1. En este momento, el atributo de tiempo de espera de la transacción se ha agregado a la transacción, por lo que si la operación de verificación y modificación excede la unidad de tiempo, se generará una excepción:

  2. org.springframework.transaction.TransactionTimedOutException: Transaction timed out: deadline was Fri Jun 04 16:25:39 CST 2022
    

8.2.4 Atributos de transacción: estrategia de reversión

La estrategia de reversión en los atributos de la transacción se refiere a cómo manejar la confirmación o reversión de la transacción cuando ocurre una excepción en la transacción.

Clasificación de atributos:

  1. Atributo rollbackFor: cuando el método de transacción genera una excepción del tipo especificado, la transacción se revertirá

    @Transactional(rollbackFor = {
          
          SQLException.class, IOException.class})
    
  2. Atributo rollbackForClassName: similar al atributo rollbackFor, pero utiliza una cadena al especificar el tipo de excepción.

    @Transactional(rollbackForClassName = {
          
          "java.sql.SQLException", "java.io.IOException"})
    
  3. Atributo noRollbackFor: especifica que la transacción no se revertirá cuando el método de transacción genere una excepción del tipo especificado.

    @Transactional(noRollbackFor = {
          
          NullPointerException.class, IllegalArgumentException.class})
    
  4. Atributo noRollbackForClassName: similar al atributo noRollbackFor, pero utiliza una cadena al especificar el tipo de excepción.

    @Transactional(noRollbackForClassName = {
          
          "java.lang.NullPointerException", "java.lang.IllegalArgumentException"})
    

Caso de uso básico:

@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);
}

ilustrar:

En este momento, el atributo configurado por la anotación @Transactional es noRollbackFor, por lo que cuando ArithmeticException.classocurre tal excepción, la transacción no se revertirá.

8.2.5 Atributos de transacción: nivel de aislamiento

El nivel de aislamiento de transacciones se refiere a un mecanismo de aislamiento adoptado por la base de datos para garantizar la coherencia de los datos entre transacciones cuando se ejecutan varias transacciones al mismo tiempo.

nivel de aislamiento lectura sucia lectura no repetible lectura fantasma
LEER SIN COMPROMISO tener tener tener
LEER COMPROMETIDO ninguno tener tener
LECTURA REPETIBLE ninguno ninguno tener
SERIALIZABLE ninguno ninguno ninguno

ilustrar:

  • READ_UNCOMMITTED: indica que una transacción puede leer datos de otra transacción no confirmada. Este nivel puede provocar lecturas sucias, lecturas no repetibles y lecturas fantasma y, en general, no se recomienda.
  • READ_COMMITTED: indica que una transacción solo puede leer los datos de otra transacción confirmada, lo que puede evitar problemas de lectura sucia, pero aún pueden ocurrir problemas de lectura no repetible y lectura fantasma.
  • REPEATABLE_READ: indica que una transacción puede leer la misma fila de datos varias veces durante la ejecución, lo que puede evitar problemas de lectura sucia y lectura no repetible, pero aún pueden ocurrir problemas de lectura fantasma.
  • SERIALIZABLE: Indica que una transacción bloquea todos los datos involucrados durante la ejecución, evitando los problemas de lecturas sucias, lecturas no repetibles y lecturas fantasmas, pero el rendimiento de concurrencia es muy pobre.

Uso básico

@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 Atributos de transacción: comportamiento de propagación

El comportamiento de propagación de transacciones se refiere a las reglas que controlan cómo se propagan las transacciones y afectan el comportamiento de cada una cuando varios métodos de transacción se llaman entre sí. En el marco Spring, el comportamiento de propagación de transacciones Propagationestá definido por clases de enumeración. Los comportamientos de propagación comúnmente utilizados incluyen los siguientes:

  1. OBLIGATORIO (predeterminado): si hay una transacción actual, únase a la transacción; si no hay ninguna transacción actual, cree una nueva transacción. Es decir, si no existe, crea uno nuevo, y si existe, agrégalo.
  2. SOPORTES: Si actualmente hay una transacción, únase a la transacción; si no hay ninguna transacción, continúe ejecutándose de manera no transaccional. En otras palabras, si lo tienes, únete; si no lo tienes, déjalo en paz.
  3. OBLIGATORIO: Si actualmente hay una transacción, únase a la transacción; si no hay ninguna transacción actual, genere una excepción. En otras palabras, si existe, agréguelo; si no, lanza una excepción.
  4. REQUIRES_NEW: Crear una nueva transacción. Si existe una transacción actualmente, suspender la transacción actual. En otras palabras, exista o no, se abre directamente una nueva transacción, no existe una relación de anidamiento entre la nueva transacción y la transacción anterior, y la transacción anterior se suspende.
  5. NOT_SUPPORTED: se ejecuta en modo no transaccional. Si actualmente existe una transacción, se suspenderá la transacción actual. En otras palabras, las transacciones no se admiten y se suspenderán si existen.
  6. NUNCA: se ejecuta en modo no transaccional y genera una excepción si existe una transacción actualmente. En otras palabras, si las transacciones no son compatibles, se generará una excepción si existen.
  7. NESTED: Si actualmente hay una transacción, se ejecutará dentro de la transacción anidada; si actualmente no hay ninguna transacción, se ejecutará de acuerdo con PROPAGATION_REQUIRED. En otras palabras, si hay una transacción, anide una transacción completamente independiente dentro de esta transacción, que se puede enviar y revertir de forma independiente. Ninguna transacción es igual a REQUERIDA
@Transactional(propagation = Propagation.REQUIRED)
public void transactionalMethod() {
    
    
    // ...
}

8.2.7 Transacciones de configuración de anotaciones completas (puntos clave)

Paso 1: agregar clase de configuración

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对象
    }
}

ilustrar:

​ Cuando utilice anotaciones completas para configurar transacciones, debe declarar un administrador de transacciones y usar la anotación @EnableTransactionManagement para habilitar el administrador de transacciones.

Paso 2: demostración

@Test
public void testTxAllAnnotation(){
    
    
    ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
    BookController accountService = applicationContext.getBean("bookController", BookController.class);
    accountService.buyBook(1, 1);
}

8.2.8 Principios subyacentes

En Java, el uso de @Transactionalanotaciones para implementar la gestión de transacciones a nivel de método se basa en las características del marco Spring y los principios de AOP (programación orientada a aspectos).

El principio subyacente es el siguiente:

  1. @TransactionalSpring intercepta la ejecución de métodos con anotaciones a través de la funcionalidad AOP .
  2. Cuando se llama a un método, Spring crea un objeto proxy para el método en tiempo de ejecución.
  3. El objeto proxy insertará lógica relacionada con la transacción antes y después de la ejecución del método.
  4. Al comienzo del método, el administrador de transacciones inicia una nueva transacción de base de datos.
  5. Si el método se ejecuta correctamente (no se genera ninguna excepción), el administrador de transacciones confirmará la transacción y persistirá las modificaciones en la base de datos.
  6. Si ocurre una excepción durante la ejecución del método, el administrador de transacciones revertirá la transacción, deshará las modificaciones en la base de datos y restaurará el estado antes de que comenzara la transacción.
  7. Una vez completada la ejecución del método, el administrador de transacciones cierra la transacción.

A través de AOP, Spring puede controlar las transacciones antes y después de la ejecución del método. Inicia una transacción antes de que se ejecute el método y confirma o revierte la transacción después de que se ejecuta el método, garantizando así la coherencia e integridad de los datos.

imagen-20230624175741508

Cabe señalar que @Transactionalla efectividad de las anotaciones también depende de la configuración del administrador de transacciones y del soporte del entorno de uso. El marco Spring proporciona una variedad de implementaciones de administradores de transacciones, como administradores de transacciones basados ​​en JDBC y administradores de transacciones basados ​​en JTA, y usted puede elegir el administrador de transacciones adecuado según sus necesidades específicas. Al mismo tiempo, Spring necesita habilitar el administrador de transacciones en el archivo de configuración y garantizar que el @Transactionalmétodo anotado se llame a través del objeto proxy obtenido por el contenedor Spring. Sólo de esta manera las anotaciones de las transacciones podrán surtir efecto y las funciones de gestión de transacciones podrán aplicarse correctamente.

8.3 Transacciones declarativas basadas en XML (comprensión)

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

Nota: Las transacciones declarativas implementadas en base a xml deben introducir dependencias de aspectoJ

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>6.0.2</version>
</dependency>

9. Operaciones de recursos: Recursos

Resumen de notas:

  1. Descripción general: en el marco Spring, org.springframework.core.io.Resourcelas interfaces y sus clases de implementación son capas de abstracción que se utilizan para manejar recursos (como archivos, recursos de classpath, URL, etc.)
  2. Interfaz de recursos: la interfaz de recursos es una abstracción de la estrategia de acceso a recursos de Spring. No proporciona ninguna implementación de acceso a recursos. El acceso a recursos específicos lo completa la clase de implementación de esta interfaz . La interfaz de recursos se utiliza para abstraer el acceso a recursos de bajo nivel.
  3. Clase de implementación de recursos:
    • UrlResource: Esta clase se utiliza para representar recursos de tipo URL , que se pueden utilizar para acceder a recursos de la red.
    • ClassPathResource : ClassPath Resource se utiliza para representar recursos bajo la ruta de clase y se puede crear una instancia especificando la ruta relativa o absoluta del recurso.
    • FileSystemResource : La clase FileSystem Resource se utiliza para acceder a los recursos del sistema de archivos.
    • ServletContextResource:levemente
    • InputStreamResource:levemente
    • ByteArrayResource:levemente
  4. Interfaz ResourceLoader: define un método de acceso unificado para cargar recursos.
  5. Clase de implementación de ResourceLoader:
    • DefaultResourceLoader: El cargador de recursos predeterminado, que se puede utilizar para cargar recursos de classpath, sistema de archivos y URL .
    • FileSystemResourceLoader: Se utiliza para cargar recursos desde el sistema de archivos .
    • ClassPathResourceLoader: Se utiliza para cargar recursos bajo el classpath .
    • ServletContextResourceLoader: Se utiliza para cargar recursos en el contexto de una aplicación web .
  6. Interfaz ResourceLoaderAware: se utiliza para inyectar instancias de ResourceLoader en Beans que implementan esta interfaz.
  7. Obtenga recursos de recursos dinámicamente: utilice directamente la inyección de dependencia para simplificar al máximo el acceso a los recursos de Spring
  8. Determine la ruta de acceso a los recursos:
    • Implementar la ruta de acceso especificada por la clase
      • ClassPathXML ApplicationContext: Corresponde al uso de ClassPathResource para acceder a recursos.
      • FileSystemXml ApplicationContext: Corresponde al uso de FileSystemResource para el acceso a recursos.
      • XmlWeb ApplicationContext: Corresponde al uso de ServletContextResource para el acceso a recursos.
    • El prefijo especifica la ruta de acceso:
      1. prefijo de ruta de clase
      2. comodín de ruta de clase
      3. Otros usos de los comodines

9.1 Descripción general

En el marco Spring, org.springframework.core.io.Resourcelas interfaces y sus clases de implementación son capas de abstracción que se utilizan para manejar recursos (como archivos, recursos de classpath, URL, etc.). Proporciona una forma unificada de acceder y manipular diferentes tipos de recursos, ya sea que se acceda a ellos en el sistema de archivos, bajo el classpath o mediante URL.

9.2Interfaz de recursos

9.2.1 Descripción general

La interfaz de recursos de Spring se encuentra org.springframework.core.ioen . Pretende ser una interfaz más poderosa para abstraer el acceso a recursos de bajo nivel.

Las interfacesResource heredan InputStreamSourceinterfaces en Spring y proporcionan más métodos. La interfaz tiene un solo InputStreamSourcemétodo.

9.2.2 Métodos comunes

  • boolean exists(): Compruebe si el recurso existe.
  • boolean isReadable(): Compruebe si el recurso es legible.
  • boolean isOpen(): compruebe si el recurso está abierto.
  • URL getURL(): Obtenga la URL del recurso.
  • URI getURI(): obtiene el URI del recurso.
  • File getFile(): Obtiene el archivo correspondiente al recurso.
  • long contentLength(): Obtenga la longitud del recurso.
  • long lastModified(): Obtiene la hora de la última modificación del recurso.
  • Resource createRelative(String relativePath): Crea un recurso relativo al recurso actual.
  • String getFilename(): obtiene el nombre de archivo del recurso.
  • String getDescription(): Obtenga la información de descripción del recurso.
  • InputStream getInputStream(): obtiene el flujo de entrada del recurso.

9.3 Clase de implementación de recursos

9.3.1 Descripción general

La interfaz de recursos es una abstracción de la estrategia de acceso a recursos de Spring. No proporciona ninguna implementación de acceso a recursos en sí misma. El acceso a recursos específicos lo completa la clase de implementación de esta interfaz. Cada clase de implementación representa una estrategia de acceso a recursos. El recurso generalmente incluye estas clases de implementación:UrlResource、ClassPathResource、FileSystemResource、ServletContextResource、InputStreamResource、ByteArrayResource

imagen-20230516133813254

9.3.2Clase de recurso URL

Esta clase se utiliza para representar recursos de tipo URL, de los que se puede crear una instancia a través de la ruta URL del URLobjeto o tipo y usarse para acceder a los recursos de la red.String

Caso de uso básico:

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");
    }
}

ilustrar:

  • Al acceder a los recursos del sistema de archivos, el archivo debe leerse según la ruta raíz del proyecto actual.

    imagen-20230516140223559

Reponer:

  • http:------Este prefijo se utiliza para acceder a recursos de red según el protocolo HTTP.
  • ftp:------Este prefijo se utiliza para acceder a recursos de red según el protocolo FTP
  • archivo: ------ Este prefijo se utiliza para leer recursos del sistema de archivos

9.3.3ClassPathClase de recurso

ClassPathResource se utiliza para representar recursos bajo la ruta de clase y se puede crear una instancia especificando la ruta relativa o absoluta del recurso. En comparación con otras clases de implementación de recursos, su principal ventaja es que facilita el acceso a los recursos en la ruta de carga de clases, especialmente para aplicaciones web. , ClassPathResource puede buscar automáticamente archivos de recursos ubicados en clases sin utilizar el acceso a la ruta absoluta.

Caso de uso básico:

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");
    }
}

ilustrar:

  • Al acceder al sistema de recursos de archivos, el archivo debe leerse según la ruta de clase del proyecto actual.

    imagen-20230516140413107

9.3.4 Clase de recurso FileSystem

La clase FileSystemResource proporcionada por Spring se usa para acceder a los recursos del sistema de archivos. No hay muchas ventajas en usar FileSystemResource para acceder a los recursos del sistema de archivos, porque la clase File proporcionada por Java también se puede usar para acceder a los recursos del sistema de archivos.

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.5Clase de recurso ServletContext

Esta es ServletContextuna implementación de recurso de un recurso que interpreta rutas relativas dentro del directorio raíz de la aplicación web asociada. Siempre admite acceso a transmisiones y acceso a URL, pero solo permite el acceso a java.io.File si el archivo de la aplicación web está extendido y el recurso está realmente en el sistema de archivos. Ya sea que esté extendido en el sistema de archivos o accedido directamente desde un JAR o desde otro lugar (como una base de datos), en realidad depende del contenedor de Servlet.

9.3.6 Clase de recurso InputStream

EsInputStreamResource la implementación de recursos del flujo de entrada dado. Su escenario de uso se utiliza cuando no hay una implementación de recursos específica (se siente muy similar al escenario aplicable de @Component). A diferencia de otras implementaciones de recursos, este es un descriptor de un recurso abierto. Por tanto, sus isOpen()métodos devuelven verdadero. No lo use si necesita mantener el descriptor de recursos en algún lugar o si necesita leer la secuencia varias veces.

9.6.7 Clase de recurso ByteArray

​ Clase de implementación de recursos de matriz de bytes. Crea uno a partir de la matriz dada ByteArrayInputStream. Es útil para cargar contenido desde cualquier matriz de bytes determinada sin recurrir a los de un solo uso InputStreamResource.

9.4Interfaz del cargador de recursos

9.4.1 Descripción general

La interfazResourceLoader es una interfaz central en el marco Spring y define un método de acceso unificado para cargar recursos. Proporciona un método unificado para cargar varios tipos de recursos, como archivos, recursos de classpath, recursos de URL, etc.

9.4.2 Métodos comunes

  • Resource getResource(String location)Resource: Obtiene un objeto basado en la ubicación del recurso dada . Las ubicaciones de los recursos pueden ser rutas de archivos, classpaths, URL, etc. La estrategia de carga de recursos específica ResourceLoaderestá determinada por la clase de implementación específica.
  • ClassLoader getClassLoader(): Obtiene el objeto utilizado para cargar la clase ClassLoader. Esto es útil para cargar recursos en el classpath.

9.4.3 Clase de implementación

El marco Spring proporciona múltiples ResourceLoaderclases que implementan interfaces, que incluyen:

  • DefaultResourceLoader: El cargador de recursos predeterminado, que se puede utilizar para cargar recursos de classpath, sistema de archivos y URL.
  • FileSystemResourceLoader: Se utiliza para cargar recursos desde el sistema de archivos.
  • ClassPathResourceLoader: Se utiliza para cargar recursos bajo el classpath.
  • ServletContextResourceLoader: Se utiliza para cargar recursos en el contexto de una aplicación web.

9.4.4 Casos de uso básicos

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());
}

ilustrar:

Spring utilizará la misma estrategia que ApplicationContext para acceder a los recursos. En otras palabras, si ApplicationContext es ClassPathXmlApplicationContext, res es la instancia de ClassPathResource

public static void main(String[] args) {
    
    
    // 创建Spring应用上下文,指定文件系统路径加载配置文件
    ApplicationContext ctx = new FileSystemXmlApplicationContext();
    Resource res = ctx.getResource("atguigu.txt");
    System.out.println(res.getFilename());
}

ilustrar:

Spring utilizará la misma estrategia que ApplicationContext para acceder a los recursos. En otras palabras, si ApplicationContext es FileSystemXmlApplicationContext, res es una instancia de FileSystemResource;

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());
    }
}

ilustrar:

Utilice el método getResource() de ApplicationContext para obtener tres tipos diferentes de recursos y utilice diferentes prefijos para especificar el uso de diferentes clases de implementación de recursos.

9.5Interfaz ResourceLoaderAware

9.5.1 Descripción general

9.5.1.1 Significado

ResourceLoaderAware es una interfaz Spring Bean que se utiliza para inyectar instancias de ResourceLoader en beans que implementan esta interfaz. Define un método setResourceLoader (ResourceLoader ResourceLoader), al cual el contenedor Spring pasa la instancia de ResourceLoader como parámetro al iniciar.

9.5.1.2 Función

Las clases que implementan la interfaz ResourceLoaderAware pueden obtener la instancia ResourceLoader del contenedor Spring, utilizando así la función de carga de recursos proporcionada por el contenedor Spring.

9.5.2 Casos de uso básicos

Paso 1: crear frijol

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;
    }

}

ilustrar:

  • Para implementar la interfaz ResourceLoaderAware, debe implementar setResourceLoadermétodos,

Paso 2: configurar 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>

Paso 3: demostración

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());
}

ilustrar:

Debido a que ApplicationContextla clase de implementación de la interfaz ClassPathXmlApplicationContextimplementa ResourceLoaderla interfaz, ClassPathXmlApplicationContextel objeto de instancia también tiene la función de "ResourceLoader". Por lo tanto, los objetos que implementan ResourceLoaderAwareesta interfaz pueden usar la función de carga de recursos proporcionada por el contenedor Spring.

9.6 Obtener recursos de recursos dinámicamente

9.6.1 Descripción general

9.6.1.1 Significado

El marco Spring no solo hace un uso completo del patrón de estrategia para simplificar el acceso a los recursos, sino que también combina completamente el patrón de estrategia con IoC para simplificar al máximo el acceso a los recursos de Spring. Cuando las instancias de beans en una aplicación necesitan acceder a recursos, Spring tiene una mejor solución: usar directamente la inyección de dependencia

9.6.1.2 Función

​ Para obtener la instancia de Recurso en el código, cuando el programa obtiene la instancia de Recurso, siempre necesita proporcionar la ubicación del Recurso, ya sea creando una instancia a través de FileSystemResource, creando una instancia a través de ClassPathResource u obteniendo una instancia a través de getResource( ) método de ApplicationContext, todos necesitan Proporcionar la ubicación del recurso. Esto significa: la ubicación física del recurso se acoplará al código y, si la ubicación del recurso cambia, el programa deberá reescribirse. Por lo tanto, generalmente se recomienda utilizar la inyección de dependencia para permitir que Spring inyecte recursos en las instancias de Bean.

9.6.2 Casos de uso básicos

Paso 1: crear una clase de inyección de dependencia y definir propiedades y métodos

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());
    }
}

Paso 2: cree un archivo de configuración de Spring y configure la inyección de dependencia

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

Paso 3: demostración

public static void main(String[] args) {
    
    
    ApplicationContext ctx =
        new ClassPathXmlApplicationContext("bean.xml");
    ResourceBean resourceBean = ctx.getBean("resourceBean",ResourceBean.class);
    resourceBean.parse();
}

9.7 Determinar la ruta de acceso a los recursos

9.7.1 Descripción general

No importa cómo cree una instancia de ApplicationContext, debe especificar un archivo de configuración para ApplicationContext. Spring permite el uso de uno o más archivos de configuración XML. Cuando un programa crea una instancia de ApplicationContext, generalmente accede al archivo de configuración en forma de recurso, por lo que ApplicationContext admite totalmente métodos de acceso a recursos como ClassPathResource, FileSystemResource y ServletContextResource.

9.7.2 Implementación de clases para especificar rutas de acceso

(1) ClassPathXMLApplicationContext: corresponde al uso de ClassPathResource para acceder a recursos.

(2) FileSystemXmlApplicationContext: corresponde al uso de FileSystemResource para acceder a recursos.

(3) XmlWebApplicationContext: utilice ServletContextResource en consecuencia para acceder a los recursos.

Para conocer los pasos detallados, consulte la clase de implementación de Recursos.

9.7.3 El prefijo especifica la ruta de acceso

9.7.3.1 prefijo de ruta de clases

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());
    }
}

ilustrar:

​ Cuando use ApplicationContext, al especificar la ruta, use **classpath:** como prefijo

9.7.3.2 comodín de ruta de clase

ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath*:bean.xml");

ilustrar:

Cuando use ApplicationContext, al especificar la ruta, use classpath * como prefijo, lo que significa que Spring buscará todos los archivos de configuración que cumplan con esta regla en la ruta de carga de clases. Por ejemplo: bean.xml, beans.xml

9.7.3.3 Otros usos de comodines

ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:bean*.xml");

ilustrar:

Cómo cargar varios archivos de configuración a la vez: use comodines al especificar archivos de configuración

ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath*:bean*.xml");

ilustrar:

​ Spring permite la combinación de classpath*: prefijos y comodines

10. Internacionalización: i18n

Resumen de notas:

  1. Descripción general: diseño de software, aplicaciones o sitios web para adaptarse a las necesidades de diferentes idiomas , culturas y regiones.

  2. Internacionalización de Java:

    • Clase ResourceBundle : es una clase de herramienta de internacionalización que se utiliza para cargar y administrar archivos de recursos en diferentes entornos lingüísticos.

    • Reglas de nomenclatura de archivos de configuración: basename_language_country.properties, por ejemplomessages_en_CB.properties

    • Caso de uso básico:

      1. Crear archivo de configuración de recursos

      2. Obtenido a través de la clase ResourceBundle

        public static void main(String[] args) {
                   
                   
            ResourceBundle resourceBundle = ResourceBundle.getBundle("messages", new Locale("en", "GB"));
            String string = resourceBundle.getString("test");
            System.out.println(string);
        }
        
  3. Internacionalización Spring6

    Paso 1: crear un archivo de configuración de recursos de propiedades

    Paso 2: cree un archivo de configuración de Spring y configure MessageSource

    Paso 3: Obtenga las claves en el archivo de configuración de recursos inyectándolas en el archivo de configuración de Spring6

    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 Descripción general

​La internacionalización, muchas veces abreviada como i18n (i + 18 letras + n), se refiere al diseño de software, aplicaciones o sitios web para poder adaptarse a las necesidades de diferentes idiomas, culturas y regiones. En términos generales, la internacionalización del software se logra a través de archivos de configuración. Si se quieren admitir dos idiomas, se requieren dos versiones de los archivos de configuración.

10.2 Internacionalización de Java

10.2.1 método crearConstante

imagen-20230525173916281

ilustrar:

java.util.Locale se usa para especificar información como la configuración regional a la que pertenece el usuario actual, y java.util.ResourceBundle se usa para encontrar el archivo de recursos correspondiente al enlace. La configuración regional contiene información de idioma e información del país. El método estático utilizado por Locale al crear el objeto de configuración regional predeterminado:

10.2.2 Clase de paquete de recursos

​ ResourceBundle es una clase de herramienta proporcionada por Java para la internacionalización (internacionalización), que se utiliza para cargar y administrar archivos de recursos en diferentes entornos de lenguaje.

10.2.3 Reglas de nomenclatura de archivos de configuración

basename_language_country.properties

ilustrar:

Debes seguir las reglas de nomenclatura anteriores antes de que Java lo reconozca. Entre ellos, el nombre base es obligatorio, el idioma y el país son opcionales. Aquí existe un concepto de prioridad. Si se proporcionan mensajes.properties y mensajes_zh_CN.propertes al mismo tiempo, y si la configuración regional proporcionada se ajusta a en_CN, entonces se buscará primero en el archivo de configuración mensajes_en_CN.propertes. Si no se encuentra, los mensajes Se buscará la configuración .properties.document. Finalmente, cuando se le solicite, todos los archivos de configuración deben colocarse en el classpath, generalmente en el directorio de recursos.

10.3 Casos de uso básicos

Paso 1: crear un archivo de configuración en el archivo de recursos de recursos

imagen-20230525175111010

ilustrar:

El sistema genera automáticamente los 'mensajes' del paquete de recursos porque los archivos de propiedades creados cumplen con las reglas de nomenclatura internacionales de Java.

Paso 2: escribir archivos de configuración en diferentes idiomas

test=123
// 
test=456

Paso 3: demostración

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);
    }
}

ilustrar:

La clase ResourceBundle se utiliza para administrar archivos de recursos en diferentes entornos lingüísticos durante la internacionalización y la configuración regional se utiliza para especificar el entorno lingüístico al que pertenece el usuario actual.

10.4 Internacionalización Primavera 6

Paso 1: crear archivos de recursos

Formato de denominación de archivos internacionalizado: nombre_idioma_país.properties básico

Contenidos como {0}{1} son parámetros dinámicos.

imagen-20221207140024056

(1) Crear atguigu_en_US.properties

www.atguigu.com=welcome {0},时间:{1}

(2) Crear atguigu_zh_CN.properties

www.atguigu.com=欢迎 {0},时间:{1}

Paso 2: cree un archivo de configuración de Spring y 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>

ilustrar:

En Spring 6, nombrar la identificación de ResourceBundleMessageSource como messageSource puede reducir la configuración innecesaria y las referencias explícitas y permitir que Spring 6 logre la inyección automática.

Paso 3: crear una clase de prueba

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. Verificación de datos: Validación

Resumen de notas:

  1. Descripción general: la validación de datos (Validación) es el proceso de validar los datos ingresados ​​por el usuario en una aplicación para garantizar que los datos cumplan con las reglas y restricciones esperadas.

  2. La verificación se implementa a través de la interfaz del Validador:

    Paso 1: Importación hibernate-validatory jakarta.eldependencia

    Paso 2: crear una clase de entidad

    Paso 3: implementar la interfaz del Validador

    Paso 4: implementar DataBinderel validador

  3. Implementar la verificación mediante la anotación Bean Validation (recomendado):

    Paso 1: crear una clase de archivo de configuración

    Paso 2: cree una clase de entidad y use anotaciones para definir reglas de verificación

    Paso 3: cree el servicio de validación (usando @Autowired)

    Paso 4: verificar

  4. La verificación se implementa mediante métodos:

    Paso 1: crear una clase de archivo de configuración

    Paso 2: cree una clase de entidad y use anotaciones para definir reglas de verificación

    Paso 3: crear el servicio de validación (usando @Valid)

  5. Pasar la verificación personalizada (complementaria):

    Paso 1: personaliza las anotaciones de verificación

    Paso 2: escribir la clase de verificación implementada

  6. Para obtener más anotaciones: consulte Verificación del parámetro de solicitud de arranque de primavera: uso de la anotación @Validated, verificación manual, anotación personalizada de verificación_validación blog-CSDN de verificar_sayyy

11.1 Descripción general

La validación de datos (Validación) es el proceso de validar los datos de entrada del usuario en una aplicación para garantizar que los datos se ajusten a las reglas y restricciones esperadas. En Java, el marco de validación de datos comúnmente utilizado es la API de validación, que forma parte de Java EE y también está integrada y admitida en el marco Spring.

11.2 Verificación de casos de uso básico a través de la interfaz del Validador

ilustrar:

Implementar la verificación de datos a través de Validatorinterfaces es otra forma de utilizar la API de validación para la verificación de datos. ValidatorLa interfaz proporciona un mecanismo de verificación más flexible y puede personalizar la lógica de verificación y los mensajes de error.

Paso 1: Introducir dependencias relevantes

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

Paso 2: crear una clase de entidad

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;
    }
}

Paso 3: implementar la interfaz del Validador

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");
        }
    }
}

ilustrar:

  • Implementar la interfaz del Validador, anular los soportes y validar los métodos, e implementar la lógica.
  • ValidationUtils es una clase de herramienta de verificación encapsulada por Spring para ayudar a implementar rápidamente la verificación.

Paso 4: demostrar

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());
}

ilustrar:

Al utilizar DataBinderel validador, puede realizar fácilmente la validación de datos en el objeto y obtener el resultado de la validación.

11.3 Verificación de casos de uso básico mediante la anotación de validación de Bean

ilustrar:

Bean Validation es una especificación de validación de datos basada en anotaciones en Java. Las reglas de validación de datos se pueden definir agregando las anotaciones correspondientes a los atributos de las clases de entidad.

Anotaciones de uso común:

  1. @NotNull: Compruebe que el valor del campo no sea nulo.
  2. @NotEmpty: Comprueba que el valor de una cadena, colección o matriz no esté vacío.
  3. @NotBlank: Comprueba que el valor de la cadena no esté vacío o contenga solo espacios en blanco.
  4. @Min(value): Comprueba que el valor del campo sea mayor o igual al valor mínimo especificado.
  5. @Max(value): Comprueba que el valor del campo sea menor o igual al valor máximo especificado.
  6. @Size(max, min): Comprueba que el tamaño del valor del campo esté dentro del rango especificado.
  7. @Email: Compruebe que el valor del campo cumpla con los requisitos de formato del correo electrónico.
  8. @Pattern(regex): Verifique que el valor del campo coincida con la expresión regular especificada.

Paso 1: crear una clase de archivo de configuración

@Configuration
@ComponentScan("org.example")
public class ValidationConfig {
    
    

    @Bean
    public LocalValidatorFactoryBean validator() {
    
    
        return new LocalValidatorFactoryBean();
    }
}

ilustrar:

  • LocalValidatorFactoryBeanEs una clase proporcionada por el marco Spring que implementa ValidatorFactoryla interfaz y se utiliza para crear y administrar Validatorinstancias.
  • Configurar las reglas de escaneo de ComponentScan es para habilitar el escaneo de paquetes y facilitar la inyección de Bean del marco Spring.

Paso 2: cree una clase de entidad y use anotaciones para definir reglas de verificación

@Data
public class User {
    
    

    @NotNull
    private String name;

    @Min(0)
    @Max(120)
    private int age;
}

Aviso:

Las anotaciones @Max y @Min requieren importar dependencias antes de la verificación de datos. Para conocer las dependencias, consulte a través de la interfaz del Validador.

Paso 3: crea el validador

1. Utilice jakarta.validation.Validator para verificar

@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();
    }
}

ilustrar:

Durante el proceso de verificación, Validatorcada atributo del objeto de usuario se verificará por turno para verificar si cumple con las restricciones especificadas. Si el valor de un atributo no cumple con las condiciones de la restricción, ConstraintViolationse generará un objeto que contiene información detallada sobre la violación de la restricción, como el nombre del atributo, el tipo de restricción violada, mensaje de error, etc. Finalmente, estos ConstraintViolationobjetos se recogen en una Setcolección y se devuelven.

2. Utilice org.springframework.validation.Validator para verificar

@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();
    }
}

ilustrar:

BindException​es org.springframework.validationuna clase en el paquete, que hereda de org.springframework.validation.Errorsla interfaz y se utiliza para recopilar información de error de verificación. Al crear BindExceptionun objeto, los resultados de la verificación se pueden recopilar en él para facilitar el procesamiento posterior de la información de error.

Aviso:

​ Cuando usas Validator, necesitas importar dependencias, al igual que a través de la interfaz de Validator.

Paso 4: demostrar

1. Utilice jakarta.validation.Validator para verificar

  @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. Utilice org.springframework.validation.Validator para verificar

    @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 Casos de uso básicos: verificación mediante métodos

ilustrar:

La verificación basada en métodos se refiere al uso de anotaciones de verificación en un método específico para verificar los parámetros de entrada, el valor de retorno o el estado del método durante la ejecución del método. Spring proporciona anotaciones y anotaciones de @Validatedverificación (como @NotNull,,, etc. ) para implementar la verificación basada en métodos.@NotBlank@Min@Max

Paso 1: crear una clase de archivo de configuración

@Configuration
@ComponentScan("org.example")
public class ValidationConfig {
    
    

    @Bean
    public MethodValidationPostProcessor validationPostProcessor() {
    
    
        return new MethodValidationPostProcessor();
    }
}

ilustrar:

EsMethodValidationPostProcessor un posprocesador proporcionado por Spring para la verificación de parámetros al llamar a métodos. Puede interceptar automáticamente @Validatedmétodos marcados por anotaciones y verificar los parámetros de los métodos.

Paso 2: cree una clase de entidad y use anotaciones para definir reglas de verificación

@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;
}

Paso 3: crea el validador

@Service
@Validated
public class MyService {
    
    
    //	使用 @Valid 注解标记了 User 参数,表示对该参数进行校验、使用 @NotNull 注解标记了 User 参数,表示该参数不能为空。
    public String testParams(@NotNull @Valid User user) {
    
    
        return user.toString();
    }
}

ilustrar:

Si la verificación falla, se lanzará una ConstraintViolationException. Si la verificación pasa, se ejecutará otra lógica de negocios.

Paso 4: demostrar

@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 Verificación personalizada de paso de caso de uso básico

Paso 1: personaliza las anotaciones de verificación

@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();
    }
}

ilustrar:

Para la implementación del contenido de esta anotación, puede consultar la parte que viene con la anotación existente.

Reponer:

  • @TargetLas anotaciones se utilizan para especificar el alcance de uso de las anotaciones, incluidos métodos, campos, tipos de anotaciones, constructores y parámetros.
  • @RetentionLa anotación se utiliza para especificar el ciclo de vida de la anotación, es decir, la información de la anotación aún se conserva en tiempo de ejecución.
  • @DocumentedUna anotación se utiliza para indicar que la anotación debe incluirse en el documento generado.
  • @ConstraintLa anotación marca la anotación como una anotación de verificación y especifica la clase de validador correspondiente CannotBlankValidator.
  • message()El método define un mensaje de error predeterminado que se utiliza cuando falla la validación.
  • groups()El método se utiliza para la verificación de grupo y puede especificar en qué grupo entrará en vigor el validador.
  • payload()El método especifica el tipo de carga útil, que se puede utilizar en validadores personalizados.
  • @ListLa anotación se utiliza cuando se especifican varias @CannotBlankanotaciones; se pueden combinar varias anotaciones.

Aviso:

La anotación en sí no implementa una lógica de verificación específica, pero CannotBlankValidatorimplementa la lógica de verificación específica a través de la clase de validador.

Paso 2: escribe la clase de validación

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;
        }
}

ilustrar:

  • Cree una clase de validador personalizada: implemente la interfaz ConstraintValidator y especifique el tipo de anotación que se verificará y el tipo de valor que se verificará. En la lógica de verificación, implemente reglas de verificación personalizadas y devuelva los resultados de la verificación según sea necesario.
  • En isValid()el método hay dos parámetros:
    • value: El valor a verificar, es decir, el valor del campo o parámetro del método que debe verificarse.
    • context: El objeto de contexto del validador, utilizado para controlar algunos comportamientos y configuraciones durante el proceso de validación.
  • Al implementar isValid()el método, de acuerdo con las reglas de verificación personalizadas, puede usar valueparámetros para obtener el valor a verificar y verificarlo de acuerdo con la lógica empresarial. Si la verificación es exitosa, regresa truepara indicar que se pasó la verificación; si la verificación falla, regresa falsepara indicar que no se pasó la verificación.

Paso 3: demostración

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);
}

ilustrar:

Este paso solo implementa reglas personalizadas para la verificación a través de anotaciones personalizadas. Para obtener detalles sobre cómo implementar la verificación, debe consultar el 实现método de verificación.

12. Compilación anticipada: AOT

Resumen de notas:

  1. Descripción general:
    • Significado: la compilación anticipada (AOT) es una tecnología que compila el código de un programa en código de máquina antes de ejecutarlo . A diferencia de la compilación justo a tiempo (JIT) tradicional, la compilación justo a tiempo interpreta el código del programa línea por línea en código de máquina y lo ejecuta en tiempo de ejecución.
    • Graalvm: la tecnología AOT admitida por Spring6, este GraalVM es el soporte subyacente y Spring también proporciona soporte de primera clase para imágenes nativas de GraalVM. GraalVM es un JDK de alto rendimiento diseñado para acelerar la ejecución de aplicaciones escritas en Java y otros lenguajes JVM, al tiempo que proporciona tiempos de ejecución para JavaScript, Python y muchos otros lenguajes populares.
    • Imagen nativa: en la actualidad, además de la solución AOT en JVM, existe otra forma de implementar Java AOT en la industria, que es abandonar directamente JVM y compilar el código en código de máquina directamente a través del compilador como C/C++. y luego ejecutar. Esta es sin duda una idea que subvierte directamente el diseño del lenguaje Java, es decir, GraalVM Native Image.
  2. Proceso de construcción de imágenes nativas
    • Instalación de GraalVM
    • Instalar el entorno de compilación de C++
    • Escribir código y crear una imagen nativa

12.1 Descripción general

12.1.1 Significado

La compilación anticipada (AOT) es una tecnología que compila el código de un programa en código de máquina antes de ejecutarlo . A diferencia de la compilación justo a tiempo (JIT) tradicional, la compilación justo a tiempo interpreta el código del programa línea por línea en código de máquina y lo ejecuta en tiempo de ejecución.

Ventajas del AOT

  1. Tiempo de inicio más rápido : dado que el código se ha compilado en código de máquina, no es necesario compilarlo e interpretarlo en tiempo de ejecución, por lo que se puede ejecutar directamente, lo que reduce el tiempo de inicio.
  2. Mayor rendimiento de ejecución : la compilación AOT puede realizar una optimización estática integral, incluida la optimización del código, la inserción en línea, la eliminación de comprobaciones innecesarias, etc. Estas optimizaciones se realizan en tiempo de compilación y pueden proporcionar un mayor rendimiento de ejecución .
  3. Mejor seguridad : la compilación AOT puede compilar el código fuente en código de máquina, ocultando la lógica del código fuente y proporcionando una mejor seguridad.

Desventajas de AOT

  1. Salida de compilación más grande: la compilación AOT compila completamente el código fuente o el código intermedio en código de máquina, por lo que la salida de la compilación suele ser mayor que el código fuente o el código de bytes y ocupa más espacio de almacenamiento.
  2. Retraso en el tiempo de compilación: la compilación AOT debe realizarse antes de que se pueda ejecutar el programa, lo que aumenta los costos de tiempo de desarrollo y compilación, especialmente para bases de código más grandes o proyectos complejos.
  3. Falta de optimización del tiempo de ejecución: dado que la compilación AOT se realiza antes de ejecutar el programa, no se puede optimizar en función de la información del contexto de tiempo de ejecución real y no se puede adaptar dinámicamente al entorno de ejecución cambiante.

12.1.2 La diferencia entre JIT y AOT

JIT, compilación dinámica (justo a tiempo) justo a tiempo, compilación durante la ejecución;

Cuando el programa se está ejecutando, el código activo se calcula en función del algoritmo y luego se realiza la compilación JIT en tiempo real. Este método tiene un alto rendimiento, tiene una bonificación de rendimiento en tiempo de ejecución, puede ejecutarse más rápido y puede generar código dinámicamente , etc. Pero la velocidad de inicio es relativamente lenta y se necesita una cierta cantidad de tiempo y frecuencia de llamadas para activar el mecanismo de capas JIT. La desventaja de JIT es que la compilación requiere recursos de tiempo de ejecución, lo que puede provocar retrasos en el proceso.

AOT, Ahead Of Time, se refiere a compilación previa a la ejecución, precompilación;

La compilación AOT puede convertir directamente el código fuente en código de máquina, con un uso bajo de memoria y una velocidad de inicio rápida . Puede ejecutarse sin tiempo de ejecución y vincular estáticamente directamente el tiempo de ejecución al programa final. Sin embargo, no hay bonificación de rendimiento del tiempo de ejecución y no se puede basar depende del estado de ejecución del programa. Para una mayor optimización, la desventaja de AOT es que compilar el programa antes de ejecutarlo aumentará el tiempo de instalación del programa.

En general: la compilación JIT justo a tiempo se refiere al proceso de convertir código de bytes en código de máquina que se puede ejecutar directamente en el hardware durante la ejecución del programa e implementarlo en el entorno de alojamiento. La compilación AOT se refiere al proceso de convertir código de bytes en código de máquina antes de que se ejecute el programa.

imagen-20230526155600385

ilustrar:

​ .java -> .class -> (usando la herramienta de compilación jaotc) -> .so (biblioteca de funciones del programa, es decir, código compilado y datos que pueden ser utilizados por otros programas)

12.1.3Graalvm

GraalVM es el soporte subyacente para la tecnología AOT compatible con Spring 6. Spring también proporciona soporte de primera clase para imágenes nativas de GraalVM. GraalVM es un JDK de alto rendimiento diseñado para acelerar la ejecución de aplicaciones escritas en Java y otros lenguajes JVM, al tiempo que proporciona tiempos de ejecución para JavaScript, Python y muchos otros lenguajes populares. GraalVM proporciona dos formas de ejecutar aplicaciones Java: utilizando el compilador Graal justo a tiempo (JIT) en HotSpot JVM o como un ejecutable nativo compilado con anticipación (AOT). Las capacidades multilingües de GraalVM hacen posible mezclar múltiples lenguajes de programación en una sola aplicación y al mismo tiempo eliminar el costo de las llamadas en idiomas extranjeros. GraalVM agrega un compilador de optimización avanzado justo a tiempo (JIT) escrito en Java a la máquina virtual HotSpot Java.

GraalVM tiene las siguientes características:

(1) Un compilador de optimización avanzado que genera código más rápido y eficiente que requiere menos recursos informáticos.

(2) La compilación de imágenes nativas de AOT compila las aplicaciones Java en binarios nativos por adelantado, se inicia inmediatamente y logra el máximo rendimiento sin precalentamiento.

(3) La programación Polyglot aprovecha las mejores funciones y bibliotecas de los lenguajes populares en una sola aplicación sin gastos adicionales

(4) Herramientas avanzadas para depurar, monitorear, analizar y optimizar el consumo de recursos en Java y múltiples lenguajes

En términos generales, los requisitos para la nube nativa no son altos. Puede continuar usando la versión 2.7.X y JDK8 en el corto plazo, pero Spring ha lanzado oficialmente la versión oficial de Spring 6.

12.1.4 Imagen nativa

Actualmente, en la industria, además de esta solución de realizar AOT en JVM, existe otra forma de implementar Java AOT, que es abandonar directamente JVM y compilar directamente el código en código de máquina a través de un compilador como C. /C++ y luego ejecútelo. Esta es sin duda una idea que subvierte directamente el diseño del lenguaje Java, es decir, GraalVM Native Image. Implementa un componente de tiempo de ejecución ultraminiatura a través del lenguaje C: Substrate VM, que básicamente implementa varias características de JVM, pero es lo suficientemente liviano y se puede integrar fácilmente, lo que permite que el lenguaje y la ingeniería de Java eliminen las limitaciones de JVM. Realmente puede realizar la misma compilación AOT que C/C++. Después de un largo período de optimización y acumulación, esta solución ha logrado muy buenos resultados y básicamente se ha convertido en la primera solución Java AOT recomendada oficialmente por Oracle.
Native Image es una tecnología innovadora que compila código Java en un archivo ejecutable nativo independiente o en una biblioteca nativa compartida . El código de bytes de Java procesado durante la creación de un ejecutable nativo incluye todas las clases de aplicación, dependencias, bibliotecas dependientes de terceros y cualquier clase JDK requerida. El ejecutable nativo autónomo resultante es específico para cada sistema operativo individual y arquitectura de máquina que no requiere una JVM.

12.2 Proceso de construcción de imágenes nativas

12.2.1Instalación de GraalVM

Paso 1: descargue GraalVM

Ingrese al sitio web oficial para descargar: https://www.graalvm.org/downloads/

imagen-20221207153944132

imagen-20221207152841304

Paso 2: configurar las variables de entorno

Agregar GRAALVM_HOME

imagen-20221207110539954

Cambie JAVA_HOME a la ubicación de graalvm

imagen-20221207153724340

Cambie la ruta a la ubicación del contenedor de graalvm

imagen-20221207153755732

Utilice el comando para comprobar si la instalación se realizó correctamente

imagen-20221207153642253

Paso 3: instale el complemento de imagen nativa

Utilice el comando gu install Native-image para descargar e instalar

imagen-20221207155009832

12.2.2 Instalar el entorno de compilación de C++

Paso 1: descargue el software de instalación de Visual Studio

https://visualstudio.microsoft.com/zh-hans/downloads/

imagen-20221219112426052

Paso 2: instale Visual Studio

imagen-20221207155726572

imagen-20221207155756512

Paso 3: agregar variables de entorno de Visual Studio

Configurar INCLUDE, LIB y Ruta

imagen-20221207110947997

imagen-20221207111012582

imagen-20221207111105569

Paso 4: abra la herramienta y opere en la herramienta

imagen-20221207111206279

12.2.3 Escribir código y crear una imagen nativa

Paso 1: escribir código Java

public class Hello {
    
    

    public static void main(String[] args) {
    
    
        System.out.println("hello world");
    }
}

Paso 2: copie el archivo al directorio y realice la compilación

imagen-20221207111420056

Paso 3: crear una imagen nativa

imagen-20221207111509837

imagen-20221207111609878

Paso 4: ver los archivos creados

imagen-20221207111644950

Paso 5: ejecutar el archivo creado

imagen-20221207111731150

Puede ver que el tamaño del archivo binario finalmente empaquetado por Hello es 11 M. Este es el tamaño después de incluir varias bibliotecas de SVM y JDK. Aunque es más grande que el archivo binario de C/C++, sigue siendo más pequeño que el archivo completo. JVM Se puede decir que ya es muy pequeño.

En comparación con la ejecución con JVM, Native Image es mucho más rápido y tiene un menor uso de CPU. También se puede ver en varios datos experimentales oficiales que Native Image mejora en gran medida la velocidad de inicio y el uso de memoria. Obviamente:

imagen-20221207111947283

imagen-20221207112009852

gasolinera conocimiento

1.La diferencia entre las clases de implementación ResourceLoader y Resource

ResourceLoaderResourceLas principales diferencias con la clase de implementación de la interfaz son las siguientes :

  1. ResourceLoaderLa clase de implementación se utiliza principalmente para cargar recursos y proporciona métodos para cargar recursos, como ClassPathResourceLoadercargar recursos en la ruta de clases, UrlResourceLoadercargar recursos URL, FileSystemResourceLoadercargar recursos en el sistema de archivos, etc.
  2. ResourceLa clase de implementación se utiliza principalmente para acceder y operar recursos, y proporciona métodos de operación específicos para los recursos, como ClassPathResourceacceder a recursos en la ruta de clases, UrlResourceacceder a recursos URL, FileSystemResourceacceder a recursos en el sistema de archivos, etc.
  3. ResourceLoaderLa clase de implementación generalmente se usa internamente en el marco Spring para proporcionar funciones de carga de recursos y no se usa directamente en la aplicación.
  4. ResourceLa clase de implementación se puede utilizar en la aplicación , a través de la cual se puede obtener, leer y operar la información y el contenido del recurso.

En general, ResourceLoaderla clase de implementación de es la principal responsable de cargar recursos, y Resourcela clase de implementación de es la principal responsable de acceder y operar los recursos. Desempeñan diferentes funciones en el marco, pero todos se utilizan para procesar y administrar recursos en la aplicación.

imagen-20230526220018997

ilustrar:

La interfaz de recursos es una abstracción para acceder a los recursos en Spring. La interfaz de recursos en sí solo proporciona regulaciones. Hay muchas clases de implementación a continuación. Todos ellos son descriptores de recursos abstraídos de los recursos subyacentes del sistema real. En términos generales, los recursos se describen en Spring como direcciones de recursos en formato URL y estilo Ant con caracteres comodín.

imagen-20230526220042075

ilustrar:

La interfazResourceLoader , como sugiere el nombre, está diseñada para devolver (es decir, cargar) rápidamente el objeto de la instancia de recurso.

Documento de referencia detallado: Análisis de código fuente (IoC) de Spring Framework: relación entre recursos, cargador de recursos y contenedor - Comunidad de desarrolladores de Tencent Cloud - Tencent Cloud (tencent.com)

Supongo que te gusta

Origin blog.csdn.net/D_boj/article/details/132286524
Recomendado
Clasificación