[Crazy God habla sobre Java] Notas detalladas de Spring5 (completas)

Directorio de artículos

1. Entender la primavera

1.1 Introducción

historia:

  • Spring: Spring——> trae la primavera a la industria del software
  • En 2002, se lanzó por primera vez el prototipo del marco Spring: ¡el marco de interfaz!
  • El marco Spring se basa en el marco interface21. Después de un rediseño y enriquecimiento continuo de sus connotaciones, la versión oficial 1.0 se lanzó el 24 de marzo de 2004.
  • Rod Johnson, fundador de Spring Framework y autor famoso. Es difícil imaginar que las calificaciones académicas de Rod Johnson realmente sorprendan a mucha gente: tiene un doctorado de la Universidad de Sydney, pero su especialidad no es informática, sino musicología.

introducir:

  • Concepto de primavera: para resolver la complejidad del desarrollo de software y hacer que las tecnologías existentes sean más fáciles de usar, es una mezcolanza en sí misma.
  • SSH: Estructura2 + Primavera + Hibernación
  • SSM: SpringMVC + Primavera + Mybatis

Dirección de descarga de recursos:

Dependencias que los proyectos Maven necesitan importar:

  • primavera-webmvc
  • primavera-jdbc

1.2 Ventajas

  • ¡Spring es un marco (contenedor) de código abierto y gratuito!
  • ¡Spring es un marco liviano y no intrusivo! (No invasivo: puedes importarlo a cualquier proyecto a tu antojo)
  • ¡Inversión de control (IOC), programación orientada a aspectos (AOP)! (entrevista)
  • ¡Admite el procesamiento de transacciones y la integración del marco!

Para resumir : ¡Spring es un marco liviano de inversión de control (IOC) y programación orientada a aspectos (AOP)!

1.3 Composición (módulo principal de Spring7)

imagen.png

1.4 Expansión

Introducción al sitio web oficial: desarrollo moderno de Java, es decir, desarrollo basado en Spring
imagen.png
SpringBoot:

  • Un andamio para un rápido desarrollo
  • El acuerdo es mayor que la configuración
  • Se puede desarrollar rápidamente un único microservicio basado en SpringBoot

Nube de primavera:

  • SpringCloud se implementa en base a SpringBoot

¡Pero para aprender bien SpringBoot, Spring y SpringMVC son requisitos previos! ¡SpringBoot conecta el pasado y el futuro!
Desventajas: lleva demasiado tiempo desarrollarlo, va en contra del concepto original y la configuración es muy engorrosa.

2. Derivación teórica del COI

La inversión de control (IOC) es en realidad una idea de diseño; ¡y hay muchas maneras de implementar esta idea!

2.1 Manera original

  • Interfaz de capa Dao
  • Clase de implementación de interfaz de capa Dao
  • Interfaz de capa de servicio (capa empresarial)
  • Clase de implementación de interfaz de capa de servicio (capa empresarial)
  • Ejecutar pruebas

Resumen: si se sigue el modelo original, una vez que el usuario necesita cambios, los programadores deberán crear nuevos objetos de instancia en la clase de implementación de la capa empresarial; si el volumen de código es grande, será muy problemático y costoso.

<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.3.18</version>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-jdbc</artifactId>
  <version>5.2.0.RELEASE</version>
</dependency>
package com.my.dao;

public interface UserDao {
    
    
    void getUser();
package com.my.dao;
 
 public class UserDaoImpl implements UserDao{
    
    
 
     //重写接口中的方法!
     /*
     * 重写:方法名、参数类型、参数个数之类的都要相同
     * 重载:只要求方法名相同,参数类型和参数个数等可以不同
     * */
     public void getUser() {
    
    
         System.out.println("默认获取用户数据!");
     }
 }
package com.my.service;

public interface UserService {
    
    
    //在该接口中也定义了一个和Dao层一样的方法,用来使我们明白这是一种业务的实现过程
    void getUser();
}
package com.my.service;
import com.my.dao.UserDao;
import com.my.dao.UserDaoImpl;
import com.my.dao.UserDaoMysqlImpl;
import com.my.dao.UserDaoOracleImpl;

public class UserServiceImpl implements UserService{
    
    
    //    private UserDao userDao = new UserDaoImpl();
    //    private UserDao userDao = new UserDaoMysqlImpl();
    private UserDao userDao = new UserDaoOracleImpl();
    public void getUser(){
    
    
        userDao.getUser();
    }
}
import com.my.dao.UserDaoOracleImpl;
import com.my.service.UserService;
import com.my.service.UserServiceImpl;

public class MyTest {
    
    

    public static void main(String[] args) {
    
    
        //用户实际上调用的是业务层,dao层用户不需要接触
        UserService userService = new UserServiceImpl();
        userService.getUser();
    }
}
//    private UserDao userDao = new UserDaoImpl();
//    private UserDao userDao = new UserDaoMysqlImpl();
//    private UserDao userDao = new UserDaoOracleImpl();

2.2 Cambio

Construimos un método establecido en la capa empresarial y se produjo un cambio revolucionario:
código de prueba:

public class UserServiceImpl implements UserService {
    
    
   private UserDao userDao;
   // 利用set实现
   public void setUserDao(UserDao userDao) {
    
    
       this.userDao = userDao;
   }

   @Override
   public void getUser() {
    
    
       userDao.getUser();
   }
}


测试
@Test
public void test(){
    
    
   UserServiceImpl service = new UserServiceImpl(); 
   service.setUserDao( new UserDaoMySqlImpl() ); 
   service.getUser();
   //那我们现在又想用Oracle去实现呢
   service.setUserDao( new UserDaoOracleImpl() ); service.getUser();
}

Resumir:

  • Resulta que el programa es un objeto creado activamente por la capa empresarial y el control está en manos del programador.
  • Después de utilizar la inyección de conjuntos, el programa de la capa empresarial ya no toma la iniciativa, sino que se convierte en un objeto receptor pasivo y puede pasar un objeto directamente a la capa empresarial sin necesidad de nuevos.
  • Esta idea esencialmente resuelve el problema: los programadores ya no controlan la creación de objetos.
  • El acoplamiento del sistema (las dependencias entre módulos) se reduce considerablemente.

¡Este es el prototipo de Inversión de Control (IOC)!
imagen.png

2.3 La esencia del COI

2.4 Explicación de la inversión de control (IOC)

  • Inversión de Control IoC (Inversión de Control) es una idea de diseño
  • DI (Inyección de dependencia) es una forma de implementar IoC. Algunas personas piensan que DI es solo otra forma de decir IoC (hay muchas formas de implementar esta idea de IOC).
  • En programas sin IoC utilizamos programación orientada a objetos. La creación de objetos y las dependencias entre objetos están completamente codificadas en el programa. La creación de objetos está controlada por el propio programa. Después de la inversión del control, la creación de objetos se transfiere a un tercero.
  • Personalmente, creo que la llamada inversión de control significa: se invierte la forma de obtener objetos dependientes.
  • Al configurar beans en XML, la información de definición del bean se separa de la implementación, pero se pueden usar métodos de anotación para integrar los dos. La información de definición del bean se define directamente en la clase de implementación en forma de anotaciones, por lo tanto lograr cero El propósito de la configuración

La inversión de control es una forma de producir u obtener objetos específicos a través de descripciones (XML o anotaciones) y a través de terceros. El contenedor de IoC que implementa la inversión de control en Spring es la inyección de dependencia (DI).

3、HolaPrimavera

3.1 Escribe el primer programa.

  1. pom.xml
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.1.10.RELEASE</version>
</dependency>

  1. clase de entidad
package org.example.pojo;

public class Hello {
    
    
    private String name;

    public String getName() {
    
    
        return name;
    }
    public void setName(String name) {
    
    
        this.name = name;
    }
    @Override
    public String toString() {
    
    
        return "Hello{" +
                "name='" + name + '\'' +
                '}';
    }
}
  1. Archivo de configuración (beans.xml bajo recurso)
<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd">

<!--    使用Spring来创建对象,每个对象都是bean

        类型 变量名 = new 类型();
        Hello hello = new Hello();

        id = 变量名
        class:new的对象
        property:相当于给对象中的属性设置一个值
-->
    <bean id="hello" class="org.example.pojo.Hello">
        <property name="name" value="Spring !"></property>
    </bean>

</beans>

  1. Ejecutar pruebas
import org.example.pojo.Hello;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {
    
    

    public static void main(String[] args) {
    
    

        //获取Spring的上下文对象(可以同时加载多个配置文件)
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");

        //我们的对象都在Spring中,我们要使用直接从里面取出来就行
        Hello hello = (Hello)context.getBean("hello");
        System.out.println(hello.toString());
    }
}


3.2 Pensamiento

  1. ¿Quién creó el objeto Hola?
    • Hola objeto es creado por la primavera.
  2. ¿Quién establece el nombre del atributo del objeto Hello? Este proceso se llama "inversión de control".
    • El nombre del atributo lo establece el contenedor de primavera.

Control : ¿Quién controla la creación de objetos? Resulta ser el programa en sí. Después de usar Spring, la creación de Spring se
invierte : el programa en sí no crea objetos activamente, sino que los recibe pasivamente.
Inyección de dependencia : usar el método set para inyectar
IOC : es una idea de programación que los cambios de programación activa a recepción pasiva
están bien. Ahora, no necesitamos hacer ningún cambio en el programa. Para implementar diferentes operaciones, solo necesitamos hacer modificaciones en el archivo de configuración xml. El llamado IOC puede ser hecho en una oración: ¡los objetos son creados y administrados por Spring.assembly!

3.3 Modificar el Caso 1

En el caso uno, agregamos un archivo de configuración de Spring beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans.xsd">

  <bean id="MysqlImpl" class="com.kuang.dao.impl.UserDaoMySqlImpl"/>
  <bean id="OracleImpl" class="com.kuang.dao.impl.UserDaoOracleImpl"/>

