Les principes de base et les concepts de base du code source d'apprentissage Spring


Principes de base

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();

Nous utilisons rarement Spring de la manière ci-dessus, mais utilisons Spring MVC ou Spring Boot, mais ils sont essentiellement basés sur cette méthode et doivent créer un ApplicationContext en interne.

  • SpringBoot crée AnnotationConfigApplicationContext
  • SpringMVC crée XmlWebApplicationContext, basé sur XML similaire à ClassPathXmlApplicationContext.

AnnotationConfigApplicationContext est la classe principale pour la recherche et l'étude

Processus de chargement des conteneurs IoC

Le processus de chargement des conteneurs IoC peut être divisé en deux étapes

  • Préparez et enregistrez certaines classes d'outils d'infrastructure sous-jacentes à utiliser dans le processus d'initialisation du conteneur, puis enregistrez la classe de configuration, puis actualisez le conteneur.
  • Scannez, analysez divers beans configurés dans BeanDefinition et stockez-les dans BeanDefinitionMap
  • Parcourez le BeanDefinitionMap, produisez des singletons et mettez-les en cache dans le pool singleton singletonObjects

Comment créer un objet au printemps

Le processus du nouveau AnnotationConfigApplicationContext(Config.class) est le processus de chargement du conteneur IoC, l'analyse pour générer BeanDefinition, la traversée pour générer un Bean singleton. Enfin, appelez manuellement getBean(beanName) pour obtenir le Bean correspondant du cache.

Processus de création du bean (cycle de vie)

classe -> Réflexion newInstance -> Objet original -> Injection de dépendances (affectation de propriété) -> Un tas de Aware -> Avant l'initialisation (@PostConstruct) -> Initialisation (InitailizedBean) -> Après initialisation (AOP) -> Objet proxy (Proxy objet .target=objet original) -> Bean

  • Instanciation, création d'un objet en appelant un certain constructeur de la classe par réflexion. S'il y a plusieurs constructeurs, une sélection sera effectuée, appelée constructeur déduit.
  • Injection de dépendances (affectation de propriétés), champs traversants dans l'objet, affectation automatique avec @Autowired
  • Tissage conscient, déterminez si l'objet est (c'est-à-dire si la classe est implémentée) BeanNameAware, ApplicationContextAware et autres Aware, si c'est le cas, forcez l'appel à la méthode set définie par la structure
  • Traitement @PostConstruct, déterminez s'il existe une méthode avec cette annotation et si tel est le cas, exécutez la méthode
  • Traitement d'initialisation du Bean, déterminez si l'objet est une instance de l'interface, si tel est le cas, exécutez la méthode afterPropertiesSet définie par l'interface
  • Méthode de méthode d'initialisation personnalisée
  • Déterminez si AOP est nécessaire. Dans le cas contraire, renvoyez l'objet actuel. Si nécessaire, générez un objet proxy et renvoyez-le.
  • S'il s'agit d'un bean singleton, il est stocké dans le pool singleton.

Prototype Singleton

La portée de Bean est divisée en deux types : singleton et prototype.

  • Singleton : chaque fois que getBean obtient le même objet, il sera mis en cache dans le pool singleton après sa première création.
  • Prototype : chaque fois que getBean est créé, il ne sera pas placé dans le pool singleton.

Les beans chargés en différé ne seront pas créés et mis en cache lorsque le conteneur IoC est chargé, mais seront créés et mis en cache lorsqu'ils sont utilisés.

constructeur déduit

Lors de l'instanciation, le constructeur sans paramètre est utilisé par défaut (si des paramètres sont écrits, il n'y aura pas de constructeur sans paramètre par défaut, sauf définition explicite)

S'il existe un constructeur sans paramètre, utilisez le constructeur sans paramètre. S'il n'y a pas de constructeur sans paramètre, déterminez le nombre de constructeurs paramétrés. S'il n'y a qu'un seul constructeur paramétré, utilisez ce constructeur paramétré. S'il existe plusieurs constructeurs sans paramètre, vous ne pouvez pas confirmer lequel utiliser, donc Erreur : le constructeur sans paramètre par défaut est introuvable.

