Home / Class/ BufferingApplicationStartup Class — spring-boot Architecture

BufferingApplicationStartup Class — spring-boot Architecture

Architecture documentation for the BufferingApplicationStartup class in BufferingApplicationStartup.java from the spring-boot codebase.

Entity Profile

Source Code

core/spring-boot/src/main/java/org/springframework/boot/context/metrics/buffering/BufferingApplicationStartup.java lines 55–175

public class BufferingApplicationStartup implements ApplicationStartup {

	private final int capacity;

	private final Clock clock;

	private Instant startTime;

	private final AtomicInteger idSeq = new AtomicInteger();

	private Predicate<StartupStep> filter = (step) -> true;

	private final AtomicReference<@Nullable BufferedStartupStep> current = new AtomicReference<>();

	private final AtomicInteger estimatedSize = new AtomicInteger();

	private final ConcurrentLinkedQueue<TimelineEvent> events = new ConcurrentLinkedQueue<>();

	/**
	 * Create a new buffered {@link ApplicationStartup} with a limited capacity and starts
	 * the recording of steps.
	 * @param capacity the configured capacity; once reached, new steps are not recorded.
	 */
	public BufferingApplicationStartup(int capacity) {
		this(capacity, Clock.systemDefaultZone());
	}

	BufferingApplicationStartup(int capacity, Clock clock) {
		this.capacity = capacity;
		this.clock = clock;
		this.startTime = clock.instant();
	}

	/**
	 * Start the recording of steps and mark the beginning of the {@link StartupTimeline}.
	 * The class constructor already implicitly calls this, but it is possible to reset it
	 * as long as steps have not been recorded already.
	 * @throws IllegalStateException if called and {@link StartupStep} have been recorded
	 * already.
	 */
	public void startRecording() {
		Assert.state(this.events.isEmpty(), "Cannot restart recording once steps have been buffered");
		this.startTime = this.clock.instant();
	}

	/**
	 * Add a predicate filter to the list of existing ones.
	 * <p>
	 * A {@link StartupStep step} that doesn't match all filters will not be recorded.
	 * @param filter the predicate filter to add.
	 */
	public void addFilter(Predicate<StartupStep> filter) {
		this.filter = this.filter.and(filter);
	}

	@Override
	public StartupStep start(String name) {
		int id = this.idSeq.getAndIncrement();
		Instant start = this.clock.instant();
		while (true) {
			BufferedStartupStep current = this.current.get();
			BufferedStartupStep parent = getLatestActive(current);
			BufferedStartupStep next = new BufferedStartupStep(parent, name, id, start, this::record);
			if (this.current.compareAndSet(current, next)) {
				return next;
			}
		}
	}

	private void record(BufferedStartupStep step) {
		if (this.filter.test(step) && this.estimatedSize.get() < this.capacity) {
			this.estimatedSize.incrementAndGet();
			this.events.add(new TimelineEvent(step, this.clock.instant()));
		}
		while (true) {
			BufferedStartupStep current = this.current.get();
			BufferedStartupStep next = getLatestActive(current);
			if (this.current.compareAndSet(current, next)) {
				return;
			}
		}
	}

	private @Nullable BufferedStartupStep getLatestActive(@Nullable BufferedStartupStep step) {
		while (step != null && step.isEnded()) {
			step = step.getParent();
		}
		return step;
	}

	/**
	 * Return the {@link StartupTimeline timeline} as a snapshot of currently buffered
	 * steps.
	 * <p>
	 * This will not remove steps from the buffer, see {@link #drainBufferedTimeline()}
	 * for its counterpart.
	 * @return a snapshot of currently buffered steps.
	 */
	public StartupTimeline getBufferedTimeline() {
		return new StartupTimeline(this.startTime, new ArrayList<>(this.events));
	}

	/**
	 * Return the {@link StartupTimeline timeline} by pulling steps from the buffer.
	 * <p>
	 * This removes steps from the buffer, see {@link #getBufferedTimeline()} for its
	 * read-only counterpart.
	 * @return buffered steps drained from the buffer.
	 */
	public StartupTimeline drainBufferedTimeline() {
		List<TimelineEvent> events = new ArrayList<>();
		Iterator<TimelineEvent> iterator = this.events.iterator();
		while (iterator.hasNext()) {
			events.add(iterator.next());
			iterator.remove();
		}
		this.estimatedSize.set(0);
		return new StartupTimeline(this.startTime, events);
	}

}

Analyze Your Own Codebase

Get architecture documentation, dependency graphs, and domain analysis for your codebase in minutes.

Try Supermodel Free