SpringIoC Bean 라이프사이클 소스 코드 분석(1부)

빈 생성 과정

여기에 이미지 설명을 삽입하세요.

빈 생성 정의

Spring은 시작될 때 스캔할 것이며 먼저 org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider#scanCandidateComponents(String basePackage)를 호출하여
패키지 경로를 스캔하고 BeanDefinition의 Set 컬렉션을 얻을 것이다.

스프링 스캔 기본 프로세스:
여기에 이미지 설명을 삽입하세요.

  1. 먼저 ResourcePatternResolver를 통해 지정된 패키지 경로에 있는 모든 .class 파일을 얻습니다. (이 파일은 Spring 소스 코드에서 Resource 객체로 패키지됩니다.)
  2. 각 리소스 개체를 탐색합니다.
  3. MetadataReaderFactory를 사용하여 Resource 객체를 구문 분석하여 MetadataReader를 얻습니다(Spring 소스 코드에서 MetadataReaderFactory의 특정 구현 클래스는 CachingMetadataReaderFactory이고 MetadataReader의 특정 구현 클래스는 SimpleMetadataReader입니다)
  4. MetadataReader를 사용하여 includeFilters 및 includeFilters와 조건부 주석 @Conditional을 필터링합니다(조건부 주석은 특정 클래스에 @Conditional 주석이 있는지 여부를 이해할 수 없습니다. 존재하는 경우 주석에 지정된 클래스의 match 메서드를 호출하여 일치합니다. 일치가 성공하면 필터를 통과하고, 일치가 실패하면 통과합니다.)
  5. 심사를 통과한 후 MetadataReader를 기반으로 ScannedGenericBeanDefinition이 생성됩니다.
  6. 그런 다음 MetadataReader를 기반으로 해당 클래스가 인터페이스인지 추상 클래스인지 확인합니다.
  7. 필터가 통과하면 Bean이 스캔되었으며 ScannedGenericBeanDefinition이 결과 세트에 추가되었음을 의미합니다.

MetadataReader는 주로 다음 기능을 가진 AnnotationMetadata를 포함하는 클래스의 메타데이터 리더를 나타냅니다 .

  • 수업 이름을 알아보세요.
  • 상위 클래스의 이름을 가져옵니다.
  • 구현된 모든 인터페이스 이름을 가져옵니다.
  • 모든 내부 클래스의 이름을 가져옵니다.
  • 추상 클래스인지 확인
  • 인터페이스인지 확인
  • 주석인지 확인
  • 특정 주석이 포함된 메서드 컬렉션 가져오기
  • 클래스에 추가된 모든 주석 정보를 가져옵니다.
  • 클래스에 추가된 모든 주석 유형의 컬렉션을 가져옵니다.

CachingMetadataReaderFactory는 ASM 기술을 사용하여 MetadataReader 객체를 얻기 위해 .class 파일을 구문 분석하고 이 클래스를 JVM에 로드하지 않습니다. 또한 결과 ScannedGenericBeanDefinition 객체에서 beanClass 속성은 클래스 객체가 아닌 현재 클래스의 이름을 저장합니다 . (beanClass 속성의 타입은 Object이며, 클래스명과 클래스 객체를 모두 저장할 수 있다)

스캐닝을 통해 BeanDefinition 객체를 얻는 것 외에도 BeanDefinition을 직접 정의하거나 spring.xml 파일의 <bean/>을 파싱하거나 @Bean Annotation을 사용하여 BeanDefinition 객체를 얻을 수도 있다.

MergeBean정의

스캐닝을 통해 모든 BeanDefinition을 얻은 후에는 BeanDefinition을 기반으로 Bean 객체를 생성할 수 있지만 Spring은 Java 부모-자식 클래스와 유사하지만 전혀 다른 부모-자식 BeanDefinition을 지원한다.

부모-자식 BeanDefinition의 실제 사용은 비교적 드물며 사용법은 다음과 같습니다.

// 这么定义的情况下,child是单例Bean
<bean id="parent" class="com.tacy.service.Parent" scope="prototype"/>
<bean id="child" class="com.tacy.service.Child"/>
// 这么定义的情况下,child就是原型Bean
//因为child的父BeanDefinition是parent,所以会继承parent上所定义的scope属性
<bean id="parent" class="com.zhouyu.service.Parent" scope="prototype"/>
<bean id="child" class="com.zhouyu.service.Child" parent="parent"/>