S'il existe plusieurs constructeurs paramétrés, vous pouvez également ajouter @Autowired pour spécifier le constructeur paramétré à utiliser.

D'où vient l'objet paramètre du constructeur paramétré ?

  • Commencez par rechercher le conteneur en fonction de son type. S'il n'y en a qu'un, utilisez-le directement. S'il y en a plusieurs, filtrez en fonction du nom. Si le nom correspond, utilisez-le directement. S'il n'y a pas de correspondance, une erreur sera générée. signalé.

injection de dépendance

Filtrez d'abord le conteneur par type. S'il n'y a qu'une seule correspondance, utilisez-la directement. S'il y a plusieurs correspondances, faites la correspondance par nom. S'il y a une correspondance, utilisez-la directement. S'il n'y a pas de correspondance, une erreur sera signalée. .

Proxy dynamique AOP

Lors de la dernière étape de création du bean, il sera jugé si l'AOP est nécessaire et, si tel est le cas, un proxy dynamique sera utilisé.

Le processus général pour déterminer si l’AOP est nécessaire

  • Trouver tous les haricots d'aspect
  • Parcourez chaque méthode et déterminez si des annotations telles que @Before et @After sont écrites.
  • S'il est écrit, déterminez si le PointCut correspondant correspond au Bean actuellement créé.
  • Si cela correspond, cela signifie que le Bean actuel doit faire de l'AOP.

Le processus général de réalisation d'AOP avec CGLib

  • Génère une classe proxy qui hérite de la classe d'origine. La classe proxy contient la cible de l'objet de classe d'origine. Notez que l'objet de classe d'origine passe par le processus de création du Bean, y compris l'injection de dépendances, l'initialisation et d'autres processus.
  • La classe proxy remplace les méthodes de la classe d'origine et appellera éventuellement la méthode correspondante de la cible, mais ajoutera une logique d'aspect avant et après, à peu près comme suit
  • Le dernier bean créé renvoie un objet proxy contenant l'objet d'origine.
public class UserService {
    
    
	@Autowired
	private OrderService orderService;
	public void test() {
    
    
		sout;
	}
}
class UserServiceProxy extend UserService {
    
    
	UserService target;
	public void test() {
    
    
		// @Before 的逻辑
		target.test();
		// @After 的逻辑
	}
}

La classe proxy hérite de la classe d'origine, donc les champs de la classe d'origine sont également présents dans la classe proxy. Cependant, Spring ne fait pas d'injection de dépendances pour la classe proxy car ce n'est pas nécessaire.

L'objet proxy n'est utilisé que pour améliorer une certaine méthode de l'objet d'origine.Si vous devez utiliser les champs d'injection de dépendances de l'objet d'origine dans la logique d'aspect, vous pouvez également faire fonctionner l'objet d'origine et chaque champ de l'objet d'origine JoinPoint.getTarget(). l'objet a déjà été injecté.

affaires

Après avoir ajouté l'annotation @Transactional à une méthode, une classe proxy et un objet proxy seront générés pour cette classe lors de l'étape AOP.

Le processus de la méthode d'exécution de l'objet proxy de transaction

  • Déterminer s'il existe une annotation @Transactional sur la méthode actuelle
  • Si tel est le cas, le gestionnaire de transactions crée une connexion à la base de données (cette connexion ne vient-elle pas du pool de connexions ?)
  • Définissez l'autoCommit de la connexion sur false (lorsqu'il n'y a pas d'annotation de transaction, la connexion est obtenue à partir du pool de connexions et est automatiquement soumise à chaque fois qu'un SQL est exécuté)
  • Méthode d'exécution, SQL dans la méthode d'exécution
  • Appelez la méthode de validation ou de restauration de la connexion

Raisons pour lesquelles les annotations de transaction doivent expirer

L'échec de la transaction dépend de l'objet qui exécute la méthode d'annotation @Transactional.

  • Objet proxy : n'expirera pas
  • Objet d'origine : invalide, car ce qui est exécuté est une méthode normale et aucune amélioration n'est apportée par l'objet proxy.

L'exemple le plus courant est qu'il existe deux méthodes de transaction a et b dans la classe, et b sera appelé dans a. L'exécution des transactions de a et b séparément ne sera pas invalide, mais lorsque b est exécuté dans a, la configuration sur l'annotation de transaction de b sera invalide