  <bean id="ServiceImpl" class="com.kuang.service.impl.UserServiceImpl">
    <!--注意: 这里的name并不是属性 , 而是set方法后面的那部分 , 首字母小写-->
    <!--引用另外一个bean , 不是用value 而是用 ref-->
    <property name="userDao" ref="OracleImpl"/>
  </bean>

</beans>

¡prueba!

@Test
public void test2() {
    
    
    ApplicationContext context = new ClassPathXmlApplicationContext( "beans.xml" );
    UserServiceImpl serviceImpl = (UserServiceImpl) context.getBean( "ServiceImpl" );
    serviceImpl.getUser();

}

Bien, ahora no necesitamos hacer ningún cambio en el programa, para implementar diferentes operaciones, solo necesitamos hacer modificaciones en el archivo de configuración xml, el llamado IoC se puede hacer en una oración: se crean objetos , administrado y ensamblado por Spring
!

4. Cómo el COI crea objetos

4.1 Crear mediante un constructor sin argumentos

  1. Usuario.java
public class User {
    
    
    private String name;
    
    public User() {
    
    
        System.out.println("user无参构造方法");
    }
    public void setName(String name) {
    
     
        this.name = name;
    }

    public void show(){
    
     
        System.out.println("name="+ name );
    }
}
  1. frijoles.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans.xsd">