자식을 기반으로 Bean 객체를 생성하기 전에 BeanDefinitions를 병합하여 자식의 완전한 BeanDefinition을 얻어야 합니다.

클래스 로드

BeanDefinition을 병합한 후 Bean 객체를 생성할 수 있는데, Bean을 생성하려면 해당 객체를 인스턴스화해야 하며 인스턴스화는 먼저 현재 BeanDefinition에 해당하는 클래스를 로드해야 하며 AbstractAutowireCapableBeanFactory 클래스의 createBean() 메소드에서 이를 수행한다. 처음에 호출됩니다. :

Class<?> resolvedClass = resolveBeanClass(mbd, beanName);

이 코드 줄은 클래스를 로드하는 것이며 메서드는 다음과 같이 구현됩니다.

if (mbd.hasBeanClass()) {
    
    
	return mbd.getBeanClass();
}
if (System.getSecurityManager() != null) {
    
    
	return AccessController.doPrivileged((PrivilegedExceptionAction<Class<?>>) () ->
		doResolveBeanClass(mbd, typesToMatch), getAccessControlContext());
	}
else {
    
    
	return doResolveBeanClass(mbd, typesToMatch);
}
public boolean hasBeanClass() {
    
    
	return (this.beanClass instanceof Class);
}

beanClass 속성의 유형이 Class이면 직접 반환하고, 그렇지 않으면 클래스 이름에 따라 로드됩니다(doResolveBeanClass 메서드가 수행하는 작업).

BeanFactory에서 설정한 클래스 로더를 사용하여 클래스를 로드하며, 설정하지 않은 경우 기본적으로 ClassUtils.getDefaultClassLoader()에서 반환한 클래스 로더를 사용합니다.

ClassUtils.getDefaultClassLoader()

  1. 현재 스레드에서 ClassLoader를 먼저 반환합니다.
  2. 스레드의 클래스 로더가 null인 경우 ClassUtils 클래스의 클래스 로더가 반환됩니다.
  3. ClassUtils 클래스의 클래스 로더가 비어 있으면 ClassUtils 클래스가 Bootstrap 클래스 로더에 의해 로드된 다음 시스템 클래스 로더가 반환된다는 의미입니다.

인스턴스화 전

현재 BeanDefinition에 해당하는 클래스가 성공적으로 로드된 후 객체를 인스턴스화할 수 있습니다.

Spring에서는 객체를 인스턴스화하기 전에 사용자가 하나 이상의 Bean을 인스턴스화하기 전에 일부 시작 작업을 수행할지 여부를 제어할 수 있는 확장 지점을 제공합니다. 이 확장점은 InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation()이라고 합니다. 예를 들어:

@Component
public class TacyBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
    
    

	@Override
	public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
    
    
		if ("userService".equals(beanName)) {
    
    
			System.out.println("实例化前");
		}
		return null;
	}
}

위의 코드는 userService Bean이 인스턴스화되기 전에 인쇄가 발생하도록 합니다.

postProcessBeforeInstantiation()에 반환 값이 있다는 점은 주목할 가치가 있습니다. 다음과 같이 구현되는 경우:

@Component
public class TacyBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
    
    

	@Override
	public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
    
    
		if ("userService".equals(beanName)) {
    
    
			System.out.println("实例化前");
			return new UserService();
		}
		return null;
	}
}

userService Bean은 인스턴스화 전에 정의한 UserService 객체를 직접 반환합니다. 이 경우 인스턴스화에 Spring이 필요하지 않으며 후속 Spring 종속성 주입이 수행되지 않으며 일부 단계를 건너뛰고 초기화 후 단계가 직접 수행된다는 의미입니다.

인스턴스화

이 단계에서는 BeanDefinition을 기반으로 객체가 생성됩니다.

공급자가 객체를 생성합니다.

먼저 BeanDefinition에 공급자가 설정되어 있는지 확인하고, 설정되어 있으면 공급자의 get()을 호출하여 객체를 가져온다.
다음과 같이 공급자를 설정하려면 BeanDefinition 개체를 직접 사용해야 합니다.

AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
beanDefinition.setInstanceSupplier(new Supplier<Object>() {
    
    
	@Override
	public Object get() {
    
    
		return new UserService();
	}
});
context.registerBeanDefinition("userService", beanDefinition);

팩토리 메소드는 객체를 생성합니다.

공급자가 설정되지 않은 경우 팩토리 메소드인 BeanDefinition에 FactoryMethod가 설정되어 있는지 확인한다.

  • 방법 1
<bean id="userService" class="com.tacy.service.UserService" factory-method="createUserService" />

해당 UserService 클래스는 다음과 같습니다.

public class UserService {
    
    

	public static UserService createUserService() {
    
    
		System.out.println("执行createUserService()");
		UserService userService = new UserService();
		return userService;
	}

	public void test() {
    
    
		System.out.println("test");
	}

}
  • 웨이 2
<bean id="commonService" class="com.tacy.service.CommonService"/>
<bean id="userService1" factory-bean="commonService" factory-method="createUserService" />

해당 CommonService 클래스는 다음과 같습니다.

public class CommonService {
    
    

	public UserService createUserService() {
    
    
		return new UserService();
	}
}

Spring은 현재 BeanDefinition 메소드가 팩토리 메소드를 설정했음을 발견한 후 두 메소드를 구별하고 객체를 얻기 위해 팩토리 메소드를 호출합니다.

@Bean을 통해 정의한 BeanDefinition에는 FactoryMethod와 FactoryBean이 있는데 이는 위의 두 번째 메소드와 매우 유사하며, @Bean으로 주석이 달린 메소드는 FactoryMethod, AppConfig 객체는 FactoryBean입니다. @Bean으로 주석이 달린 메소드가 정적이면 해당 메소드는 메소드 1입니다.

유추된 생성자

생성자가 추론된 후 생성자는 인스턴스화에 사용됩니다.

또한 생성자 메서드를 추론하는 로직에서는 생성자 메서드를 선택하고 입력 매개변수 객체를 검색하는 것 외에 해당 클래스에 @Lookup이라는 어노테이션이 붙은 메서드가 있는지도 확인한다. 존재하는 경우 메소드를 LookupOverride 객체로 캡슐화하고 이를 BeanDefinition에 추가합니다.

인스턴스화 과정에서 현재 BeanDefinition에 LookupOverride가 없다고 판단되면 생성자 메소드를 직접 사용하여 반영하여 인스턴스 객체를 얻는다. LookupOverride 개체가 있는 경우, 즉 클래스에 @Lookup 주석이 달린 메서드가 있는 경우 프록시 개체가 생성됩니다.

@Lookup 주석은 메서드 주입입니다. 다음과 같이 데모를 사용하세요.

@Component
public class UserService {
    
    

	private OrderService orderService;

	public void test() {
    
    
		OrderService orderService = createOrderService();
		System.out.println(orderService);
	}

	@Lookup("orderService")
	public OrderService createOrderService() {
    
    
		return null;
	}

}

BeanDefinition 후처리

Bean 객체가 인스턴스화되면 다음 단계는 객체의 속성에 값을 할당하는 것입니다. 실제로 속성에 값을 할당하기 전에 Spring은 다음과 같이 BeanDefinition을 처리할 수 있는 확장점 MergedBeanDefinitionPostProcessor.postProcessMergedBeanDefinition()을 제공합니다.

@Component
public class TacyMergedBeanDefinitionPostProcessor implements MergedBeanDefinitionPostProcessor {
    
    

	@Override
	public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
    
    
		if ("userService".equals(beanName)) {
    
    
			beanDefinition.getPropertyValues().add("orderService", new OrderService());
		}
	}
}

Spring 소스 코드에서 AutowiredAnnotationBeanPostProcessor는 MergedBeanDefinitionPostProcessor이며 postProcessMergedBeanDefinition()은 주입 지점을 찾아 이를 AutowiredAnnotationBeanPostProcessor 개체(injectionMetadataCache)의 맵에 캐시합니다.

인스턴스화 후

BeanDefinition을 처리한 후 Spring은 다음과 같은 확장점 InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation()을 설계했습니다.

