https://www.youtube.com/live/fg3pSIfyL6Q?feature=share

СОДЕРЖАНИЕ

Давайте посмотрим пример из Spring Framework

В Spring есть аннотация, которая называется @Component. Эта аннотация говорит фреймворку, что данный класс является служебным компонентом и должен быть загружен в рантайм. Давайте посмотрим, как это происходит. Вот сама аннотация:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Indexed
public @interface Component {
	String value() default "";
}

Ссылка на аннотацию на GitHub: https://github.com/spring-projects/spring-framework/blob/4786e2bf53a3f882c10e25d7ff79a18ff47b5e51/spring-context/src/main/java/org/springframework/stereotype/Component.java

Здесь нам всё уже знакомо, кроме аннотации @Indexed – это аннотация из Spring, которая позволяет записывать индекс классов.

Далее, давайте посмотрим на часть кода, в которой @Component непосредственно обрабатывается. Например, вот эта часть из класса обработки конфигураций:

protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
			throws IOException {
//....

		if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
			// Recursively process any member (nested) classes first
			processMemberClasses(configClass, sourceClass, filter);
		}

//.....

private void processMemberClasses(ConfigurationClass configClass, SourceClass sourceClass,
			Predicate<String> filter) throws IOException {

		Collection<SourceClass> memberClasses = sourceClass.getMemberClasses();
		if (!memberClasses.isEmpty()) {
			List<SourceClass> candidates = new ArrayList<>(memberClasses.size());
			for (SourceClass memberClass : memberClasses) {
				if (ConfigurationClassUtils.isConfigurationCandidate(memberClass.getMetadata()) &&
						!memberClass.getMetadata().getClassName().equals(configClass.getMetadata().getClassName())) {
					candidates.add(memberClass);
				}
			}
			OrderComparator.sort(candidates);
			for (SourceClass candidate : candidates) {
				if (this.importStack.contains(configClass)) {
					this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
				}
				else {
					this.importStack.push(configClass);
					try {
						processConfigurationClass(candidate.asConfigClass(configClass), filter);
					}
					finally {
						this.importStack.pop();
					}
				}
			}
		}
	}

protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {
		if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
			return;
		}

		ConfigurationClass existingClass = this.configurationClasses.get(configClass);
		if (existingClass != null) {
			if (configClass.isImported()) {
				if (existingClass.isImported()) {
					existingClass.mergeImportedBy(configClass);
				}
				// Otherwise ignore new imported config class; existing non-imported class overrides it.
				return;
			}
			else {
				// Explicit bean definition found, probably replacing an import.
				// Let's remove the old one and go with the new one.
				this.configurationClasses.remove(configClass);
				this.knownSuperclasses.values().removeIf(configClass::equals);
			}
		}

		// Recursively process the configuration class and its superclass hierarchy.
		SourceClass sourceClass = asSourceClass(configClass, filter);
		do {
			sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
		}
		while (sourceClass != null);

		this.configurationClasses.put(configClass, configClass);
	}

Ссылка на класс на GitHub:

https://github.com/spring-projects/spring-framework/blob/4786e2bf53a3f882c10e25d7ff79a18ff47b5e51/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java#L265

В этой части кода Spring проверяет если класс является компонентом, то его нужно положить в коллекцию configurationClasses. Что там происходит дальше немного за рамками нашего курса, здесь мы видим как просто обрабатывается существующая кастомная аннотация.

Почему Spring работает, если ты Александра говоришь, что Reflection очень замедляет проект?

Spring работает с аннотациями через байт-код с помощью библиотеки ASM: (https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/asm/package-summary.html Это все та же рефлексия, но работает она значительно быстрее, чем с использованием внутренних классов Java.

Код урока

Код урока находится в прикреплённом архиве. Архив содержит полный проект IDEA, который можно открыть через командное меню File→Open и указанием пути на текущий проект:

.

easyjava_junior_lesson25.zip