  <bean id="user" class="com.kuang.pojo.User">
    <property name="name" value="kuangshen"/>
  </bean>

</beans>
  1. clase de prueba
@Test
public void test() {
    
    
    ApplicationContext context = new ClassPathXmlApplicationContext( "beans.xml" );
    //在执行getBean的时候, user已经创建好了 , 通过无参构造
    User user = (User) context.getBean( "user" );
    //调用对象的方法 .
    user.show();

Como resultado, se puede encontrar que antes de llamar al método show, el objeto Usuario se ha inicializado mediante una construcción sin parámetros.

4.2 Crear mediante constructor parametrizado

  1. UsuarioT. Java
public class UserT {
    
    

    private String name;


    public UserT(String name) {
    
     
        this.name = name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    public void show(){
    
    
        System.out.println("name="+ name );
    }
}
  1. beans.xml se puede escribir de tres maneras
<!-- 第一种根据index参数下标设置 -->
<bean id="userT" class="com.kuang.pojo.UserT">
  <!-- index指构造方法 , 下标从0开始 -->
  <constructor-arg index="0" value="kuangshen2"/>
</bean>
<!-- 第二种根据参数名字设置 -->
<bean id="userT" class="com.kuang.pojo.UserT">
  <!-- name指参数名 -->
  <constructor-arg name="name" value="kuangshen2"/>
</bean>
<!-- 第三种根据参数类型设置 -->
<bean id="userT" class="com.kuang.pojo.UserT">
  <constructor-arg type="java.lang.String" value="kuangshen3"/>
</bean>
  1. prueba
@Test
public void testT() {
    
    
    ApplicationContext context = new ClassPathXmlApplicationContext( "beans.xml" );
    UserT user = (UserT) context.getBean( "userT" );
    user.show();
}

Conclusión: cuando se carga el archivo de configuración. ¡Todos los objetos administrados han sido inicializados!

5. Configuración de resorte

5.1 Alias

alias establece un alias, establece un alias para un bean y puede establecer múltiples alias

<!--设置别名:在获取Bean的时候可以使用别名获取-->
<alias name="userT" alias="userNew"/>

5.2 Configuración del frijol

<!--bean就是java对象,由Spring创建和管理-->

<!--
id 是bean的标识符,要唯一,就是对象名,如果没有配置id,name就是默认标识符
如果配置id,又配置了name,那么name是别名
name可以设置多个别名,可以用逗号,分号,空格隔开
如果不配置id和name,可以根据applicationContext.getBean(.class)获取对象;

class是bean的全限定名=包名+类名
-->
<bean id="hello" name="hello2 h2,h3;h4" class="com.kuang.pojo.Hello">
  <property name="name" value="Spring"/>
</bean>

5.3. importar

La cooperación en equipo se logra mediante la importación.

<import resource="{path}/beans.xml"/>

<!-- 若不同的bean有相同的内容,导入以最后一个为主 -->

6. Inyección de dependencia (DI)

  • Inyección de dependencia (DI).
  • Dependencia: significa que la creación del objeto Bean depende del contenedor, los recursos dependientes del objeto Bean.
  • Inyección: se refiere a los recursos de los que depende el objeto Bean, que son configurados y ensamblados por el contenedor.

6.1 Inyección de constructor

En la Sección 4, ya hemos hablado de ello en detalle antes.

6.2 inyección establecida (énfasis)

El atributo que se requiere inyectar debe tener un método set. El nombre del método set es set + la primera letra del atributo está en mayúscula. Si el atributo es de tipo booleano y no hay un método set, es .Probar clase pojo:
Address.java

public class Address {
    
    

    private String address;

    public String getAddress() {
    
    
        return address;
    }

    public void setAddress(String address) {
    
    
        this.address = address;
    }
}

Estudiante.java

package org.example.pojo;

import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;


public class Student {
    
    

    private String name;
    private Address address;
    private String[] books;
    private List<String> hobbys;
    private Map<String,String> card;
    private Set<String> games;
    private String wife;
    private Properties info;

    public void setName(String name) {
    
    
        this.name = name;
    }

    public void setAddress(Address address) {
    
    
        this.address = address;
    }

    public void setBooks(String[] books) {
    
    
        this.books = books;
    }

    public void setHobbys(List<String> hobbys) {
    
    
        this.hobbys = hobbys;
    }

    public void setCard(Map<String, String> card) {
    
    
        this.card = card;
    }

    public void setGames(Set<String> games) {
    
    
        this.games = games;
    }

    public void setWife(String wife) {
    
    
        this.wife = wife;
    }

    public void setInfo(Properties info) {
    
    
        this.info = info;
    }

    public void show() {
    
    
        System.out.println( "name=" + name
                           + ",address=" + address.getAddress()
                           + ",books="
                          );
        for (String book : books) {
    
    
            System.out.print( "<<" + book + ">>\t" );
        }
        System.out.println( "\n爱好:" + hobbys );
        System.out.println( "card:" + card );
        System.out.println( "games:" + games );


        System.out.println( "wife:" + wife );


        System.out.println( "info:" + info );
    }
}

inyección normal

<bean id="student" class="org.example.pojo.Student">
    <property name="name" value="Martin"/>
</bean>

prueba:

@Test
public void test01() {
    
    
    ApplicationContext context = new ClassPathXmlApplicationContext( "applicationContext.xml" );
    Student student = (Student) context.getBean( "student" );
    System.out.println( student.getName() );
}
<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd">
    
    <bean id="addr" class="org.example.pojo.Address">
        <property name="address" value="重庆"/>
    </bean>
    
    <bean id="student" class="org.example.pojo.Student">
        <!--1.常量注入-->
        <property name="name" value="小明"/>
        <!--2.引用注入,bean注入-->
        <property name="address" ref="addr"/>
        <!--3.数组注入-->
        <property name="books">
            <array>
                <value>西游记</value>
                <value>红楼梦</value>
                <value>水浒传</value>
            </array>
        </property>
        <!--4.List注入-->
        <property name="hobbys">
            <list>
                <value>听歌</value>
                <value>敲代码</value>
                <value>看抖音</value>
            </list>
        </property>
        <!--5.Map注入-->
        <property name="card">
            <map>
                <entry key="身份证" value="123"/>
                <entry key="银行卡" value="456"/>
            </map>
        </property>
        <!--6.Set注入-->
        <property name="games">
            <set>
                <value>LOL</value>
                <value>CF</value>
            </set>
        </property>
        <!--7.Null注入-->
        <property name="wife">
            <null></null>
        </property>
        <!--8.Properties注入-->
        <property name="info">
            <props>
                <prop key="学号">789</prop>
                <prop key="性别"></prop>
            </props>
        </property>
    </bean>

</beans>

prueba:

public class MyTest {
    
    
    @Test
    public void test01() {
    
    
        ApplicationContext context = new ClassPathXmlApplicationContext( "beans.xml" );
        Student student = (Student) context.getBean( "student" );
        student.show();
    }
}

6.3 Implementación de inyección de extensión

User.java: [Nota: ¡aquí no hay ningún constructor parametrizado!

public class User {
    
    
    private String name;
    private int age;

    public void setName(String name) {
    
    
        this.name = name;
    }

    public void setAge(int age) {
    
    
        this.age = age;
    }

    @Override
    public String toString() {
    
    
        return "User{" +
            "name='" + name + '\'' +
            ", age=" + age +
            '}';
    }
}

1. Inyección de espacio de nombres P: es necesario restringir el archivo en el archivo de encabezado

导入约束 : xmlns:p="http://www.springframework.org/schema/p"


<!-- P(属性: properties)命名空间 , 属性依然要设置set方法,p->para参数,直接设置类的属性 -->
<bean id="user" class="com.kuang.pojo.User" p:name="狂神" p:age="18"/>

2. c inyección de espacio de nombres: es necesario restringir el archivo en el archivo de encabezado

导入约束 : xmlns:c="http://www.springframework.org/schema/c"

<!--C(构造: Constructor)命名空间 , 属性依然要设置set方法,c->构造器-->
<bean id="user" class="com.kuang.pojo.User" c:name="狂神" c:age="18"/>

Encontré el problema: ¡es tan popular que no escribimos la estructura parametrizada en este momento!
Solución: agregue un constructor parametrizado. ¡También puede saber aquí que c es la llamada inyección de constructor!
Código de prueba:

@Test
public void test02() {
    
    
    ApplicationContext context = new ClassPathXmlApplicationContext( "applicationContext.xml" );
    User user = (User) context.getBean( "user" );
    System.out.println( user );
}

6.4 Alcance del frijol

En Spring, los objetos que constituyen el cuerpo principal de la aplicación y son administrados por el contenedor Spring IOC se denominan beans. En pocas palabras, un bean es un objeto inicializado, ensamblado y administrado por un contenedor IOC.
imagen.png
Entre los diversos alcances, los alcances de solicitud y sesión solo se usan en aplicaciones basadas en web (no tiene que preocuparse por qué marco de aplicación web está utilizando). están usando) Solo se puede usar en entornos Spring ApplicationContext basados ​​en web.

6.4.1 Producto único

**Modo Singleton:** Cuando el alcance de un bean es Singleton, solo habrá una instancia de bean compartida en el contenedor Spring IoC, y todas las solicitudes del bean, siempre que la identificación coincida con la definición del bean, solo devolverán la misma instancia del frijol. Singleton es un tipo singleton, lo que significa que un objeto bean se crea automáticamente cuando se crea el contenedor, ya sea que lo use o no, existe y el objeto obtenido cada vez es el mismo objeto. Tenga en cuenta que el alcance Singleton es el alcance predeterminado en Spring. Para definir un bean como singleton en XML, puede configurarlo así:

<bean id="ServiceImpl" class="cn.csdn.service.ServiceImpl" scope="singleton">

prueba:

@Test
public void test03() {
    
    
    ApplicationContext context = new
        ClassPathXmlApplicationContext( "applicationContext.xml" );
    User user = (User) context.getBean( "user" );
    User user2 = (User) context.getBean( "user" );
    System.out.println( user == user2 );//true
}

6.4.2 Prototipo

**Modo prototipo:** Cuando el alcance de un bean es Prototipo, significa que una definición de bean corresponde a múltiples instancias de objetos. Un bean con ámbito de prototipo hace que se cree una nueva instancia de bean cada vez que se solicita el bean (ya sea inyectándolo en otro bean o llamando al método getBean() del contenedor mediante programación). Prototipo es un tipo de prototipo. No se crea una instancia de él cuando creamos el contenedor, sino que se crea un objeto cuando obtenemos el bean, y el objeto que obtenemos no es el mismo objeto cada vez. Como regla general, el alcance del prototipo debe usarse para beans con estado y el alcance singleton debe usarse para beans sin estado. Defina beans como prototipos en XML y configúrelos así:

<bean id="account" class="com.foo.DefaultAccount" scope="prototype"/>
或者
<bean id="account" class="com.foo.DefaultAccount" singleton="false"/>

prueba:

@Test
public void test03() {
    
    
    ApplicationContext context = new
        ClassPathXmlApplicationContext( "applicationContext.xml" );
    User user = (User) context.getBean( "user" );
    User user2 = (User) context.getBean( "user" );
    System.out.println( user == user2 );//false
}

6.4.3 Solicitud

Cuando el alcance de un bean es Solicitud, significa que en una solicitud HTTP, una definición de bean corresponde a una instancia; es decir, cada solicitud HTTP tendrá su propia instancia de bean, que se crea en función de una determinada definición de bean. Este alcance solo es válido en el caso de Spring ApplicationContext basado en web. Considere la siguiente definición de frijol:

<bean id="loginAction" class=cn.csdn.LoginAction" scope="request"/>

Para cada solicitud HTTP, el contenedor Spring creará una nueva instancia del bean LoginAction basada en la definición del bean loginAction, y la instancia del bean loginAction solo es válida dentro de la solicitud HTTP actual, por lo que puede cambiar de forma segura el estado interno de la instancia creada. según sea necesario, y las instancias creadas a partir de la definición del bean loginAction en otras solicitudes no verán estos cambios de estado específicos de la solicitud. Cuando finaliza el procesamiento de la solicitud, la instancia de bean en el alcance de la solicitud se destruirá.

6.4.4 Sesión

Cuando el alcance de un bean es Sesión, significa que en una sesión HTTP, una definición de bean corresponde a una instancia. Este alcance solo es válido en el caso de Spring ApplicationContext basado en web. Considere la siguiente definición de frijol:

<bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/>

Para una determinada sesión HTTP, el contenedor Spring creará una nueva instancia de bean userPreferences basada en la definición del bean userPreferences, y el bean userPreferences solo es válido dentro de la sesión HTTP actual. Al igual que el alcance de la solicitud, puede cambiar de forma segura el estado interno de la instancia creada según sea necesario. Las instancias creadas según las preferencias del usuario en otras sesiones HTTP no verán estos cambios de estado específicos de una determinada sesión HTTP. Cuando finalmente se descarte la sesión HTTP, los beans dentro del alcance de la sesión HTTP también se descartarán.

7. Montaje automático de frijoles.

  • El cableado automático es una forma de utilizar Spring para satisfacer las dependencias de los beans.
  • Spring buscará los beans de los que depende un bean en el contexto de la aplicación.

Existen tres mecanismos de ensamblaje de beans en Spring, que son:

  1. Configurado explícitamente en xml;
  2. Configuración explícita en java;
  3. Mecanismo implícito de descubrimiento de beans y cableado automático. 【importante】

Aquí hablamos principalmente del tercer tipo: beans de ensamblaje automatizados.
El ensamblaje automático de Spring debe implementarse desde dos perspectivas o dos operaciones:

  1. Escaneo de componentes: Spring descubrirá automáticamente los beans creados en el contexto de la aplicación;
  2. Cableado automático: Spring cumple automáticamente con las dependencias entre beans, que es lo que llamamos IoC/DI;

La combinación de escaneo de componentes y ensamblaje automático aporta un gran poder para reducir la configuración de visualización al mínimo.
Se recomienda no utilizar la configuración xml de cableado automático, sino utilizar anotaciones.

7.1 Construcción del entorno de prueba

  1. Crear un nuevo proyecto
  2. Crea dos nuevas clases de entidad. Cat Dog tiene un método llamado
package org.example.pojo;

public class Cat {
    
    
    public void shout() {
    
    
        System.out.println("miao~");
    }
}

package org.example.pojo;

public class Dog {
    
    
    public void shout() {
    
    
        System.out.println("wang~");
    }
}

  1. Crear una nueva clase de usuario Usuario
package org.example.pojo;

public class User {
    
    
    private Cat cat;
    private Dog dog;
    private String str;

    public Cat getCat() {
    
    
        return cat;
    }

    public void setCat(Cat cat) {
    
    
        this.cat = cat;
    }

    public Dog getDog() {
    
    
        return dog;
    }

    public void setDog(Dog dog) {
    
    
        this.dog = dog;
    }

    public String getStr() {
    
    
        return str;
    }

    public void setStr(String str) {
    
    
        this.str = str;
    }

    @Override
    public String toString() {
    
    
        return "User{" +
                "cat=" + cat +
                ", dog=" + dog +
                ", str='" + str + '\'' +
                '}';
    }
}
  
  1. Escribir archivo de configuración de Spring
<?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="dog" class="org.example.pojo.Dog"/>
    <bean id="cat" class="org.example.pojo.Cat"/>
    
    <bean id="user" class="org.example.pojo.User">
        <property name="cat" ref="cat"/>
        <property name="dog" ref="dog"/>
        <property name="str" value="Martin"/>
    </bean>
</beans>

  1. prueba
import org.example.pojo.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {
    
    

    @Test
    public void test1(){
    
    
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        User user = context.getBean("user", User.class);
        user.getDog().shout();
        user.getCat().shout();
    }

}

El resultado se genera normalmente y el entorno es correcto.

7.2 、por nombre

autowire byName (autowire por nombre)

Durante la configuración manual de xml, a menudo ocurren errores como letras faltantes y mayúsculas que no se pueden verificar, lo que reduce la eficiencia del desarrollo.
El uso del cableado automático evitará estos errores y simplificará la configuración. prueba:

  1. Modifique la configuración del bean y agregue un atributo autowire="byName"
<bean id="user" class="org.example.pojo.User" autowire="byName">
  <property name="str" value="qinjiang"/>
</bean>
  1. ¡Probado nuevamente y el resultado aún se obtuvo exitosamente!
  2. Cambiamos el bean id de cat a catXXX
  3. Probado nuevamente, se produjo un puntero nulo java.lang.NullPointerException durante la ejecución. Debido a que de acuerdo con la regla byName no se puede encontrar el método set correspondiente, el setCat real no se ejecuta y el objeto no se inicializa, por lo que se informará un error de puntero nulo al llamar.
resumen:

Cuando un nodo bean tiene el atributo autowire byName.

  1. Buscará todos los nombres de métodos establecidos en su clase, como setCat, y obtendrá una cadena con el conjunto eliminado y la primera letra en minúscula, es decir, cat.
  2. Vaya al contenedor de primavera para buscar si hay un objeto con esta identificación de nombre de cadena.
  3. Si lo hay, retire la inyección; si no, informe una excepción de puntero nulo.

7.3 、 por tipo

autowire byType (cableado automático por tipo)

Cuando utilice autowire byType, primero debe asegurarse de que los objetos del mismo tipo sean únicos en el contenedor de resorte. Si no es único, se informará una excepción no única.

NoUniqueBeanDefinitionException

prueba:

  1. Modificar la configuración del bean del usuario: autowire = “byType”
  2. Prueba, salida normal
  3. ¡Registrando un objeto gato frijol!
<bean id="dog" class="org.example.pojo.Dog"/>
<bean id="cat" class="org.example.pojo.Cat"/>
<bean id="cat2" class="org.example.pojo.Cat"/>

<bean id="user" class="org.example.pojo.User" autowire="byType">
  <property name="str" value="qinjiang"/>
</bean>
  1. Prueba, error: NoUniqueBeanDefinitionException
  2. ¡Elimine cat2 y cambie el nombre del frijol cat! ¡prueba! Debido a que está ensamblado por tipo, no se informará ninguna excepción y el resultado final no se verá afectado. Incluso eliminar el atributo id no afecta el resultado.

¡Este es un ensamblaje automático por tipo!

7.4 Configuración automática mediante anotaciones

jdk1.5 comenzó a admitir anotaciones y spring 2.5 comenzó a admitir anotaciones por completo. Preparación: utilice anotaciones para inyectar propiedades.

  1. Introducir el encabezado del archivo de contexto en el archivo de configuración de Spring
xmlns:context="http://www.springframework.org/schema/context"

http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
  1. Agregar soporte para anotaciones
<context:annotation-config/>

7.4.1 、@Autowired

  • @Autowired se asigna automáticamente por tipo y no admite la coincidencia de ID.
  • ¡Necesita importar el paquete spring-aop!
<?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:aop="http://www.springframework.org/schema/aop"
       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/aop
       http://www.springframework.org/schema/context/spring-aop.xsd">

</beans>

prueba:

  1. Elimine el método set en la clase Usuario y use la anotación @Autowired
public class User {
    
    
    @Autowired
    private Cat cat;
    @Autowired
    private Dog dog;
    private String str;

    public Cat getCat() {
    
    
        return cat;
    }

    public Dog getDog() {
    
    
        return dog;
    }

    public String getStr() {
    
    
        return str;
    }
}
  1. El contenido del archivo de configuración en este momento.
<context:annotation-config/>

<bean id="dog" class="org.example.pojo.Dog"/>
<bean id="cat" class="org.example.pojo.Cat"/>
<bean id="user" class="org.example.pojo.User"/>
  1. Pruebe, ¡el resultado se genera con éxito!

[Tiempo de divulgación científica]
@Autowired (required = false) Descripción: falso, el objeto puede ser nulo; verdadero, el objeto debe almacenar el objeto y no puede ser nulo.

//如果允许对象为null,设置required = false, 默认为true
@Autowired(required = false)
    private Cat cat;

7.4.2 、@Calificador

@Autowired se ensambla automáticamente según el tipo, y @Qualifier se puede ensamblar automáticamente según byName. @Qualifier no se puede usar solo.
Pasos experimentales de prueba:

  1. Modifique el contenido del archivo de configuración para asegurarse de que el tipo exista. ¡Y el nombre no es el nombre predeterminado de la clase!
<bean	id="dog1"	class="com.kuang.pojo.Dog"/>
<bean	id="dog2"	class="com.kuang.pojo.Dog"/>
<bean	id="cat1"	class="com.kuang.pojo.Cat"/>
<bean	id="cat2"	class="com.kuang.pojo.Cat"/>
  1. No hay prueba de calificador. Hay múltiples objetos. No sé qué objeto es y se informa un error directamente.
  2. Agregar anotación de calificador en el atributo
@Autowired
@Qualifier(value = "cat2")
private Cat cat;
@Autowired
@Qualifier(value = "dog2")
private Dog dog;
  1. Prueba, salida exitosa!

7.4.3 、@Recurso

  • Si @Resource tiene un atributo de nombre especificado, primero busque el ensamblado por Nombre de acuerdo con este atributo;
  • Luego proceda al método byName predeterminado para el ensamblaje;
  • Si nada de lo anterior tiene éxito, se ensamblará automáticamente según byType.
  • Si ninguno de los dos tiene éxito, se informará una excepción.

Clase de entidad:

public class User {
    
    
    //如果允许对象为null,设置required = false,默认为true 
    @Resource(name = "cat2")
    private Cat cat; 
    @Resource 
    private Dog dog;
    private String str;
}

frijoles.xml

<bean	id="dog" class="com.kuang.pojo.Dog"/>
<bean	id="cat1" class="com.kuang.pojo.Cat"/>
<bean	id="cat2" class="com.kuang.pojo.Cat"/>

<bean	id="user" class="com.kuang.pojo.User"/>

Prueba: resultado correcto

<bean id="dog" class="com.kuang.pojo.Dog"/>
<bean id="cat1" class="com.kuang.pojo.Cat"/>

Archivo de configuración 2: beans.xml, eliminar cat2

@Resource
private Cat cat;
@Resource
private Dog dog;

Sólo se retienen las anotaciones en la clase de entidad.
Resultado: OK
Conclusión: La primera búsqueda por Nombre falla; luego la búsqueda por Tipo tiene éxito.

7.5 Resumen

Similitudes y diferencias entre @Autowired y @Resource:

  1. Tanto @Autowired como @Resource se pueden utilizar para ensamblar beans. Se puede escribir en el campo o en el método setter.
  2. @Autowired se ensambla por tipo de forma predeterminada (pertenece a la especificación de resorte). De forma predeterminada, los objetos dependientes deben existir. Si desea permitir valores nulos, puede establecer su atributo requerido en falso, como por ejemplo: @Autowired(required=false ), si queremos que el ensamblaje de nombre se pueda usar junto con la anotación @Qualifier
  3. @Resource (pertenece al retorno J2EE), está ensamblado por nombre de forma predeterminada y el nombre se puede especificar a través del atributo de nombre. Si no se especifica el atributo de nombre, cuando la anotación se escribe en el campo, el nombre del campo se usa de manera predeterminada para buscar por nombre. Si la anotación se escribe en el método de establecimiento, el nombre del atributo se usa de manera predeterminada para el ensamblaje. Conecte por tipo solo cuando no se encuentre ningún bean que coincida con el nombre. Sin embargo, cabe señalar que si se especifica el atributo de nombre, solo se ensamblará según el nombre.

Tienen la misma función y usan anotaciones para inyectar objetos, pero el orden de ejecución es diferente. @Autowired primero por Tipo, @Resource primero
por Nombre.

8. Desarrollar usando anotaciones.

8.1 Descripción

Después de la primavera 4, si desea utilizar el formulario de anotación, debe introducir el paquete aop y
imagen.png
también debe introducir una restricción de contexto 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"
  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">

  <

</beans>

8.2 Implementación de beans

Solíamos usar etiquetas de beans para la inyección de beans, pero en el desarrollo real, generalmente usamos anotaciones.

  1. Configurar anotaciones bajo qué paquetes escanear
<!--指定注解扫描包,这个包下的注解会生效-->
<context:component-scan base-package="org.example.pojo"/>
  1. Escriba una clase en el paquete especificado y agregue anotaciones
@Component("user")
// 相当于配置文件中 <bean id="user" class="当前注解的类"/> 
public class User {
    
    
    public String name = "秦疆";
}
  1. prueba
public class MyTest {
    
    
    @Test
    public void test(){
    
    
        ApplicationContext applicationContext =new ClassPathXmlApplicationContext("beans.xml");
        User user = (User)applicationContext.getBean("user");
        System.out.println(user.name);
    }
}

8.3 Inyección de atributos

Inyectar propiedades usando anotaciones

  1. Puede agregar @value ("valor") directamente al nombre directo sin proporcionar el método set.
@Component("user")
// 相当于配置文件中 <bean id="user" class="当前注解的类"/> 
public class User {
    
    
    @Value("秦疆")
    // 相当于配置文件中 <property name="name" value="秦疆"/>
    public String name;
}
  1. Si se proporciona un método establecido, agregue @value("valor") al método establecido;
@Component("user")
public class User {
    
    

    public String name;

    @Value("秦疆")
    public void setName(String name) {
    
    
        this.name = name;
    }
}

8.4 Anotaciones derivadas

¡Nuestras anotaciones simplemente reemplazan los pasos de configuración en el archivo de configuración! ¡Más conveniente y más rápido!

@Component tres anotaciones derivadas

Para lograr mejores capas, Spring puede usar las otras tres anotaciones, que tienen las mismas funciones, cualquiera que sea la función que se use actualmente es la misma.

  • @Controller: capa web
  • @Service: capa de servicio
  • @Repositorio: capa dao

¡Escribir estas anotaciones equivale a entregar esta clase a Spring para su administración y ensamblaje!

8.5 Anotaciones automáticas de montaje

Ya hemos hablado del montaje automático de frijoles, ¡puedes revisarlo!

@Autowired
@Nullable
@Resource

8.6 Alcance

@alcance

  • singleton: de forma predeterminada, Spring creará este objeto en modo singleton. Cuando la fábrica esté cerrada, todos los objetos serán destruidos.
  • prototipo: modo de instancia múltiple. Cuando la fábrica esté cerrada, no se destruirán todos los objetos. El mecanismo interno de recolección de basura recolectará
@Controller("user") 
@Scope("prototype") 
public class User {
    
    
    @Value("秦疆")
    public String name;
}

8.7, Resumen

XML frente a anotaciones
  • XML se puede aplicar a cualquier escenario, tiene una estructura clara y es fácil de mantener.
  • Las anotaciones no se pueden utilizar en clases que no las proporcione usted mismo, lo que hace que el desarrollo sea simple y conveniente.
Desarrollo integrado de xml y anotaciones: mejores prácticas recomendadas
  • beans administrados xml
  • La anotación completa la inyección de atributos.
  • Durante el uso, no es necesario escanear. El escaneo es para anotaciones en las clases.
<context:annotation-config/>

efecto:

  • Registre el controlador de anotaciones para que las anotaciones sean efectivas.
  • Se utiliza para activar anotaciones en beans que se han registrado en el contenedor Spring, es decir, para registrarse explícitamente en Spring.
  • Si no escanea el paquete, debe configurar manualmente el bean
  • Si el controlador no está anotado, el valor inyectado será nulo.

8.8 Configuración basada en clases de Java

JavaConfig era originalmente un subproyecto de Spring, que proporciona información de definición de Bean a través de clases Java. En la versión Spring 4, JavaConfig se ha convertido oficialmente en la función central de Spring 4.
prueba:

  1. Escribe una clase de entidad, Perro
@Component //将这个类标注为Spring的一个组件,放到容器中! 
public class Dog {
    
    
    public String name = "dog";
}
  1. Cree un nuevo paquete de configuración y escriba una clase de configuración MyConfig
@Configuration //代表这是一个配置类
public class MyConfig {
    
    

    @Bean //通过方法注册一个bean,这里的返回值就Bean的类型,方法名就是bean的id!
    public Dog dog(){
    
    
        return new Dog();
    }
}
  1. prueba
@Test
public void test2(){
    
    
    ApplicationContext applicationContext =new AnnotationConfigApplicationContext(MyConfig.class); 
    Dog dog = (Dog) applicationContext.getBean("dog"); //方法名
    System.out.println(dog.name);
}
  1. ¡Obtenga el resultado con éxito!
¿Cómo importar otras configuraciones?
  1. ¡Escribamos otra clase de configuración!
@Configuration //代表这是一个配置类
public class MyConfig2 {
    
    
}
  1. En la clase de configuración anterior, elegimos importar esta clase de configuración.
@Configuration
@Import(MyConfig2.class)//导入合并其他配置类,类似于配置文件中的 inculde 标签
public class MyConfig {
    
    

    @Bean
    public Dog dog(){
    
    
        return new Dog();
    }

}

Con respecto a este método de configuración de clases Java, veremos mucho en SpringBoot y SpringCloud más adelante, ¡solo necesitamos conocer el papel de estas anotaciones!

9. Modo agente

¿Por qué debería aprender el modo proxy? ¡Porque el mecanismo subyacente de AOP es el proxy dinámico!
Modo agente:

  • proxy estático
  • proxy dinámico

Antes de aprender aop, primero debemos comprender el modo proxy.
imagen.png
imagen.png

9.1 Proxy estático

Análisis de rol de agente estático.
  • Rol abstracto: generalmente implementado mediante interfaces o clases abstractas (alquilar una casa)
  • Rol real: Rol actuado (propietario)
  • Rol de agente: actúa como agente del personaje real; después de actuar como agente del personaje real, normalmente realizarás algunas operaciones auxiliares (intermediario).
  • Cliente: utilice el rol de agente para realizar algunas operaciones.
Código

Rent.java es el rol abstracto

//抽象角色:租房
public interface Rent {
    
     
    public void rent();
}

Host.java es el papel real

//真实角色: 房东,房东要出租房子
public class Host implements Rent{
    
    
    public void rent() {
    
    
        System.out.println("我是房东,房屋出租");
    }
}

Proxy. Java es la función de proxy.

public class Proxy implements Rent{
    
    
    private Host host;

    public Proxy(){
    
     }

    public Proxy(Host host) {
    
    
        this.host = host;
    }

    @Override
    public void rent() {
    
    
        seeHouse();
        host.rent();
        fare();
    }

    //看房
    public void seeHouse(){
    
    
        System.out.println("中介带房客看房");
    }
    //收中介费
    public void fare(){
    
    
        System.out.println("中介收中介费");
    }
}

Cliente.java es el cliente

// 客户
public class Client {
    
    
    public static void main(String[] args) {
    
    
        //房东要租房
        Host host = new Host();

        //中介帮助房东
        Proxy proxy = new Proxy(host);

        // 你去找中介!
        proxy.rent();
    }
}

Análisis: En este proceso, usted está en contacto directo con el intermediario. El intermediario puede hacer cosas que el propietario no puede hacer. Al igual que en la vida real, no puede ver al propietario, pero aún así alquila la casa del propietario a través del agente. En el llamado modelo de agente, los programas provienen de la vida, por lo que las personas que aprenden a programar generalmente pueden ver lo que sucede en la vida de manera más abstracta.

9.2 Beneficios del proxy estático

  • Puede hacer que nuestro verdadero papel sea más puro y dejar de prestar atención a algunas cosas públicas.
  • Los asuntos públicos los completan los agentes, se realiza la división del trabajo.
  • Los servicios públicos se vuelven más centralizados y convenientes a medida que se expanden.

defecto :

  • Un rol real crea un rol de agente, lo que aumenta la carga de trabajo y reduce la eficiencia del desarrollo.

Queremos los beneficios de los proxies estáticos sin las desventajas de los proxies estáticos, ¡por eso tenemos proxies dinámicos!

9.3 Recomprensión de los agentes estáticos

Una vez que los alumnos hayan terminado de practicar, ¡demos otro ejemplo para consolidar el aprendizaje de todos! Pasos de práctica:

  1. Cree un rol abstracto, como el negocio de usuario que hacemos habitualmente. En abstracción, significa agregar, eliminar, modificar y verificar.
//抽象角色:增删改查业务
public interface UserService {
    
     
    void add();
    void delete(); 
    void update(); 
    void query();
}
  1. Necesitamos un objeto real para completar estas operaciones de adición, eliminación, modificación y consulta.
//真实对象,完成增删改查操作的人
public class UserServiceImpl implements UserService {
    
    

    public void add() {
    
    
        System.out.println("增加了一个用户");
    }

    public void delete() {
    
    
        System.out.println("删除了一个用户");
    }

    public void update() {
    
    
        System.out.println("更新了一个用户");
    }

    public void query() {
    
    
        System.out.println("查询了一个用户");
    }
}
  1. Ha llegado la demanda, ahora necesitamos agregar una función de registro, ¡cómo implementarla!
    • Idea 1: agregar código a la clase de implementación [¡Problema!
    • Idea 2: Utilice un agente para hacerlo. Si puede implementar esta función sin cambiar la situación comercial original, ¡es lo mejor!
  2. ¡Configure una clase de proxy para manejar los registros! rol de agente
//代理角色,在这里面增加日志的实现
public class UserServiceProxy implements UserService {
    
    
    private UserServiceImpl userService;

    public void setUserService(UserServiceImpl userService) {
    
    
        this.userService = userService;
    }

    public void add() {
    
    
        log( "add" );
        userService.add();
    }

    public void delete() {
    
    
        log( "delete" );
        userService.delete();
    }

    public void update() {
    
    
        log( "update" );
        userService.update();
    }

    public void query() {
    
    
        log( "query" );
        userService.query();
    }

    public void log(String msg) {
    
    
        System.out.println( "执行了" + msg + "方法" );
    }
}
  1. Clase de acceso de prueba:
public class Client {
    
    
    public static void main(String[] args) {
    
    
        //真实业务
        UserServiceImpl userService = new UserServiceImpl();
        //代理类
        UserServiceProxy proxy = new UserServiceProxy();
        //使用代理类实现日志功能!
        proxy.setUserService(userService);

        proxy.add();
    }
}

Bien, ahora todos no deberían tener problemas con el modo proxy. El punto clave es que todos deben entender la idea;
hemos mejorado las funciones originales sin cambiar el código original. Esta es la idea central en AOP.
[Hablemos de AOP : desarrollo vertical, desarrollo horizontal]
imagen.png

9.4 Proxy dinámico

  • El papel de los proxies dinámicos es el mismo que el de los proxies estáticos.
  • La clase de proxy del proxy dinámico se genera dinámicamente y la clase de proxy del proxy estático la escribimos de antemano.
  • Los proxies dinámicos se dividen en dos categorías: uno son proxies dinámicos basados ​​en interfaz y el otro son proxies dinámicos basados ​​en clases.
    • Proxy dinámico basado en interfaz: proxy dinámico JDK
    • Proxy dinámico basado en clases – cglib
    • Hoy en día, la biblioteca de clases de código de bytes de Java, javasist, se utiliza con más frecuencia para generar agentes dinámicos.Baidu y javasist
    • Usamos el código nativo de JDK para implementarlo aquí, ¡y el resto de los principios son los mismos!

El proxy dinámico de JDK necesita comprender dos clases
: núcleo: controlador de llamadas InvocationHandler y agente proxy. Abra el documento de ayuda de JDK y eche un vistazo a
[InvocationHandler: controlador de llamadas]
imagen.png

Object invoke(Object proxy, 方法 method, Object[] args);
//参数
//proxy - 调用该方法的代理实例
//method -所述方法对应于调用代理实例上的接口方法的实例。 方法对象的声明类将是该方法声明的接口,它可以是代理类继承该方法的代理接口的超级接口。
//args -包含的方法调用传递代理实例的参数值的对象的阵列,或null如果接口方法没有参数。 原始类型的参数包含在适当的原始包装器类的实例中,例如java.lang.Integer或java.lang.Boolean

【Proxy: proxy】
imagen.png
imagen.png
imagen.png

//生成代理类
 public Object getProxy(){
     return Proxy.newProxyInstance(this.getClass().getClassLoader(),
     rent.getClass().getInterfaces(),this);
 }
Código

¡Los personajes abstractos y los personajes reales son los mismos que antes!
Rent.java es el rol abstracto

//抽象角色:租房
public interface Rent {
    
     
    public void rent();
}

Host.java es el papel real

//真实角色: 房东,房东要出租房子
public class Host implements Rent {
    
    
    public void rent() {
    
    
        System.out.println("我是房东,房屋出租");
    }
}

ProxyInvocationHandler.java es la función de proxy

// 用这个类,自动生产代理
public class ProxyInvocationHandler implements InvocationHandler {
    
    
    // 被代理的接口
    private Rent rent;

    public void setRent(Rent rent) {
    
    
        this.rent = rent;
    }
    //生成代理类,重点是第二个参数,获取要代理的抽象角色!之前都是一个角色,现在可以代理一类角色
    public Object getProxy(){
    
    
        return Proxy.newProxyInstance(this.getClass().getClassLoader(),
                rent.getClass().getInterfaces(),
                this);
    }

    // proxy : 代理类 method : 代理类的调用处理程序的方法对象.
    // 处理代理实例上的方法调用并返回结果
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
    
        seeHouse();
        //核心:本质利用反射实现!
        Object result = method.invoke(rent, args);
        fare();
        return result;
    }

    //看房
    public void seeHouse(){
    
    
        System.out.println("带房客看房");
    }
    //收中介费
    public void fare(){
    
    
        System.out.println("收中介费");
    }
}

Cliente . Java

//租客
public class Client {
    
    

    public static void main(String[] args) {
    
    
        //真实角色
        Host host = new Host();
        //代理实例的调用处理程序
        ProxyInvocationHandler pih = new ProxyInvocationHandler();
        pih.setRent(host); //将真实角色放置进去!
        Rent proxy = (Rent)pih.getProxy(); //动态生成对应的代理类!
        proxy.rent();
    }
}

Núcleo: un agente dinámico generalmente actúa como agente para un determinado tipo de negocio. Un agente dinámico puede actuar como agente para múltiples clases y actúa como agente para interfaces. ,

9.5 Profundizar la comprensión

¡Usemos un proxy dinámico para representar el servicio de usuario que escribimos más tarde!
¡También podemos escribir una clase de implementación de proxy dinámico general! ¡Simplemente configure todos los objetos proxy en Objeto!

public class ProxyInvocationHandler implements InvocationHandler {
    
    
    private Object target;

    public void setTarget(Object target) {
    
    
        this.target = target;
    }

    //生成代理类
    public Object getProxy(){
    
    
        return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
    }

    // proxy : 代理类
    // method : 代理类的调用处理程序的方法对象.
    public Object invoke(Object proxy, Method method, Object[] args) throws
    Throwable {
    
    
        log(method.getName());
        Object result = method.invoke(target, args);
        return result;
    }

    public void log(String methodName){
    
    
        System.out.println("执行了"+methodName+"方法");
    }

}

¡prueba!

public class Test {
    
    
    public static void main(String[] args) {
    
    
        //真实对象
        UserServiceImpl userService = new UserServiceImpl();
        //代理对象的调用处理程序
        ProxyInvocationHandler pih = new ProxyInvocationHandler(); pih.setTarget(userService); //设置要代理的对象
        UserService proxy = (UserService)pih.getProxy(); //动态生成代理类!
        proxy.delete();
    }
}

[Probar, agregar, eliminar, modificar, verificar, ver resultados]

9.6 Beneficios del proxy dinámico

Tiene todo lo que tienen los proxies estáticos y también tiene lo que los proxies estáticos no tienen.

  • Puede hacer que nuestro verdadero papel sea más puro y dejar de prestar atención a algunas cosas públicas.
  • Los asuntos públicos los completan los agentes, se realiza la división del trabajo.
  • Los servicios públicos se vuelven más centralizados y convenientes a medida que se expanden.
  • Un agente dinámico, que generalmente actúa como agente de un determinado tipo de negocio.
  • Un proxy dinámico puede representar varias clases, ¡y el proxy es la interfaz!

10、AOP

10.1 ¿Qué es AOP?

AOP (Programación orientada a aspectos) significa: programación orientada a aspectos, una tecnología que logra el mantenimiento unificado de las funciones del programa mediante precompilación y agentes dinámicos en tiempo de ejecución. AOP es la continuación de OOP, un punto caliente en el desarrollo de software, un contenido importante en el marco Spring y un paradigma derivado de la programación funcional. AOP se puede utilizar para aislar varias partes de la lógica empresarial, reduciendo así el acoplamiento entre las distintas partes de la lógica empresarial, mejorando la reutilización del programa y mejorando la eficiencia del desarrollo.
imagen.png

10.2 El papel de Aop en Spring

Proporciona transacciones declarativas; permite aspectos definidos por el usuario.

  • Preocupaciones transversales: métodos o funciones que abarcan múltiples módulos de una aplicación. Es decir, no tiene nada que ver con nuestra lógica empresarial, pero la parte a la que debemos prestar atención son las preocupaciones transversales. Como registro, seguridad, almacenamiento en caché, transacciones, etc.
  • Aspecto (ASPECTO): Un objeto especial que está modularizado a través de preocupaciones transversales. Es decir, es una clase.
  • Consejo: El trabajo que los aspectos deben completar. Es decir, es un método de la clase.
  • Destino: el objeto a notificar.
  • Proxy: un objeto creado después de aplicar notificaciones al objeto de destino.
  • Pointcut (PointCut): la definición del "lugar" donde se ejecuta la notificación de aspecto.
  • JoinPoint: el punto de ejecución que coincide con el punto de entrada.

imagen.png
En Spring AOP, la lógica transversal se define a través de consejos. Spring admite cinco tipos de consejos:
imagen.png
es decir, Aop puede agregar nuevas funciones sin cambiar el código original.

10.3 Implementación de Aop usando Spring

[Importante] Cuando utilice el tejido AOP, debe importar un paquete de dependencia.

<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
  <groupId>org.aspectj</groupId>
  <artifactId>aspectjweaver</artifactId>
  <version>1.9.4</version>
</dependency>

primera manera

Implementado a través de Spring API

Primero escriba nuestra interfaz empresarial y clase de implementación.

public interface UserService {
    
    

    public void add();


    public void delete();


    public void update();


    public void search();
}
public class UserServiceImpl implements UserService{
    
    

    @Override
    public void add() {
    
    
        System.out.println("增加用户"); 
    }

    @Override
    public void delete() {
    
    
        System.out.println("删除用户");
    }

    @Override
    public void update() {
    
    
        System.out.println("更新用户");
    }

    @Override
    public void search() {
    
    
        System.out.println("查询用户");
    }
}

Luego escriba nuestra clase de mejora, escribimos dos, una antes de la mejora y otra después de la mejora.

public class Log implements MethodBeforeAdvice {
    
    

    //method : 要执行的目标对象的方法
    //objects : 被调用的方法的参数
    //Object : 目标对象
    @Override
    public void before(Method method, Object[] objects, Object o) throws Throwable {
    
    
        System.out.println( o.getClass().getName() + "的" + method.getName() + "方法被执行了");
    }
}
public class AfterLog implements AfterReturningAdvice {
    
    
    //returnValue 返回值
    //method被调用的方法
    //args 被调用的方法的对象的参数
    //target 被调用的目标对象
    @Override
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
    
    
        System.out.println("执行了" + target.getClass().getName() +"的"+method.getName()+"方法," +"返回值:"+returnValue);
    }
}

Finalmente, regístrese en el archivo Spring e implemente un corte OP, prestando atención a las restricciones de importació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:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans.xsd
  http://www.springframework.org/schema/aop
  http://www.springframework.org/schema/aop/spring-aop.xsd">
    
    <!--注册bean-->
    <bean id="userService" class="org.example.service.UserServiceImpl"/>
    <bean id="log" class="org.example.log.Log"/>
    <bean id="afterLog" class="org.example.log.AfterLog"/>

    <!--使用原生的Spring API接口-->
    <!--aop的配置,需要导入aop的约束-->
    <aop:config>
        <!--切入点 expression:表达式匹配要执行的方法-->
        <aop:pointcut id="pointcut" expression="execution(* org.example.service.UserServiceImpl.*(..))"/>
        <!--执行环绕; advice-ref执行方法 . pointcut-ref切入点-->
        <aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
        <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
    </aop:config>

</beans>

prueba

public class MyTest {
    
    
    @Test
    public void test(){
    
    
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        // 注意点,代理的是接口
        UserService userService = (UserService) context.getBean("userService"); 
        userService.search();
    }
}

La importancia de Aop: Muy importante. Debe comprender las ideas, principalmente la comprensión de las ideas.
Spring's Aop combina negocios públicos (registro, seguridad, etc.) con negocios de dominio. Al ejecutar negocios de dominio, se agregarán servicios públicos a Realizar la reutilización de servicios públicos. El negocio de dominios es más puro y los programadores se centran en el negocio de dominios, pero su esencia sigue siendo una agencia dinámica.

Segunda forma

Clase personalizada para implementar Aop

La clase de negocio de destino permanece sin cambios y sigue siendo userServiceImpl.
El primer paso es escribir nuestra propia clase de nivel de entrada.

public class DiyPointcut {
    
    

    public void before(){
    
    
        System.out.println("---------方法执行前	");
    }
    public void after(){
    
    
        System.out.println("---------方法执行后	");
    }

}

Ir a la configuración de primavera

<!--第二种方式自定义实现-->
<!--注册bean-->
<bean id="diy" class="com.kuang.config.DiyPointcut"/>

<!--aop的配置-->
<aop:config>
  <!--第二种方式:使用AOP的标签实现-->
  <aop:aspect ref="diy">
    <aop:pointcut id="diyPonitcut" expression="execution(* com.kuang.service.UserServiceImpl.*(..))"/>
    <aop:before pointcut-ref="diyPonitcut" method="before"/>
    <aop:after pointcut-ref="diyPonitcut" method="after"/>
  </aop:aspect>
</aop:config>

prueba:

public class MyTest {
    
     
    @Test
    public void test(){
    
     
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); 
        UserService userService = (UserService) context.getBean("userService"); 
        userService.add();
    }
}

la tercera manera

Implementado mediante anotaciones.

Paso 1: escribir una clase mejorada con implementación de anotaciones

package com.kuang.config;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect
public class AnnotationPointcut {
    
    
    @Before("execution(* com.kuang.service.UserServiceImpl.*(..))")
    public void before(){
    
    
        System.out.println("---------方法执行前	");
    }

