Spring 학습 소스코드의 기본 핵심 원리와 핵심 개념


핵심 원칙

AnnotationConfigApplicationContext

ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
UserService userService = (UserService) context.getBean("userService");
userService.test();
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
UserService userService = (UserService) context.getBean("userService");
userService.test();

위와 같은 방식으로 Spring을 사용하는 경우는 거의 없으며 Spring MVC나 Spring Boot를 사용하지만 기본적으로 이 방법을 기반으로 하고 내부적으로 ApplicationContext를 생성해야 합니다.

  • SpringBoot는 AnnotationConfigApplicationContext를 생성합니다.
  • SpringMVC는 ClassPathXmlApplicationContext와 유사한 xml을 기반으로 하는 XmlWebApplicationContext를 생성합니다.

AnnotationConfigApplicationContext 는 연구 및 학습을 위한 주요 클래스입니다.

IoC 컨테이너 로딩 프로세스

IoC 컨테이너 로딩 프로세스는 두 단계로 나눌 수 있습니다.

  • 컨테이너 초기화 프로세스에 사용할 일부 기본 인프라 도구 클래스를 준비하고 등록한 다음 구성 클래스를 등록하고 컨테이너를 새로 고칩니다.
  • 다양하게 구성된 Bean을 스캔하고 BeanDefinition으로 구문 분석한 후 BeanDefinitionMap에 저장합니다.
  • BeanDefinitionMap을 탐색하고, 싱글톤을 생성하고, 싱글톤 풀에 캐시합니다.

Spring에서 객체를 생성하는 방법

new AnnotationConfigApplicationContext(Config.class)의 프로세스는 IoC 컨테이너의 로딩, BeanDefinition 생성을 위한 스캔, 싱글톤 Bean 생성을 위한 순회, 마지막으로 수동으로 getBean(beanName)을 호출하여 캐시에서 해당 Bean을 가져오는 프로세스입니다.

Bean 생성 프로세스(Life Cycle)

클래스 -> Reflection newInstance -> 원본 객체 -> 종속성 주입(속성 할당) -> Aware 무리 -> 초기화 전(@PostConstruct) -> 초기화(InitailizedBean) -> 초기화 후(AOP) -> 프록시 객체(Proxy) object .target=원본 개체) -> 빈

  • 인스턴스화(Instantiation), 리플렉션을 통해 클래스의 특정 생성자를 호출하여 객체를 생성하는 것입니다. 생성자가 여러 개인 경우 선택이 이루어지는데 이를 유추 생성자라고 합니다.
  • 종속성 주입(속성 할당), 객체의 필드 탐색, @Autowired를 사용한 자동 할당
  • Weaving을 인식하고 객체가 BeanNameAware, ApplicationContextAware 및 기타 Aware인지 여부(즉, 클래스가 구현되었는지 여부)를 확인하고, 그렇다면 구조에 정의된 set 메서드를 강제로 호출합니다.
  • @PostConstruct 처리, 이 주석이 포함된 메서드가 있는지 확인하고 있으면 해당 메서드를 실행합니다.
  • 초기화Bean 처리, 객체가 인터페이스의 인스턴스인지 확인하고, 그렇다면 인터페이스에 정의된 afterPropertiesSet 메소드를 실행합니다.
  • 사용자 정의 초기화 방법 방법
  • AOP가 필요한지 판단하고, 그렇지 않다면 현재 객체를 반환하고, 필요하다면 프록시 객체를 생성하여 반환한다.
  • 싱글톤 Bean인 경우 싱글톤 풀에 저장됩니다.

싱글톤 프로토타입

Bean의 범위는 싱글톤과 프로토타입의 두 가지 유형으로 구분됩니다.

  • 싱글톤: getBean이 동일한 객체를 얻을 때마다 처음 생성된 후 싱글톤 풀에 캐시됩니다.
  • 프로토타입: getBean이 생성될 때마다 싱글톤 풀에 배치되지 않습니다.