Parce que le processus d'exécution de a est comme ceci, récupérez l'objet proxy de la classe, exécutez son a, passez d'abord par la logique d'aspect, créez la connexion, configurez pour ne pas soumettre automatiquement, puis exécutez target.a, qui est le a méthode de l'objet d'origine, le corps principal à ce moment C'est l'objet d'origine plutôt que l'objet proxy.Lorsque la méthode b est exécutée, l'essence est la suivante.b, le sujet est toujours l'objet d'origine et il n'y a aucun aspect logique, donc la configuration de l'annotation de transaction de la méthode b dans a sera invalide.

Bien entendu, il existe de nombreuses autres raisons qui nécessitent une analyse détaillée.

De nombreux autres échecs AOP ont la même raison, tous causés par un auto-appel.

Il existe une solution, qui est l'auto-référence. La classe dépend de son injection dans self. À ce stade, self est l'objet proxy. Lorsque vous appelez b dans a, utilisez self.b. De cette façon, le corps principal est l'objet proxy. Objet proxy. Il y a des aspects pour renforcer la logique et les affaires de B. La configuration prendra effet

Pourquoi la transaction @Configuration prend-elle effet après l'avoir ajoutée ci-dessous ?

@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();
	}
}
  • Sans ajouter de temps, appeler deux fois dataSource() génère deux sources de données différentes. En fin de compte, le gestionnaire de transactions et le modèle utilisent des sources de données différentes.
  • De plus, il y aura un traitement spécial. dataSource() sera considéré comme un Bean, et le même objet sera passé dans les deux.

Lors de l'obtention d'une connexion dans JdbcTemplate, il vérifiera si le courant est un environnement de transaction. Si tel est le cas, la connexion liée au thread sera obtenue TransactionSynchronizationManager.getResource(dataSource);à partir de la connexion créée par le gestionnaire de transactions. Vous devez utiliser la même source de données objet pour obtenir la même connexion. De cette façon, les opérations de validation et d'annulation du gestionnaire de transactions prendront effet sur le JdbcTemplate.

Idée de base

Il existe de nombreuses abstractions et outils dans le code source Spring, qui doivent être compris à l'avance pour faciliter la lecture du code source.

BeanDéfinition

BeanDefinition est utilisé pour enregistrer diverses informations sur la configuration du Bean.

  • classe, indiquant le type de Bean
  • portée, indiquant la portée du Bean, le singleton ou le prototype, etc.
  • lazyInit : indique si le Bean est chargé paresseux
  • initMethodName : Indique la méthode à exécuter lors de l'initialisation du Bean.
  • destroyMethodName : Indique la méthode à exécuter lorsque le Bean est détruit
  • Il y a beaucoup plus…

Il existe deux manières de définir les beans : déclaratif et programmatique. Les beans définis de différentes manières seront finalement analysés dans BeanDefinition et mis en cache.

  • Déclaration:
    • <haricot/>
    • @Haricot
    • @Composant (@Service,@Contrôleur)
  • Programmatique
    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

Utilisé pour analyser les ressources dans BeanDefinition selon certaines règles

AnnotatedBeanDefinitionReader

Une classe peut être analysée dans un BeanDefinition, y compris des annotations sur la classe (@Conditional, @Scope, @Lazy, @Primary, @DependsOn, @Role, @Description)

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

Peut analyser les beans configurés avec les balises <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, mais sa fonction est similaire à BeanDefinitionReader. Il peut analyser, analyser un certain chemin de package et analyser les classes analysées.

Si l'annotation @Component existe sur la classe analysée, la classe sera analysée dans un BeanDefinition

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

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

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

BeanFactory

L'interface racine du conteneur Spring, la Bean factory, est responsable de la création et de l'obtention des beans, et fournit la définition de diverses méthodes getBean().

DefaultListableBeanFactory

BeanFactory a une classe d'implémentation principale DefaultListableBeanFactory , qui peut être utilisée directement comme BeanFactory et peut être utilisée à la place de ApplicationContext, mais elle a moins de fonctions.

DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();

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

beanFactory.registerBeanDefinition("user", beanDefinition);

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