    @After("execution(* com.kuang.service.UserServiceImpl.*(..))")
    public void after(){
    
    
        System.out.println("---------方法执行后	");
    }

    @Around("execution(* com.kuang.service.UserServiceImpl.*(..))")
    public void around(ProceedingJoinPoint jp) throws Throwable {
    
    
        System.out.println("环绕前");
        System.out.println("签名:"+jp.getSignature());
        //执行目标方法proceed
        Object proceed = jp.proceed();
        System.out.println("环绕后");
        System.out.println(proceed);
    }
}

// 环绕前->执行方法前->执行方法->环绕后->执行方法后

Paso 2: en el archivo de configuración de Spring, registre el bean y agregue una configuración que admita anotaciones

<!--第三种方式:注解实现-->
<bean id="annotationPointcut" class="com.kuang.config.AnnotationPointcut"/>
<aop:aspectj-autoproxy/>

aop:aspectj-autoproxy: Descripción

通过aop命名空间的<aop:aspectj-autoproxy   />声明自动为spring容器中那些配置@aspectJ切面
的bean创建代理,织入切面。当然,spring 在内部依旧采用
AnnotationAwareAspectJAutoProxyCreator进行自动代理的创建工作,但具体实现的细节已经被
<aop:aspectj-autoproxy />隐藏起来了

<aop:aspectj-autoproxy />有一个proxy-target-class属性,默认为false,表示使用jdk动态
代理织入增强,当配为<aop:aspectj-autoproxy    poxy-target-class="true"/>时,表示使用
CGLib动态代理技术织入增强。不过即使proxy-target-class设置为false,如果目标类没有声明接
口,则spring将自动使用CGLib动态代理。

11. Integrar Mybatis

paso:

  1. Importar paquetes jar relacionados
  2. junit
<dependency>
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
  <version>4.13.2</version>
</dependency>
  1. mi zapato
<dependency>
  <groupId>org.mybatis</groupId>
  <artifactId>mybatis</artifactId>
  <version>3.5.6</version>
</dependency>
  1. conector-mysql-java
<dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
  <version>8.0.28</version>
</dependency>
  1. relacionado con la primavera
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.3.18</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.2.0.RELEASE</version>
</dependency>
  1. tejedor de aspecto J AOP
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
  <groupId>org.aspectj</groupId>
  <artifactId>aspectjweaver</artifactId>
  <version>1.9.4</version>
</dependency>
  1. Paquete de integración mybatis-spring [Puntos clave]
<dependency>
  <groupId>org.mybatis</groupId>
  <artifactId>mybatis-spring</artifactId>
  <version>2.0.2</version>
</dependency>
  1. lombok
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.10</version>
</dependency>
  1. ¡Problema de configuración de filtrado de recursos estáticos de Maven!
<build>
  <resources>
    <resource>
      <directory>src/main/java</directory>
      <includes>
        <include>**/*.properties</include>
        <include>**/*.xml</include>
      </includes>
      <filtering>true</filtering>
    </resource>
  </resources>
</build>
  1. Escribir archivo de configuración
  2. Código

RecuerdosMyBatis

Escribir clase de entidad pojo
package com.kuang.pojo;

@Data
public class User {
    
    
    private int id; //id
    private String name;//姓名
    private String pwd;//密码
}

Implementar el archivo de configuración de mybatis.

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--configuration core file-->
<configuration>
    <typeAliases>
        <package name="org.example.pojo"/>
    </typeAliases>
    
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
    

</configuration>
Escritura de la interfaz UserDao
public interface UserMapper {
    
     
    public List<User> selectUser();
}

Archivo de mapeo del mapeador correspondiente a la interfaz

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.example.mapper.UserMapper">
    