지연 로드된 Bean은 IoC 컨테이너가 로드될 때 생성 및 캐시되지 않지만 사용될 때는 생성 및 캐시됩니다.

유추된 생성자

인스턴스화 시 기본적으로 매개변수 없는 생성자가 사용됩니다(매개변수를 작성하면 명시적으로 정의하지 않는 한 기본적으로 매개변수 없는 생성자가 없습니다).

매개변수 없는 생성자가 있으면 매개변수 없는 생성자를 사용하고, 매개변수 없는 생성자가 없으면 매개변수 있는 생성자가 몇 개 있는지 확인하고, 매개변수 있는 생성자가 1개만 있으면 이 매개변수 있는 생성자를 사용하고, 매개변수 없는 생성자가 여러 개 있으면 확인할 수 없다. 어떤 것을 사용해야 합니까? 오류: 매개 변수가 없는 기본 생성자를 찾을 수 없습니다.

매개변수화된 생성자가 여러 개 있는 경우 @Autowired를 추가하여 사용할 매개변수화된 생성자를 지정할 수도 있습니다.

매개변수화된 생성자의 매개변수 객체는 어디에서 왔습니까?

  • 먼저 컨테이너를 종류별로 검색하여 하나만 있으면 바로 사용하고, 여러 개 있으면 이름으로 필터링하고, 이름이 일치하면 바로 사용하고, 일치하는 것이 없으면 에러가 난다. 보고되었습니다.

의존성 주입

먼저 유형별로 컨테이너를 필터링합니다. 일치하는 항목이 하나뿐이면 직접 사용합니다. 일치하는 항목이 여러 개인 경우 이름별로 일치합니다. 일치하는 항목이 있으면 직접 사용합니다. 일치하는 항목이 없으면 오류가 보고됩니다. .

AOP 동적 프록시

Bean을 생성하는 마지막 단계에서 AOP가 필요한지 판단하고, 필요한 경우 동적 프록시를 사용하게 된다.

AOP가 필요한지 여부를 결정하는 일반적인 프로세스

  • 모든 측면 콩 찾기
  • 각 메소드를 순회하여 @Before 및 @After와 같은 주석이 작성되었는지 확인합니다.
  • 작성되었다면 해당 PointCut이 현재 생성된 Bean과 일치하는지 확인합니다.
  • 일치하면 현재 Bean이 AOP를 수행해야 함을 의미합니다.

CGLib로 AOP를 수행하는 일반적인 프로세스

  • 원본 클래스를 상속하는 프록시 클래스를 생성합니다. 프록시 클래스는 원본 클래스 개체 대상을 보유합니다. 원본 클래스 개체는 종속성 주입, 초기화 및 기타 프로세스를 포함하여 Bean 생성 프로세스를 거칩니다.
  • 프록시 클래스는 원래 클래스의 메서드를 재정의하고 결국 대상의 해당 메서드를 호출하지만 대략 다음과 같이 전후에 측면 로직을 추가합니다.
  • 생성된 마지막 빈은 원본 객체를 보유하는 프록시 객체를 반환합니다.
public class UserService {
    
    
	@Autowired
	private OrderService orderService;
	public void test() {
    
    
		sout;
	}
}
class UserServiceProxy extend UserService {
    
    
	UserService target;
	public void test() {
    
    
		// @Before 的逻辑
		target.test();
		// @After 的逻辑
	}
}

프록시 클래스는 원본 클래스를 상속하므로 원본 클래스의 필드가 프록시 클래스에도 존재하지만 Spring에서는 필요하지 않기 때문에 프록시 클래스에 대한 종속성 주입을 수행하지 않습니다.

JoinPoint.getTarget()프록시 객체는 원본 객체의 특정 메소드를 향상시키는 데에만 사용됩니다.Aspect 로직에서 원본 객체의 종속성 주입 필드를 사용해야 하는 경우 원본 객체를 작동시키고 원본의 각 필드를 가져올 수도 있습니다. 개체가 이미 주입되었습니다.

사무