DefaultListableBeanFactory

L'architecture de DefaultListableBeanFactory est la même que ci-dessus, avec de nombreuses interfaces (capacités) et classes

  • AliasRegistry : prend en charge la fonction alias, définit les fonctions d'enregistrement/acquisition/jugement/suppression de l'alias et prend en charge la fonction d'un BeanDefinition/Bean avec plusieurs noms.
  • SimpleAliasRegistry , maintenu Map<String, String> aliasMap, voici la relation plusieurs-à-un entre l'alias et le beanName, ce qui permet de trouver facilement le nom d'origine à partir de l'alias (les alias peuvent également être alias), bien sûr, vous pouvez également trouver tous les alias de l'original nom
  • BeanDefinitionRegistry : définit les fonctions d'enregistrement/acquisition/existence/suppression de BeanDefinition
  • SingletonBeanRegistry : définit des fonctions telles que l'enregistrement/l'existence/l'obtention/l'obtention de la quantité/l'obtention du nom des beans singleton
  • BeanFactory : Définit les fonctions de Bean telles que l'acquisition/existence/acquisition d'alias/détermination de portée, etc.
  • ListableBeanFactory : étend BeanFactory et fournit des méthodes pour énumérer et récupérer les instances de bean dans le conteneur. Vous pouvez facilement obtenir les noms de tous les beans, obtenir les beans par type et récupérer les beans par conditions.
  • HierarchicalBeanFactory : étend BeanFactory et fournit une structure de conteneur hiérarchique et un mécanisme d'héritage. Chaque sous-conteneur peut gérer indépendamment sa propre définition et instance de bean. Les conteneurs enfants peuvent hériter des beans définis dans le conteneur parent et peuvent remplacer ou étendre les définitions de bean dans le conteneur parent dans le conteneur enfant. Peut obtenir une meilleure modularisation et organisation, et gérer et personnaliser de manière flexible les définitions et les portées des beans
  • AutowireCapableBeanFactory : étend BeanFactory, offre la possibilité d'assembler automatiquement des beans et peut réaliser des fonctions telles que l'injection de dépendances, l'assemblage automatique et le découplage.
  • ConfigurableBeanFactory , en plus de BeanFactory Bean, fournit également des outils pour configurer BeanFactory. Ajout de paramètres pour définir le BeanFactory parent, le chargeur de classe (indiquant qu'un chargeur de classe peut être spécifié pour le chargement des classes) et définir l'analyseur d'expression Spring EL (indiquant que The BeanFactory peut analyser les expressions EL), définir les services de conversion de type (indiquant que BeanFactory peut effectuer la conversion de type), ajouter BeanPostProcessor (indiquant que BeanFactory prend en charge les post-processeurs Bean), fusionner les BeanDefinitions, détruire un Bean, etc.
  • ConfigurableListableBeanFactory : En plus de ConfigurableBeanFactory, il fournit également des outils pour analyser et modifier les définitions de bean et pré-instancier des singletons.
  • DefaultSingletonBeanRegistry : Principalement utilisé pour gérer et maintenir l'enregistrement et l'acquisition des beans singleton, les singletonObjects sont ici
  • FactoryBeanRegistrySupport : Principalement utilisé pour prendre en charge l'enregistrement et l'acquisition de FactoryBean, factoryBeanObjectCache est ici
  • AbstractBeanFactory : La fonction est déjà très complète, mais elle ne peut pas assembler et obtenir automatiquement des beanNames. Les beanPostProcessors sont ici
  • AbstractAutowireCapableBeanFactory : a la fonction d'assemblage automatique
  • DefaultListableBeanFactory : C'est un composant clé du conteneur Spring et est responsable de la gestion de l'enregistrement, de la fusion et de la recherche des BeanDefinitions, ainsi que de la création, de l'assemblage et de la destruction des Beans. Il offre des fonctionnalités riches et des options de configuration flexibles et constitue l'une des implémentations BeanFactory les plus couramment utilisées dans les applications Spring.

Contexte d'application

BeanFactory a une sous-interface principale ApplicationContext , qui est définie comme suit

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

Insérer la description de l'image ici

  • HierarchicalBeanFactory : A pour fonction d'obtenir le BeanFactory parent
  • ListableBeanFactory : A pour fonction d'obtenir des beanNames
  • ResourcePatternResolver : chargeur de ressources, qui peut obtenir plusieurs ressources (ressources de fichiers, etc.) en même temps
  • EnvironmentCapable : peut obtenir l'environnement d'exécution (il n'y a pas de fonction pour définir l'environnement d'exécution)
  • ApplicationEventPublisher : a pour fonction de diffuser des événements (pas de fonction d'ajout d'écouteurs d'événements)
  • MessageSource : possède des capacités d'internationalisation

ApplicationContext se positionne comme le contexte d'application de Spring et est responsable de la gestion et de l'organisation des différentes parties de l'application. Du point de vue du code, ApplicationContext est une BeanFactory. Du point de vue architectural, ApplicationContext est une existence plus avancée que BeanFactory. Il régit BeanFactory. EnvironmentCapable, MessageSource et d'autres composants complètent les fonctions correspondantes, et BeanFactory n'en est qu'une partie.

Selon cette idée, GenericApplicationContext n'hérite pas de DefaultListableBeanFactory mais l'utilise comme attribut.Toutes les fonctions héritées de BeanFactory sont confiées au DefaultListableBeanFactory qu'il détient pour exécution, ce qui est très raisonnable.

L'interface ApplicationContext hérite de ListableBeanFactory et HierarchicalBeanFactory, mais elle se positionne comme une BeanFactory de haut niveau et se concentre uniquement sur un certain degré de fonctions de base de BeanFactory.Elle ne nécessite pas toutes les fonctions plus puissantes et détaillées des couches intermédiaire et inférieure.

ApplicationContext a deux classes d'implémentation importantes

  • AnnotationConfigApplicationContext
  • ClassPathXmlApplicationContext
AnnotationConfigApplicationContext

Insérer la description de l'image ici

  • Lifecycle : Une interface commune qui définit les méthodes de contrôle du cycle de vie de démarrage/arrêt
  • ConfigurableApplicationContext : Ajout, ajout d'écouteurs d'événements, ajout de BeanFactoryPostProcessor, définition de l'environnement, obtention de ConfigurableListableBeanFactory et d'autres fonctions
  • AbstractApplicationContext : implémente la fonction de contexte universel, la fameuse méthode de rafraîchissement est ici
  • GenericApplicationContext : Classe d'implémentation concrète du contexte général de l'application
  • AnnotationConfigRegistry : utilisé pour annoter et configurer le contexte de l'application. Vous pouvez enregistrer une classe en tant que BeanDefinition séparément (peut gérer l'annotation @Configuration @Bean sur cette classe)
  • AnnotationConfigApplicationContext : est une implémentation de contexte d'application pratique et puissante, adaptée au développement basé sur les annotations. Il réalise l'enregistrement et l'assemblage automatisés des Beans en analysant et en traitant les annotations, réduisant ainsi la configuration XML fastidieuse.
ClassPathXmlApplicationContext

Insérer la description de l'image ici
Il hérite également de AbstractApplicationContext, mais comparé à AnnotationConfigApplicationContext, ses fonctions ne sont pas aussi puissantes qu'AnnotationConfigApplicationContext. Par exemple, BeanDefinition ne peut pas être enregistré.

Source de message internationale

Insérer la description de l'image ici

# 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"))); // 你好, 不存在, 走默认
	}
Chargement des ressources 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());
}
Obtenir l'environnement d'exécution
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"));

Remarque : Vous pouvez utiliser @PropertySource("classpath:spring.properties")la méthode pour ajouter des paramètres dans un fichier de propriétés à l'environnement d'exécution.

sortie d'événement
@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("测试事件");
	}

}

conversion de types

Dans le code source Spring, il peut être nécessaire de convertir String en d'autres types, donc le code source Spring fournit certaines technologies pour rendre la conversion de type d'objet plus pratique. Concernant les scénarios d'application de conversion de type, vous le rencontrerez lorsque vous lirez le source code plus tard.

Éditeur de propriétés

Je suppose que tu aimes

Origine blog.csdn.net/mrathena/article/details/132474313
conseillé
Classement