    <select id="selectUser" resultType="User">
        select * from user
    </select>

</mapper>

clase de prueba

public class MyTest {
    
    
    @Test
    public void selectUser() throws IOException {
    
    
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream( resource );
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build( inputStream );
        SqlSession sqlSession = sqlSessionFactory.openSession();

        UserMapper mapper = sqlSession.getMapper( UserMapper.class );

        List<User> userList = mapper.selectUser();
        for (User user : userList) {
    
    
            System.out.println(user);
        }

        sqlSession.close();
    }
}

MyBatis-aprendizaje de primavera

Antes de presentar Spring, es necesario comprender algunas clases importantes del paquete mybatis-spring;
http://www.mybatis.org/spring/zh/index.html
imagen.png

¿Qué es MyBatis-Spring?

MyBatis-Spring lo ayudará a integrar perfectamente el código MyBatis en Spring.

conocimiento básico

Antes de comenzar a utilizar MyBatis-Spring, debe estar familiarizado con los dos marcos Spring y MyBatis y su terminología. Es importante que
MyBatis-Spring requiera las siguientes versiones:

MyBatis-primavera MiBatis marco de primavera Lote de primavera Java
2.0 3.5+ 5.0+ 4.0+ Java 8+
1.3 3.4+ 3.2.2+ 2.1+ java 6+

Si usa Maven como herramienta de compilación, solo necesita agregar el siguiente código a pom.xml:

<dependency>
  <groupId>org.mybatis</groupId>
  <artifactId>mybatis-spring</artifactId>
  <version>2.0.2</version>
</dependency>

Para usar MyBatis con Spring, necesita definir al menos dos cosas en el contexto de la aplicación Spring: un SqlSessionFactory y al menos una clase de mapeador de datos.