@Transactional 주석을 메소드에 추가한 후 AOP 단계에서 이 클래스에 대한 프록시 클래스 및 프록시 객체가 생성됩니다.

트랜잭션 프록시 객체 실행 과정 과정

  • 현재 메소드에 @Transactional 주석이 있는지 확인
  • 그렇다면 트랜잭션 관리자는 데이터베이스 연결을 생성합니다. (이 연결은 연결 풀에서 나오지 않습니까?)
  • 연결의 autoCommit을 false로 설정(트랜잭션 주석이 없는 경우 연결 풀에서 연결을 얻어 SQL이 실행될 때마다 자동으로 제출됨)
  • 실행 방법, 실행 방법의 SQL
  • 연결의 커밋 또는 롤백 메서드 호출

트랜잭션 주석이 만료되도록 예약된 이유

트랜잭션이 실패할지 여부는 @Transactional 주석 메서드를 실행하는 객체에 따라 다릅니다.

  • 프록시 개체: 만료되지 않습니다.
  • 원본 개체: 실행되는 내용이 일반적인 메서드이고 프록시 개체에 의한 개선 사항이 없기 때문에 유효하지 않습니다.

가장 일반적인 예는 클래스에 a와 b의 두 가지 트랜잭션 메소드가 있고 a에서 b가 호출되는 것입니다. a와 b의 트랜잭션을 별도로 실행하는 것은 유효하지 않지만 b가 a에서 실행될 때의 구성은 다음과 같습니다. b의 트랜잭션 주석은 유효하지 않습니다.

a를 실행하는 과정은 이렇기 때문에 클래스의 프록시 객체를 얻어서 a를 실행하고 먼저 Aspect 로직을 거쳐 Connection을 생성하고 자동으로 submit되지 않도록 설정한 후 a인 target.a를 실행한다. 원본 객체의 메소드, 이때 본체는 프록시 객체가 아닌 원본 객체이고, b 메소드가 실행되면 본질은 this.b이고, 주체는 여전히 원본 객체이고, 양상은 없다. 따라서 a에서 b 메소드의 트랜잭션 주석 구성은 유효하지 않습니다.

물론 이 밖에도 상세한 분석이 필요한 이유는 많이 있습니다.

다른 많은 AOP 실패도 같은 이유를 갖고 있으며 모두 자체 호출로 인해 발생합니다.

self-reference라는 해결 방법이 있습니다. 클래스는 self에 자신을 주입하는 것에 의존합니다. 이때 self는 프록시 객체입니다. a에서 b를 호출할 때는 self.b를 사용합니다. 이런 식으로 본체는 프록시 객체입니다. 로직과 b의 업무를 강화하는 측면이 있습니다. 구성이 적용됩니다.

@Configuration 트랜잭션을 아래에 추가한 후 왜 적용됩니까?

@Configuration
public class Config {
    
    
	@Bean
	public TransactionManager transationManager() {
    
    
		return new DataSourceTransactionManager(dataSource());
	}
	@Bean
	public JdbcTemplate jdbcTemplate() {
    
    
		return new JdbcTemplate(dataSource())
	}
	@Bean
	public DataSource dataSource() {
    
    
		return new DataSource();
	}
}
  • 시간을 추가하지 않고 dataSource()를 두 번 호출하면 서로 다른 두 개의 데이터 소스가 생성되며 결국 트랜잭션 관리자와 템플릿은 서로 다른 데이터 소스를 사용하게 됩니다.
  • 또한 특별한 처리가 있는데, dataSource()는 Bean으로 간주되어 동일한 객체가 둘 다에 전달됩니다.

JdbcTemplate에서 연결을 획득할 때 현재가 트랜잭션 환경인지 확인하고, 그렇다면 스레드 바인딩된 연결은 트랜잭션 관리자가 생성한 연결인 TransactionSynchronizationManager.getResource(dataSource);에서 동일한 연결을 얻기 위한 개체 이러한 방식으로 트랜잭션 관리자의 커밋 및 롤백 작업이 JdbcTemplate에 적용됩니다.

