我正在使用 Spring Boot 创建一个航空公司网站。我有一个
Seat
类和 Flight
类,它们代表数据库中的表。这个想法是,每当添加航班时,都会自动创建该航班的座位并将其添加到表中。
以下是我添加航班和创建座位的服务类别:
package com.example.airline.flight.seat;
import com.example.airline.flight.FlightService;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
@Service
@RequiredArgsConstructor
public class SeatServiceImp implements SeatService {
private final SeatRepository seatRepository;
private final @Lazy FlightService flightService; // Used @Lazy to break the cycle
@Override
public void createSeat(long flightId) {
flightService.getSeatNumbers(flightId).forEach((key, value) -> {
int rowNumber = 1;
char seatLetter = 'A';
for (int i = 1; i <= value; i++) {
String seatNumber = seatLetter + String.valueOf(rowNumber);
Seat seat = Seat.builder()
.seatNumber(seatNumber)
.seatClass(SeatClass.valueOf(key))
.flight(flightService.getFlightById(flightId))
.seatStatus(SeatStatus.AVAILABLE)
.build();
seatRepository.save(seat);
seatLetter++;
if (seatLetter > 'F') {
seatLetter = 'A';
rowNumber++;
}
}
});
}
}
package com.example.airline.flight;
import com.example.airline.flight.seat.SeatService;
import com.example.airline.plane.Plane;
import com.example.airline.plane.PlaneService;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import java.util.Map;
@Service
@RequiredArgsConstructor
public class FlightServiceImp implements FlightService {
private final FlightRepository flightRepository;
private final PlaneService planeService;
private final @Lazy SeatService seatService; // Used @Lazy to break the cycle
@Override
public Map<String, Integer> getSeatNumbers(long flightId) {
long planeId = flightRepository.findById(flightId).orElseThrow().getPlane().getId();
return planeService.getSeatNumbers(planeId);
}
@Override
public Flight getFlightById(long id) {
return flightRepository.findById(id).orElseThrow();
}
@Override
public void addFlight(Flight flight) {
if (planeService.findPlaneById(flight.getPlane().getId()) == null) {
throw new IllegalArgumentException("Plane not found");
}
Plane existingPlane = planeService.findPlaneById(flight.getPlane().getId());
if (existingPlane == null || !existingPlane.getCurrentAirport().equals(flight.getDepartureAirport())) {
throw new IllegalArgumentException("Plane not found");
}
flightRepository.save(flight);
seatService.createSeat(flight.getId());
}
}
当我运行应用程序时,出现循环依赖错误。这是错误消息:
The dependencies of some of the beans in the application context form a cycle:
DBSeeder defined in file [C:\Users\Omar\Desktop\Airline_Backend\target\classes\com\example\airline\DBSeeder.class]
| flightServiceImp defined in file [C:\Users\Omar\Desktop\Airline_Backend\target\classes\com\example\airline\flight\FlightServiceImp.class]
↑ ↓
| seatServiceImp defined in file [C:\Users\Omar\Desktop\Airline_Backend\target\classes\com\example\airline\flight\seat\SeatServiceImp.class]
@Lazy
注释:我尝试在依赖项上使用@Lazy
注释来打破循环,但问题仍然存在。我需要一个更简单的解决方案,可以解决循环依赖关系,而无需显着改变应用程序的结构。我怎样才能实现这个目标?
这是我的
DBSeeder
和其他相关课程,可能有助于提供更多上下文:
package com.example.airline;
import com.example.airline.plane.aircraft.Aircraft;
import com.example.airline.plane.aircraft.AircraftService;
import com.example.airline.plane.Plane;
import com.example.airline.plane.PlaneService;
import com.example.airline.flight.Flight;
import com.example.airline.flight.FlightService;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import java.sql.Date;
import java.sql.Time;
import java.time.LocalDate;
@Component
@RequiredArgsConstructor
public class DatabaseSeeder implements CommandLineRunner {
private final AircraftService aircraftService;
private final PlaneService planeService;
private final @Lazy FlightService flightService; // Added @Lazy here to prevent early initialization
@Override
public void run(String... args) throws Exception {
// Add Aircraft
Aircraft aircraft1 = Aircraft.builder()
.model("Boeing 737")
.businessSeats(20)
.businessSeatPrice(2000)
.economySeats(150)
.economySeatPrice(500)
.firstClassSeats(10)
.firstClassSeatPrice(5000)
.rangeKm(6000)
.build();
aircraftService.addAircraft(aircraft1);
Aircraft aircraft2 = Aircraft.builder()
.model("Airbus A320")
.businessSeats(15)
.businessSeatPrice(1800)
.economySeats(160)
.economySeatPrice(600)
.firstClassSeats(12)
.firstClassSeatPrice(4500)
.rangeKm(5800)
.build();
aircraftService.addAircraft(aircraft2);
// Add Planes
Plane plane1 = Plane.builder()
.id(1L)
.aircraft(aircraft1)
.name("Plane 1")
.lastMaintenanceDate(Date.valueOf(LocalDate.now()))
.nextMaintenanceDate(Date.valueOf(LocalDate.now().plusDays(30))) // 30 days from now
.hoursOnAir(1000)
.flightsCompleted(200)
.currentAirport("JFK")
.operationlaStatus(OperationlaStatus.ACTIVE)
.build();
Plane plane2 = Plane.builder()
.id(2L)
.aircraft(aircraft1)
.name("Plane 2")
.lastMaintenanceDate(Date.valueOf(LocalDate.now()))
.nextMaintenanceDate(Date.valueOf(LocalDate.now().plusDays(30))) // 30 days from now
.hoursOnAir(1200)
.flightsCompleted(220)
.currentAirport("LAX")
.operationlaStatus(OperationlaStatus.ACTIVE)
.build();
Plane plane3 = Plane.builder()
.id(3L)
.aircraft(aircraft2)
.name("Plane 3")
.lastMaintenanceDate(Date.valueOf(LocalDate.now()))
.nextMaintenanceDate(Date.valueOf(LocalDate.now().plusDays(30))) // 30 days from now
.hoursOnAir(800)
.flightsCompleted(180)
.currentAirport("JFK")
.operationlaStatus(OperationlaStatus.ACTIVE)
.build();
planeService.addPlane(plane1);
planeService.addPlane(plane2);
planeService.addPlane(plane3);
// Add Flights
Flight flight1 = Flight.builder()
.departureCity("New York")
.arrivalCity("London")
.departureTime(Time.valueOf("10:00:00"))
.arrivalTime(Time.valueOf("20:00:00"))
.departureDate(Date.valueOf(LocalDate.now()))
.arrivalDate(Date.valueOf(LocalDate.now().plusDays(1))) // 1 day from now
.departureAirport("JFK")
.arrivalAirport("LHR")
.departureTerminal("T4")
.arrivalTerminal("T5")
.departureCountry("USA")
.arrivalCountry("UK")
.plane(plane1)
.build();
Flight flight2 = Flight.builder()
.departureCity("Los Angeles")
.arrivalCity("Tokyo")
.departureTime(Time.valueOf("14:00:00"))
.arrivalTime(Time.valueOf("04:00:00"))
.departureDate(Date.valueOf(LocalDate.now()))
.arrivalDate(Date.valueOf(LocalDate.now().plusDays(1))) // 1 day from now
.departureAirport("LAX")
.arrivalAirport("HND")
.departureTerminal("T2")
.arrivalTerminal("T3")
.departureCountry("USA")
.arrivalCountry("Japan")
.plane(plane2)
.build();
flightService.addFlight(flight1);
flightService.addFlight(f
light2);
}
}
谢谢您的帮助!
在编写服务甚至服务方法时,您应该考虑用例而不是实体。您的
addFlight
方法应该创建集合等,而不是将其委托给另一个服务(SeatService
)。只需将该方法移动到 FlightService
使其成为 private
并从该方法中调用它即可。我怀疑您是否需要独立的 createSeat
方法。
当您移动该方法时,您可以放弃
SeatService
并简单地将 SeatRepository
注入到 FlightService
中,甚至更好,假设 Flight
是一个正确的 JPA 实体并且与 Seat
有关系,您甚至不知道需要它,只需将 Seat
添加到 Flight
即可一次性保存所有内容。
@Service
@RequiredArgsConstructor
public class FlightServiceImp implements FlightService {
private final FlightRepository flightRepository;
private final PlaneService planeService;
@Override
public Map<String, Integer> getSeatNumbers(long flightId) {
long planeId = flightRepository.findById(flightId).orElseThrow().getPlane().getId();
return planeService.getSeatNumbers(planeId);
}
@Override
public Flight getFlightById(long id) {
return flightRepository.findById(id).orElseThrow();
}
@Override
public void addFlight(Flight flight) {
Plane existingPlane = planeService.findPlaneById(flight.getPlane().getId());
if (existingPlane == null) {
throw new IllegalArgumentException("Plane not found");
}
if (existingPlane == null || !existingPlane.getCurrentAirport().equals(flight.getDepartureAirport())) {
throw new IllegalArgumentException("Plane not found");
}
createSeats(flight);
flightRepository.save(flight);
}
private void createSeats(Flight flight) {
var planeId = flight.getPlane().getId();
planeService.getSeatNumbers(planeId).forEach((key, value) -> {
int rowNumber = 1;
char seatLetter = 'A';
for (int i = 1; i <= value; i++) {
String seatNumber = seatLetter + String.valueOf(rowNumber);
Seat seat = Seat.builder()
.seatNumber(seatNumber)
.seatClass(SeatClass.valueOf(key))
.flight(flight
.seatStatus(SeatStatus.AVAILABLE)
.build();
flight.addSeat(seat);
seatLetter++;
if (seatLetter > 'F') {
seatLetter = 'A';
rowNumber++;
}
}
});
}
}