  1. En MyBatis-Spring, SqlSessionFactoryBean se puede utilizar para crear SqlSessionFactory. Para configurar este bean de fábrica, simplemente coloque el siguiente código en

En el archivo de configuración XML de Spring:

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
  <property name="dataSource" ref="dataSource" />
</bean>

Nota: SqlSessionFactory requiere una fuente de datos. Puede ser cualquier fuente de datos, simplemente configúrelo como cualquier otra conexión de base de datos Spring.

  1. En el uso básico de MyBatis, SqlSessionFactory se crea a través de SqlSessionFactoryBuilder. En MyBatis-Spring, use

SqlSessionFactoryBean para crear.

  1. En MyBatis, puede usar SqlSessionFactory para crear SqlSession. Una vez que obtenga una sesión, puede usarla para ejecutar declaraciones asignadas, confirmar o deshacer la conexión y, finalmente, cuando ya no sea necesaria, puede cerrar la sesión. SqlSessionFactory tiene una única propiedad requerida: JDBC DataSource. Puede ser cualquier objeto DataSource y su método de configuración es el mismo que el de otras conexiones de bases de datos Spring.
  2. Un atributo comúnmente utilizado es configLocation, que se utiliza para especificar la ruta del archivo de configuración XML de MyBatis. Es muy útil cuando necesitas modificar la configuración básica de MyBatis. Normalmente, la configuración base se refiere al elemento o.

Cabe señalar que este archivo de configuración no necesita ser una configuración completa de MyBatis. Específicamente, se ignora cualquier configuración de entorno (), fuente de datos () y administrador de transacciones MyBatis () . SqlSessionFactoryBean creará su propia configuración del entorno MyBatis (Environment) y establecerá los valores del entorno personalizado según sea necesario.

  1. SqlsessionTemplate es el núcleo de MyBatis-Spring. Como implementación de SqlSession, esto significa que se puede usar para reemplazar sin problemas el SqlSession que ya se usa en su código.
  2. Las plantillas pueden participar en la gestión de transacciones de Spring y, debido a que son seguras para subprocesos y pueden ser utilizadas por múltiples clases de mapeadores, siempre debe reemplazar la implementación DefaultSqlsession predeterminada de MyBatis con SqlsessionTemplate. Combinar el uso entre diferentes clases en la misma aplicación puede causar problemas de coherencia de los datos.

Los objetos SqlsessionTemplate se pueden crear utilizando SqlSessionFactory como parámetro del método constructor.

<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
  <constructor-arg index="0" ref="sqlSessionFactory" />
</bean>

Ahora, este frijol se puede inyectar directamente en su frijol DAO. Necesita agregar una propiedad SqlSession a su bean
, como esta:

public class UserDaoImpl implements UserDao {
    
    

    private SqlSession sqlSession;

    public void setSqlSession(SqlSession sqlSession) {
    
    
        this.sqlSession = sqlSession;
    }

    public User getUser(String userId) {
    
    
        return sqlSession.getMapper...;
    }
}

Inyecte SqlsessionTemplate de la siguiente manera:

<bean id="userDao" class="org.mybatis.spring.sample.dao.UserDaoImpl">
  <property name="sqlSession" ref="sqlSession" />
</bean>

Realización de la integración uno.

  1. Introduzca el archivo de configuración de Spring beans.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  xsi:schemaLocation="http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans.xsd">

</beans>
  1. Configurar la fuente de datos para reemplazar la fuente de datos de mybaits
<!--配置数据源:数据源有非常多,可以使用第三方的,也可使使用Spring的-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&amp;useUnicode=true&amp;characterEncoding=utf8"/>
    <property name="username" value="root"/>
    <property name="password" value="root"/>
</bean>
  1. Configurar SqlSessionFactory y asociarlo con MyBatis
<!--配置SqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <!--关联Mybatis-->
    <property name="configLocation" value="classpath:mybatis-config.xml"/>
    <property name="mapperLocations"
              value="classpath:org/example/mapper/*.xml"/>
</bean>
  1. Registre sqlSessionTemplate y asocie sqlSessionFactory;
<!--注册sqlSessionTemplate , 关联sqlSessionFactory-->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
  <!--利用构造器注入-->
  <constructor-arg index="0" ref="sqlSessionFactory"/>
</bean>
  1. Agregar clase de implementación de la interfaz Dao; privatizar sqlSessionTemplate
public class UserMapperImpl implements UserMapper {
    
    

    //sqlSession不用我们自己创建了,Spring来管理
    private SqlSessionTemplate sqlSession;

    public void setSqlSession(SqlSessionTemplate sqlSession) {
    
    
        this.sqlSession = sqlSession;
    }

    public List<User> selectUser() {
    
    
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        return mapper.selectUser();
    }

}
  1. Registrar implementación de beans
<bean id="userMapper" class="org.example.mapper.UserMapperImpl">
    <property name="sqlSession" ref="sqlSession"/>
</bean>
  1. prueba
@Test
public void test2(){
    
    
    ApplicationContext context = new ClassPathXmlApplicationContext("spring-dao.xml");
    UserMapper mapper = (UserMapper) context.getBean("userMapper");
    List<User> user = mapper.selectUser();
    System.out.println(user);
}

¡El resultado se genera con éxito! ¡Ahora el estado de nuestro archivo de configuración Mybatis! ¡Todo lo encontrado puede ser integrado por Spring!

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
  <typeAliases>
    <package name="org.example.pojo"/>
  </typeAliases>
</configuration>

Implementación de integración dos

Mybatis-spring versión 1.2.3 o superior solo tiene esto.
Captura de pantalla del documento oficial:
dao hereda la clase Support, la obtiene directamente usando getSqlSession() y luego inyecta directamente SqlSessionFactory. En comparación con el método 1, no es necesario administrar SqlSessionTemplate. y el soporte para transacciones es más amigable. Se puede ver el código fuente rastreable
imagen.png
. Prueba:

  1. Modifique el UserDaoImpl que escribimos arriba
public class UserDaoImpl extends SqlSessionDaoSupport implements UserMapper {
    
    
    public List<User> selectUser() {
    
    
        UserMapper mapper = getSqlSession().getMapper(UserMapper.class); 
        return mapper.selectUser();
    }
}
  1. Modificar la configuración del frijol
<bean id="userDao" class="com.kuang.dao.UserDaoImpl">
    <property name="sqlSessionFactory" ref="sqlSessionFactory" />
    </bean>
  1. prueba
@Test
public void test2() {
    
    
    ApplicationContext context = new
        ClassPathXmlApplicationContext( "beans.xml" );
    UserMapper mapper = (UserMapper) context.getBean( "userDao" );
    List<User> user = mapper.selectUser();
    System.out.println( user );
}

Resumen: Después de la integración en Spring, puede eliminar por completo el archivo de configuración de mybatis. Además de estos métodos para lograr la integración, también podemos usar anotaciones para lograr esto. ¡También probaremos la integración cuando aprendamos SpringBoot más adelante!

12. Transacciones declarativas

12.1 Asuntos de revisión

  • Las transacciones son muy importantes en el proceso de desarrollo del proyecto. ¡Los problemas relacionados con la coherencia de los datos no se pueden tomar a la ligera!
  • La gestión de transacciones es una tecnología esencial en el desarrollo de aplicaciones empresariales para garantizar la integridad y coherencia de los datos.

Una transacción trata una serie de acciones como una unidad de trabajo independiente. Estas acciones se completan todas o ninguna funciona.

Cuatro atributos de la transacción ACID
  1. atomicidad
    • Una transacción es una operación atómica, que consta de una serie de acciones. La atomicidad de la transacción garantiza que las acciones se completen o no tengan ningún efecto.
  2. Consistencia
    • Una vez que se completan todas las acciones de la transacción, se confirma la transacción. Los datos y recursos se encuentran en un estado consistente que cumple con las reglas comerciales.
  3. aislamiento
    • Varias transacciones pueden procesar los mismos datos al mismo tiempo, por lo que cada transacción debe aislarse de otras transacciones para evitar la corrupción de datos.
  4. durabilidad
    • Una vez que se completa una transacción, no importa qué errores ocurran en el sistema, los resultados no se verán afectados. Normalmente, los resultados de una transacción se escriben en un almacenamiento persistente.

12.2 Pruebas

Copie el código anterior a un nuevo proyecto.
En el caso anterior, agregamos dos métodos a la interfaz userDao, eliminando y agregando usuarios;

//添加一个用户
int addUser(User user);

//根据id删除用户
int deleteUser(int id);

archivo mapper, deliberadamente escribimos eliminaciones incorrectas, ¡prueba!

<insert id="addUser" parameterType="com.kuang.pojo.User">
  insert into user (id,name,pwd) values (#{id},#{name},#{pwd})
</insert>

<delete id="deleteUser" parameterType="int">
  deletes from user where id = #{id}
</delete>

Escriba la clase de implementación de la interfaz. En la clase de implementación, pasamos por una ola de operaciones.

public class UserDaoImpl extends SqlSessionDaoSupport implements UserMapper
{
    
    

    //增加一些操作
    public List<User> selectUser() {
    
    
        User user = new User(4,"小明","123456");
        UserMapper mapper = getSqlSession().getMapper(UserMapper.class);
        mapper.addUser(user);
        mapper.deleteUser(4);
        return mapper.selectUser();
    }

    //新增
    public int addUser(User user) {
    
    
        UserMapper mapper = getSqlSession().getMapper(UserMapper.class);
        return mapper.addUser(user);
    }
    //删除
    public int deleteUser(int id) {
    
    
        UserMapper mapper = getSqlSession().getMapper(UserMapper.class);
        return mapper.deleteUser(id);
    }

}

prueba

@Test
public void test2() {
    
    
    ApplicationContext context = new
        ClassPathXmlApplicationContext( "beans.xml" );
    UserMapper mapper = (UserMapper) context.getBean( "userDao" );
    List<User> user = mapper.selectUser();
    System.out.println( user );
}

Error: excepción de SQL, la eliminación se escribió incorrectamente. Resultado: ¡Inserción exitosa!
No hay gestión de los asuntos; queremos que todos tengan éxito antes de que ellos tengan éxito. Si uno falla, todos fracasan, ¡así que deberíamos necesitar asuntos! En el pasado, teníamos que gestionar las cosas manualmente, ¡lo cual era muy problemático!
Pero Spring nos proporciona gestión de transacciones, solo necesitamos configurarla;

12.3 Gestión de transacciones en primavera

Spring define una capa de abstracción sobre diferentes API de gestión de transacciones, lo que permite a los desarrolladores utilizar el mecanismo de gestión de transacciones de Spring sin conocer la API de gestión de transacciones subyacente. Spring admite la gestión de transacciones programáticas y la gestión de transacciones declarativas.

Gestión programática de transacciones
  • Incorpore código de gestión de transacciones en métodos comerciales para controlar el envío y la reversión de transacciones.
  • Desventaja: se debe incluir un código de gestión de transacciones adicional en la lógica empresarial de cada operación de transacción
Gestión de transacciones declarativas
  • Generalmente más fácil de usar que las transacciones programáticas.
  • Separe el código de gestión de transacciones de los métodos comerciales e implemente la gestión de transacciones de forma declarativa.
  • Trate la gestión de transacciones como una preocupación transversal y modularícela mediante métodos AOP. Spring admite la gestión de transacciones declarativas a través del marco Spring AOP.

Utilice Spring para administrar transacciones, preste atención a la importación de restricciones del archivo de encabezado: tx

xmlns:tx="http://www.springframework.org/schema/tx"


http://www.springframework.org/schema/tx

http://www.springframework.org/schema/tx/spring-tx.xsd">
administrador de transacciones
  • Independientemente de qué estrategia de gestión de transacciones de Spring se utilice (programática o declarativa), se requiere un administrador de transacciones.
  • Es la abstracción central de gestión de transacciones de Spring: la gestión encapsula un conjunto de métodos independientes de la tecnología.
Transacciones JDBC
<!-- 配置声明式事务 -->
<bean id="transactionManager" 
  class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  <property name="dataSource" ref="dataSource" />
</bean>

Después de configurar el administrador de transacciones, necesitamos configurar las notificaciones de transacciones.

<!-- 结合AOP实现事务的的植入 -->
<!--配置事务通知-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
  <tx:attributes>
    <!--配置哪些方法使用什么样的事务,配置事务的传播特性-->
    <tx:method name="add" propagation="REQUIRED"/>
    <tx:method name="delete" propagation="REQUIRED"/>
    <tx:method name="update" propagation="REQUIRED"/>
    <tx:method name="search*" propagation="REQUIRED"/>
    <tx:method name="get" read-only="true"/>
    <tx:method name="*" propagation="REQUIRED"/>
  </tx:attributes>
</tx:advice>
Características de propagación de transacciones de Spring:

El comportamiento de propagación de transacciones es cómo las transacciones se propagan entre múltiples métodos de transacción cuando se llaman entre sí. Spring admite 7 tipos de comportamientos de propagación de transacciones:

  • propagation_requierd: Si no hay una transacción actual, cree una nueva transacción. Si ya hay una transacción, agréguela a esta transacción. Esta es la opción más común.
  • propagation_supports: admite la transacción actual, si no hay una transacción actual, se ejecutará en un método no transaccional.
  • propagation_mandatory: utiliza la transacción actual, si no hay ninguna transacción actual, lanza una excepción.
  • propagation_required_new: crea una nueva transacción. Si existe una transacción actualmente, suspende la transacción actual.
  • propagation_not_supported: realiza operaciones de manera no transaccional. Si existe una transacción actualmente, suspenda la transacción actual.
  • propagation_never: realiza operaciones de forma no transaccional y lanza una excepción si la transacción actual existe.
  • propagation_nested: si existe una transacción actualmente, ejecútela dentro de una transacción anidada. Si no hay ninguna transacción actual, realice operaciones similares a propagation_required

El comportamiento de propagación de transacciones predeterminado de Spring es PROPAGATION_REQUIRED, que es adecuado para la mayoría de situaciones.
Supongamos que todos ServiveX#methodX() funcionan en un entorno de transacciones (es decir, todos están mejorados por transacciones Spring) y supongamos que existe la siguiente cadena de llamadas en el programa: Service1#method1()->Service2#method2() ->Service3#method3(), entonces los tres métodos de estas tres clases de servicio funcionan en la misma transacción a través del mecanismo de propagación de transacciones de Spring.
Por ejemplo, los métodos que acabamos de mencionar se llaman, por lo que se colocarán en un grupo de transacciones.

Configurar AOP

¡Importe el archivo de encabezado de aop!

<!--配置aop织入事务-->
<aop:config>
  <aop:pointcut id="txPointcut" expression="execution(* com.kuang.dao.*.* (..))"/>
  <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
</aop:config>
realizar pruebas

¡Elimine los datos que acaba de insertar y vuelva a probar!

@Test
public void test2() {
    
    
    ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
    UserMapper mapper = (UserMapper) context.getBean("userDao");
    List<User> user = mapper.selectUser();
    System.out.println(user);
}

Supongo que te gusta

Origin blog.csdn.net/qq_53517370/article/details/128868040
Recomendado
Clasificación