핵심 아이디어

Spring 소스 코드에는 많은 추상화와 도구가 있으며, 소스 코드를 더 쉽게 읽을 수 있도록 미리 이해해야 합니다.

콩정의

BeanDefinition은 Bean 구성에 대한 다양한 정보를 기록하는 데 사용됩니다.

  • Bean 유형을 나타내는 클래스
  • Bean 범위, 싱글톤 또는 프로토타입 등을 나타내는 범위.
  • lazyInit: Bean이 지연 로드되었는지 여부를 나타냅니다.
  • initMethodName: Bean이 초기화될 때 실행될 메소드를 나타냅니다.
  • destroyMethodName: Bean이 파기될 때 실행될 메소드를 나타냅니다.
  • 더 많은 것이 있습니다…

Bean을 정의하는 방법에는 선언적 방식과 프로그래밍 방식이 있으며, 다양한 방식으로 정의된 Bean은 결국 BeanDefinition으로 파싱되어 캐시됩니다.

  • 선언:
    • < 콩/>
    • @콩
    • @Component(@서비스,@컨트롤러)
  • 프로그래밍 방식
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
    
    // 生成一个BeanDefinition对象,并设置beanClass为User.class,并注册到ApplicationContext中
    AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
    beanDefinition.setBeanClass(User.class);
    context.registerBeanDefinition("user", beanDefinition);
    
    System.out.println(context.getBean("user"));
    

BeanDefinitionReader

특정 규칙에 따라 리소스를 BeanDefinition으로 구문 분석하는 데 사용됩니다.

AnnotatedBeanDefinitionReader

클래스에 대한 주석(@Conditional, @Scope, @Lazy, @Primary, @DependsOn, @Role, @Description)을 포함하여 클래스를 BeanDefinition으로 구문 분석할 수 있습니다.

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

AnnotatedBeanDefinitionReader reader = new AnnotatedBeanDefinitionReader(context);

// 将User.class解析为BeanDefinition
reader.register(User.class);

System.out.println(context.getBean("user"));

XmlBeanDefinitionReader

<bean/> 태그로 구성된 Bean을 구문 분석할 수 있습니다.

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(context);
int i = reader.loadBeanDefinitions("spring.xml");

System.out.println(context.getBean("user"));

ClassPathBeanDefinitionScanner

Scanner이지만 그 기능은 BeanDefinitionReader와 유사하며 특정 패키지 경로를 스캔하고 스캔한 클래스를 구문 분석할 수 있습니다.

스캔된 클래스에 @Component 주석이 존재하는 경우 해당 클래스는 BeanDefinition으로 구문 분석됩니다.

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.refresh();

ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context);
scanner.scan("com.coder");

System.out.println(context.getBean("userService"));

콩공장

Spring 컨테이너의 루트 인터페이스인 Bean 팩토리는 Bean을 생성하고 획득하는 역할을 담당하며 다양한 getBean() 메서드의 정의를 제공합니다.

DefaultListableBeanFactory

BeanFactory 에는 BeanFactory로 직접 사용할 수 있고 ApplicationContext 대신 사용할 수 있는 핵심 구현 클래스 DefaultListableBeanFactory 가 있지만 기능이 더 적습니다.

DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();

AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
beanDefinition.setBeanClass(User.class);

beanFactory.registerBeanDefinition("user", beanDefinition);

System.out.println(beanFactory.getBean("user"));

DefaultListableBeanFactory