@Component
public class TacyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
    
    

	@Override
	public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
    
    

		if ("userService".equals(beanName)) {
    
    
			UserService userService = (UserService) bean;
			userService.test();
		}

		return true;
	}
}

자동 주입

자동 주입은 Spring의 자동 주입을 의미합니다.

속성 처리

이 단계에서는 **@Autowired, @Resource 및 @Value 와 같은 주석이 처리되며 이는 InstantiationAwareBeanPostProcessor.postProcessProperties()** 확장점을 통해 구현됩니다. 예를 들어 자체 자동 주입 기능을 구현할 수도 있습니다. , 와 같은:

@Component
public class TacyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
    
    

	@Override
	public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
    
    
		if ("userService".equals(beanName)) {
    
    
			for (Field field : bean.getClass().getFields()) {
    
    
				if (field.isAnnotationPresent(TacyInject.class)) {
    
    
					field.setAccessible(true);
					try {
    
    
						field.set(bean, "123");
					} catch (IllegalAccessException e) {
    
    
						e.printStackTrace();
					}
				}
			}
		}

		return pvs;
	}
}

실행 인식

속성 할당을 완료한 후 Spring은 다음을 포함한 일부 콜백을 실행합니다.

  • BeanNameAware: beanName을 bean 객체에 반환합니다.
  • BeanClassLoaderAware: classLoader를 Bean 객체에 반환합니다.
  • BeanFactoryAware: beanFactory를 객체에 반환합니다.

초기화 전

초기화 전에는 Spring이 제공하는 확장점이기도 합니다: BeanPostProcessor.postProcessBeforeInitialization ()

@Component
public class TacyBeanPostProcessor implements BeanPostProcessor {
    
    

	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    
    
		if ("userService".equals(beanName)) {
    
    
			System.out.println("初始化前");
		}

		return bean;
	}
}

초기화 전에 의존성이 주입된 Bean을 처리할 수 있습니다
.Spring 소스 코드에서:

  • InitDestroyAnnotationBeanPostProcessor는 초기화 전 이 단계에서 @PostConstruct 메소드를 실행합니다.
  • ApplicationContextAwareProcessor는 초기화 전 이 단계에서 다른 Aware 콜백을 수행합니다:
    a. EnvironmentAware: 환경 변수 반환
    b. EmbeddedValueResolverAware: 자리 표시자 파서 반환
    c. ResourceLoaderAware: 리소스 로더 반환
    d. ApplicationEventPublisherAware: 이벤트 게시 반환 e
    . MessageSourceAware: 국제화된 리소스 반환
    f. ApplicationStartupAware : 무시할 수 있는 애플리케이션의 다른 모니터링 개체를 반환합니다.
    g. ApplicationContextAware: Spring 컨테이너 ApplicationContext를 반환합니다.

초기화

  • 현재 Bean 객체가 InitializingBean 인터페이스를 구현하고 있는지 확인하고, 구현되어 있다면 afterPropertiesSet() 메소드를 호출하세요.
  • BeanDefinition에 지정된 초기화 메소드를 실행합니다.

초기화 후

이는 Bean 생성 라이프사이클의 마지막 단계이며 Spring에서 제공하는 BeanPostProcessor.postProcessAfterInitialization() 확장점이기도 합니다 .

@Component
public class TacyBeanPostProcessor implements BeanPostProcessor {
    
    

	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    
    
		if ("userService".equals(beanName)) {
    
    
			System.out.println("初始化后");
		}

		return bean;
	}
}

이 단계에서는 최종적으로 Bean을 처리하게 되는데, Spring의 AOP는 초기화를 기반으로 구현되며, 초기화 후 반환되는 객체가 최종 Bean 객체이다.

요약BeanPostProcessor

  1. InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation()
  2. 인스턴스화
  3. MergedBeanDefinitionPostProcessor.postProcessMergedBeanDefinition()
  4. InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation()
  5. 자동 주입
  6. InstantiationAwareBeanPostProcessor.postProcessProperties()
  7. 인식 개체
  8. BeanPostProcessor.postProcessBeforeInitialization()
  9. 초기화
  10. BeanPostProcessor.postProcessAfterInitialization()

추천

출처blog.csdn.net/beautybug1126/article/details/132330052