Solución de dependencia circular en Spring

dependencia circular

 La dependencia circular es uno de los problemas comunes en el marco Spring. Cuando dos o más clases se refieren entre sí, se produce una dependencia circular. En este caso, el marco Spring no puede determinar qué clase se debe crear una instancia e inicializar primero, lo que genera una excepción. Las soluciones comunes incluyen: inyección de constructor, inyección de método de establecimiento, inyección de método de fábrica estático y uso de bibliotecas de terceros .

Versión utilizada esta vez:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.6.0</version>
    <relativePath/>
</parent>

Caso

public interface ServiceA {
    
    
}

public interface ServiceB {
    
    
}

@Service
public class ServiceAImpl implements ServiceA {
    
    
    private ServiceB serviceB;

    public ServiceAImpl(ServiceB serviceB) {
    
    
        this.serviceB = serviceB;
    }
}

@Service
public class ServiceBImpl implements ServiceB {
    
    
    private ServiceA serviceA;

    public ServiceBImpl(ServiceA serviceA) {
    
    
        this.serviceA = serviceA;
    }
}

Insertar descripción de la imagen aquí

Solución

1. Rediseño

Cuando hay una dependencia circular es probable que haya un problema de diseño y las responsabilidades no estén bien separadas. Los componentes deben rediseñarse adecuadamente tanto como sea posible para que su jerarquía esté bien diseñada y no sean necesarias dependencias circulares.

Si un componente no se puede rediseñar (puede haber muchas razones: código heredado, código que ha sido probado y no se puede modificar, no hay suficiente tiempo o recursos para rediseñarlo por completo...), pero existen algunas soluciones para resolver el problema.

2.@Perezoso

 Una solución simple a las dependencias circulares de Spring es utilizar la carga diferida de un bean . En otras palabras: este Bean no se ha inicializado por completo, de hecho, se inyecta en un proxy, que solo se inicializará por completo cuando se utilice por primera vez.

@Service
public class ServiceAImpl implements ServiceA {
    
    
    private ServiceB serviceB;

    public ServiceAImpl(@Lazy ServiceB serviceB) {
    
    
        this.serviceB = serviceB;
    }
}

3.Setter/Inyección de campo

En pocas palabras, utiliza la inyección de setter (o inyección de campo) para los beans que necesita inyectar, no la inyección de constructor. Al crear un Bean de esta manera, de hecho, sus dependencias no se inyectan en este momento y se inyectarán solo cuando lo necesite.

@Service
public class ServiceAImpl implements ServiceA {
    
    
    private ServiceB serviceB;

    @Autowired
    public void setServiceB(ServiceB serviceB) {
    
    
        this.serviceB = serviceB;
    }
}

SpringBoot 2.6.x no recomienda el uso de dependencias circulares. La forma más sencilla es permitir referencias circulares en el archivo de configuración global. El valor predeterminado de esta propiedad es falso y la declaración de visualización es verdadera, lo que puede evitar excepciones de referencia circular de la consola. cuando comienza el proyecto.

spring:
  main:
    allow-circular-references: true

4.@PostConstrucción

Otra forma de romper el ciclo es usarlo en la propiedad que desea inyectar (que es un bean) @Autowiredy usar @PostConstructla anotación en otro método y establecer la dependencia de otros métodos en ese método.

@Service
public class ServiceAImpl implements ServiceA {
    
    
    @Autowired
    private ServiceB serviceB;

    @PostConstruct
    public void init() {
    
    
        System.out.println(serviceB);
        serviceB.setServiceA(this);
    }
}

@Service
public class ServiceBImpl implements ServiceB {
    
    
    private ServiceA serviceA;

    public void setServiceA(ServiceA serviceA) {
    
    
        System.out.println(serviceA);
        this.serviceA = serviceA;
    }
}

Resumir:

Forma Dependencias Método de inyección Capacidad para resolver dependencias circulares.
Situación uno interdependencia AB Todos usan el método setter capaz
Situación 2 interdependencia AB Ambos usan el método constructor. no puedo
Situación tres interdependencia AB Inyectar B en A usa un setter, e inyectar A en B usa un constructor capaz
Situación cuatro interdependencia AB Inyectar B en A usa un constructor, e inyectar A en B usa un setter no puedo
Situación cinco interdependencia AB Inyecte B en A y úselo @Autowired, inyecte A en B y use @PostConstruct+ setter capaz
Situación seis interdependencia AB Inyectar B en A usa @PostConstruct+ setter, inyectar A en B usa@Autowired capaz

Supongo que te gusta

Origin blog.csdn.net/weixin_43847283/article/details/132328210
Recomendado
Clasificación