DefaultListableBeanFactory의 아키텍처는 위와 같으며 많은 인터페이스(기능)와 클래스가 있습니다.

  • AliasRegistry : Alias ​​기능을 지원하고, Alias의 등록/획득/판단/제거 기능을 정의하며, 여러 이름을 갖는 BeanDefinition/Bean의 기능을 지원한다.
  • 유지되는 SimpleAliasRegistry는Map<String, String> aliasMap 별칭과 beanName 사이의 다대일 관계입니다. 이를 통해 별칭에서 원래 이름을 쉽게 찾을 수 있습니다(별칭도 별칭일 수 있음). 물론 원본에서 모든 별칭도 찾을 수 있습니다. 이름
  • BeanDefinitionRegistry : BeanDefinition의 등록/획득/존재/제거 기능을 정의한다.
  • SingletonBeanRegistry : 싱글톤 빈의 등록/존재/수량 가져오기/가져오기/이름 가져오기 등의 기능을 정의합니다.
  • BeanFactory : 획득/존재/별칭 획득/범위 결정 등 Bean의 기능을 정의합니다.
  • ListableBeanFactory : BeanFactory를 확장하고 컨테이너 내 Bean 인스턴스를 열거하고 검색하는 메소드를 제공하며, 모든 Bean의 이름을 쉽게 가져오고, 유형별로 Bean을 가져오고, 조건별로 Bean을 검색할 수 있습니다.
  • HierarchicalBeanFactory : BeanFactory를 확장하고 계층적 컨테이너 구조와 상속 메커니즘을 제공하며, 각 하위 컨테이너는 자신의 Bean 정의와 인스턴스를 독립적으로 관리할 수 있습니다. 하위 컨테이너는 상위 컨테이너에 정의된 Bean을 상속할 수 있으며 하위 컨테이너의 상위 컨테이너에 있는 Bean 정의를 대체하거나 확장할 수 있습니다. 더 나은 모듈화 및 구성을 달성하고 Bean 정의 및 범위를 유연하게 관리 및 사용자 정의할 수 있습니다.
  • AutowireCapableBeanFactory : BeanFactory를 확장하고 Bean을 자동으로 조립하는 기능을 제공하며 종속성 주입, 자동 조립 및 분리와 같은 기능을 실현할 수 있습니다.
  • ConfigurableBeanFactory 는 BeanFactory Bean 외에 BeanFactory를 구성하기 위한 도구도 제공합니다. 부모 BeanFactory 설정, 클래스 로더(클래스 로딩을 위해 클래스 로더를 지정할 수 있음을 나타냄) 및 Spring EL 표현식 파서(BeanFactory가 다음을 수행할 수 있음을 나타냄) 설정을 위한 설정을 추가했습니다. EL 표현식 구문 분석), 유형 변환 서비스 설정(BeanFactory가 유형 변환을 수행할 수 있음을 나타냄), BeanPostProcessor 추가(BeanFactory가 Bean 후처리기를 지원함을 나타냄), BeanDefinitions 병합, Bean 삭제 등 기능
  • ConfigurableListableBeanFactory : ConfigurableBeanFactory 외에도 Bean 정의를 분석 및 수정하고 싱글톤을 사전 인스턴스화하기 위한 도구도 제공합니다.
  • DefaultSingletonBeanRegistry : 주로 싱글톤 Bean의 등록 및 획득을 관리하고 유지하는 데 사용되며, SingletonObjects가 여기에 있습니다.
  • FactoryBeanRegistrySupport : 주로 FactoryBean 등록 및 획득을 지원하는 데 사용되며, FactoryBeanObjectCache는 여기에 있습니다.
  • AbstractBeanFactory : 이 함수는 이미 매우 포괄적이지만 beanNames를 자동으로 조립하고 얻을 수 없습니다. beanPostProcessors는 여기에 있습니다.
  • AbstractAutowireCapableBeanFactory : 자동 조립 기능이 있습니다.
  • DefaultListableBeanFactory : Spring 컨테이너의 핵심 구성 요소이며 BeanDefinitions의 등록, 병합 및 검색은 물론 Bean의 생성, 조립 및 파괴를 관리합니다. 풍부한 기능과 유연한 구성 옵션을 제공하며 Spring 애플리케이션에서 일반적으로 사용되는 BeanFactory 구현 중 하나입니다.

애플리케이션컨텍스트

BeanFactory 에는 다음과 같이 정의된 핵심 하위 인터페이스 ApplicationContext가 있습니다.

