¿Cómo maneja Java las dependencias circulares? (Método + Ejemplo de código)

Tabla de contenido

1: Usar interfaz o clase abstracta

2: inyección de constructor

3: utilizar el contenedor de inyección de dependencia (Spring)

4. Inicialización diferida

5. Utilice el patrón de fábrica



1: Usar interfaz o clase abstracta

// 接口或抽象类
public interface ServiceA {
    void methodA();
}

public interface ServiceB {
    void methodB();
}

// 实现类
public class ServiceAImpl implements ServiceA {
    private ServiceB serviceB;

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

    public void methodA() {
        // 使用ServiceB的方法
        serviceB.methodB();
    }
}

public class ServiceBImpl implements ServiceB {
    private ServiceA serviceA;

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

    public void methodB() {
        // 使用ServiceA的方法
        serviceA.methodA();
    }
}

En este ejemplo, ServiceAdefina ServiceBinterfaces, respectivamente, ServiceAImple ServiceBImplimplemente esas interfaces, respectivamente. Inyectan las dependencias de cada uno a través del constructor.

2: inyección de constructor

public class ServiceA {
    private ServiceB serviceB;

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

    public void methodA() {
        // 使用ServiceB的方法
        serviceB.methodB();
    }
}

public class ServiceB {
    private ServiceA serviceA;

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

    public void methodB() {
        // 使用ServiceA的方法
        serviceA.methodA();
    }
}

En este ejemplo, las clases ServiceAy ServiceBinyectan las dependencias de cada una a través de constructores.

3: utilizar el contenedor de inyección de dependencia (Spring)

Si usa el marco Spring, el contenedor Spring puede manejar automáticamente dependencias circulares. El siguiente es un ejemplo simple de configuración de Spring:

@Configuration
public class AppConfig {
    @Bean
    public ServiceA serviceA() {
        return new ServiceA(serviceB());
    }

    @Bean
    public ServiceB serviceB() {
        return new ServiceB(serviceA());
    }
}

En este ejemplo, el contenedor Spring resolverá automáticamente la dependencia circular entre serviceAy serviceBporque garantizará que se serviceAcreó cuando se creó serviceB, y viceversa.

Estos ejemplos demuestran diferentes formas de manejar las dependencias circulares y usted puede elegir el método que se adapte a las necesidades de su proyecto. Cualquiera que sea el enfoque que adopte, asegúrese de que su código esté claramente estructurado y que las dependencias se inyecten correctamente para evitar posibles problemas.

Hay otras formas:

4. Inicialización diferida

Si su lenguaje de programación admite la inicialización diferida (como @Lazylas anotaciones de Java), puede configurar ciertas dependencias para que se inicialicen de forma diferida. De esta manera, incluso si existen dependencias circulares, los objetos solo se inicializarán cuando sea necesario, lo que puede reducir la aparición de problemas.

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;

@Configuration
public class AppConfig {

    @Bean
    @Lazy // 使用@Lazy注解延迟初始化ServiceA
    public ServiceA serviceA() {
        return new ServiceA();
    }

    @Bean
    @Lazy // 使用@Lazy注解延迟初始化ServiceB
    public ServiceB serviceB() {
        return new ServiceB();
    }
}

public class ServiceA {
    private ServiceB serviceB;

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

    public void methodA() {
        // 使用ServiceB的方法
        serviceB.methodB();
    }
}

public class ServiceB {
    private ServiceA serviceA;

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

    public void methodB() {
        // 使用ServiceA的方法
        serviceA.methodA();
    }
}

En este ejemplo, usamos @Lazyla anotación para marcar las definiciones serviceAde beans serviceBy para decirle al contenedor Spring que las inicialice lentamente. De esta forma, incluso si existen dependencias circulares, el objeto solo se instanciará cuando sea necesario, evitando así problemas causados ​​por dependencias circulares.

Tenga en cuenta que @Lazylas anotaciones generalmente se usan con el contenedor Spring, por lo que antes de usarlas, asegúrese de que su proyecto integre el marco Spring.

5. Utilice el patrón de fábrica

public class ServiceA {
    private ServiceB serviceB;

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

    public void methodA() {
        // 使用ServiceB的方法
        serviceB.methodB();
    }
}

public class ServiceB {
    private ServiceA serviceA;

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

    public void methodB() {
        // 使用ServiceA的方法
        serviceA.methodA();
    }
}

public class ServiceFactory {
    private ServiceA serviceA;
    private ServiceB serviceB;

    public ServiceA createServiceA() {
        if (serviceA == null) {
            serviceA = new ServiceA();
            serviceA.setServiceB(createServiceB());
        }
        return serviceA;
    }

    public ServiceB createServiceB() {
        if (serviceB == null) {
            serviceB = new ServiceB();
            serviceB.setServiceA(createServiceA());
        }
        return serviceB;
    }
}

En este ejemplo, presentamos una ServiceFactoryclase de fábrica responsable de crear ServiceAobjetos ServiceB. Cuando necesite crear ServiceAo ServiceB, el método de fábrica verificará si el objeto ya existe y devolverá el objeto existente si existe; de ​​lo contrario, creará un nuevo objeto. De esta manera, el método de fábrica asegura que el problema de dependencia circular se resuelva al crear objetos, porque solo se hacen referencia entre sí cuando es necesario.

El uso del método de fábrica puede abordar eficazmente el problema de la dependencia circular mientras se mantiene la naturaleza de instancia única del objeto para mejorar el rendimiento y la utilización de recursos.

Supongo que te gusta

Origin blog.csdn.net/ZLAKS123456/article/details/132697207
Recomendado
Clasificación