public interface ApplicationContext 
extends EnvironmentCapable, 
ListableBeanFactory, 
HierarchicalBeanFactory, 
MessageSource, 
ApplicationEventPublisher, 
ResourcePatternResolver

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

  • HierarchicalBeanFactory: 상위 BeanFactory를 얻는 기능을 가지고 있습니다.
  • ListableBeanFactory: beanNames을 얻는 기능이 있습니다.
  • ResourcePatternResolver: 한 번에 여러 리소스(파일 리소스 등)를 얻을 수 있는 리소스 로더
  • EnvironmentCapable : 런타임 환경을 얻을 수 있음 (런타임 환경을 설정하는 기능은 없음)
  • ApplicationEventPublisher: 이벤트를 방송하는 기능이 있습니다. (이벤트 리스너를 추가하는 기능은 없습니다.)
  • MessageSource: 국제화 기능이 있습니다.

ApplicationContext는 Spring의 애플리케이션 컨텍스트로 위치하며 애플리케이션의 다양한 부분을 관리하고 구성하는 역할을 담당하며, 코드 수준에서 보면 ApplicationContext는 BeanFactory이고, 아키텍처 수준에서 보면 ApplicationContext는 BeanFactory보다 더 발전된 존재로 BeanFactory를 관리한다. EnvironmentCapable, MessageSource 및 기타 구성요소는 해당 기능을 완성하며 BeanFactory는 그 일부일 뿐입니다.

이 아이디어에 따르면 GenericApplicationContext는 DefaultListableBeanFactory를 상속하지 않고 속성으로 사용하며 BeanFactory에서 상속된 모든 함수는 실행을 위해 자신이 보유한 DefaultListableBeanFactory에 위임되는데 이는 매우 합리적입니다.

ApplicationContext 인터페이스는 ListableBeanFactory와 HierarchicalBeanFactory를 상속하지만 상위 BeanFactory로 위치하여 BeanFactory의 어느 정도 기본 기능에만 초점을 맞추고 있으며, 중간층과 하위층의 더 강력하고 세부적인 기능을 모두 요구하지는 않는다.

ApplicationContext에는 두 가지 중요한 구현 클래스가 있습니다.

  • AnnotationConfigApplicationContext
  • ClassPathXmlApplicationContext
AnnotationConfigApplicationContext

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

  • Lifecycle : 시작/중지 수명주기 제어 방법을 정의하는 공통 인터페이스
  • ConfigurableApplicationContext : 이벤트 리스너 추가, BeanFactoryPostProcessor 추가, 환경 설정, ConfigurableListableBeanFactory 획득 및 기타 기능 추가
  • AbstractApplicationContext : 범용 컨텍스트 기능을 구현합니다. 유명한 새로 고침 방법은 여기에 있습니다.
  • GenericApplicationContext : 일반 애플리케이션 컨텍스트 구체적인 구현 클래스
  • AnnotationConfigRegistry : 애플리케이션 컨텍스트에 주석을 달고 구성하는 데 사용됩니다. 클래스를 별도로 BeanDefinition으로 등록할 수 있습니다(이 클래스에서 @Configuration @Bean 주석을 처리할 수 있음).
  • AnnotationConfigApplicationContext : 주석 기반 개발에 적합한 편리하고 강력한 애플리케이션 컨텍스트 구현입니다. 주석을 스캔하고 처리하여 자동화된 Bean 등록 및 어셈블리를 실현하여 지루한 XML 구성을 줄입니다.
ClassPathXmlApplicationContext

여기에 이미지 설명을 삽입하세요.
AbstractApplicationContext도 상속하지만 AnnotationConfigApplicationContext에 비해 그 기능은 AnnotationConfigApplicationContext만큼 강력하지 않다.예를 들어 BeanDefinition을 등록할 수 없다.

국제 메시지 출처

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

# messages.properties
test = 你好啊
# messages_en_US.properties
test = Hello
# messages_zh_CN.properties
test = 你好
@Configuration
public class MessageSourceConfig {
    
    

	@Bean
	public MessageSource messageSource() {
    
    
		ResourceBundleMessageSource resourceBundleMessageSource = new ResourceBundleMessageSource();
		resourceBundleMessageSource.setDefaultEncoding("UTF-8");
		resourceBundleMessageSource.setBasename("i18n.messages");
		return resourceBundleMessageSource;
	}

}
	public static void main(String[] args) {
    
    
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Main.class);
		System.out.println(Locale.getDefault()); // zh_CN
		System.out.println(context.getMessage("test", null, Locale.getDefault())); // 你好
		System.out.println(context.getMessage("test", null, new Locale("zh_CN"))); // 你好
		System.out.println(context.getMessage("test", null, new Locale("en_US"))); // Hello
		System.out.println(context.getMessage("test", null, new Locale("de_DE"))); // 你好, 不存在, 走默认
	}
리소스 로드 getResource/getResources
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Main.class);

Resource resource1 = context.getResource("file:/C:/coder/develop/workspace/idea/mrathena/spring/spring-analyze-test/src/main/java/com/coder/UserService.java");
System.out.println(resource1.contentLength());
System.out.println(resource1.getFilename());

Resource resource2 = context.getResource("https://www.baidu.com");
System.out.println(resource2.contentLength());
System.out.println(resource2.getURL());

// Resource resource3 = context.getResource("classpath:spring.xml");
// System.out.println(resource3.contentLength());
// System.out.println(resource3.getURL());

Resource[] resources = context.getResources("classpath:com/coder/**/*.class");
for (Resource resource : resources) {
    
    
	System.out.println(resource.contentLength());
	System.out.println(resource.getFilename());
}
런타임 환경 가져오기
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Main.class);

Map<String, Object> systemEnvironment = context.getEnvironment().getSystemEnvironment();
for (Map.Entry<String, Object> entry : systemEnvironment.entrySet()) {
    
    
	System.out.println(entry.getKey() + "\t\t" + entry.getValue());
}

System.out.println("=======");

Map<String, Object> systemProperties = context.getEnvironment().getSystemProperties();
for (Map.Entry<String, Object> entry : systemProperties.entrySet()) {
    
    
	System.out.println(entry.getKey() + "\t\t" + entry.getValue());
}

System.out.println("=======");

// 会包含所有的属性源, 包括上面的 SystemEnvironment 和 SystemProperties
MutablePropertySources propertySources = context.getEnvironment().getPropertySources();
for (PropertySource<?> propertySource : propertySources) {
    
    
	System.out.println(propertySource);
}

System.out.println("=======");

System.out.println(context.getEnvironment().getProperty("NO_PROXY"));
System.out.println(context.getEnvironment().getProperty("sun.jnu.encoding"));
System.out.println(context.getEnvironment().getProperty("Path"));

참고: @PropertySource("classpath:spring.properties")이 메소드를 사용하여 속성 파일의 매개변수를 런타임 환경에 추가할 수 있습니다.

이벤트 출시
@ComponentScan
@Configuration
public class ApplicationListenerTest {
    
    

	@Bean
	public ApplicationListener<ApplicationEvent> applicationListener() {
    
    
		return event -> {
    
    
			System.out.println();
            System.out.println("接收到了一个事件\t\t" + event.getClass());
            System.out.println(event);
			if (event instanceof PayloadApplicationEvent) {
    
    
				System.out.println(((PayloadApplicationEvent) event).getPayload());
			}
        };
	}

	public static void main(String[] args) {
    
    
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ApplicationListenerTest.class);
		context.publishEvent("测试事件");
	}

}

유형 변환

Spring 소스 코드에서는 String을 다른 유형으로 변환해야 할 수 있으므로 Spring 소스 코드는 객체 유형 변환을 보다 편리하게 만드는 몇 가지 기술을 제공합니다. 유형 변환의 응용 시나리오에 대해서는 소스를 읽을 때 직면하게 됩니다. 나중에 코드를 작성하세요.

속성편집기

추천

출처blog.csdn.net/mrathena/article/details/132474313