[Spring-Thema] Analyse der Kernkonzepte der zugrunde liegenden Architektur von Spring

Vorwort

Der Inhalt dieser Lektion ist das Konzept und die Klasse, die für das anschließende Lesen des Spring-Quellcodes erforderlich sind. Wenn Sie beim anschließenden Lesen des Quellcodes auf etwas stoßen, das Sie nicht wissen oder verstehen, müssen Sie herausspringen und lerne es alleine. Daher verfügt jeder über ein gutes Verständnis dieser Konzepte, was zukünftigen Schülern beim Lesen des Quellcodes sehr helfen kann.
Es gibt noch einen weiteren Bedarfbesondere Aussage::
Die Rolle der Schnittstelle wird manchmal dazu genutzt, Verhalten einzuschränken und zu regulieren. Hervorragender Quellcode wie Spring wird gemäß der Schnittstellenbeschreibung ausgeführt. Daher kann uns die Betrachtung von Schnittstellenanmerkungen helfen, die Fähigkeiten einer bestimmten Klasse zu verstehen!
Erinnern!
Erinnern!
Erinnern!
Erinnern!
Erinnern!
Erinnern!

Vorwissen


Sie können sich zuerst die beiden vorherigen Artikel ansehen . Ich persönlich denke, dass dies die Erleuchtung des Spring- Quellcode - Lernens ist .

Kursinhalte

1. BeanDefinition: Zeichnungen

BeanDefinitionStellt die Bean-Definition dar, BeanDefinitionfür die es viele Attribute gibtBeschreiben Sie die Eigenschaften einer Bohne. Zum Beispiel:

  • Klasse, die den Bean-Typ angibt
  • Bereich, der den Bean-Bereich, Singleton oder Prototyp usw. angibt.
  • lazyInit: Gibt an, ob die Bean verzögert geladen wird
  • initMethodName: Gibt die Methode an, die ausgeführt werden soll, wenn die Bean initialisiert wird
  • destroyMethodName: Gibt die Methode an, die ausgeführt werden soll, wenn die Bean zerstört wird
  • Und viele mehr... (Bild unten)
    Fügen Sie hier eine Bildbeschreibung ein

Im Frühling definieren wir Bohnen oft auf folgende Weise:

  1. <bean>-Tag in XML
  2. Kommentiert @Bean
  3. Anmerkungen zur @Component-Serie (@Service, @Controller)

Das Obige nennen wir: [deklarative Definition von Bean]
Wir können es auch [programmatische Definition von Bean], also direkt über BeanDefinition, zum Beispiel:

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

Wir können über BeanDefinition auch andere Eigenschaften einer Bean festlegen:

beanDefinition.setScope("prototype"); // 设置作用域
beanDefinition.setInitMethodName("init"); // 设置初始化方法
beanDefinition.setLazyInit(true); // 设置懒加载

Kurz gesagt, unabhängig davon, wie die Bean definiert ist, wird sie schließlich von Spring in das entsprechende BeanDefinition-Objekt analysiert und in den Spring-Container gestellt.
Um es für jeden einfacher zu machen, die Existenz dieser Sache zu verstehen, werde ich ein beliebtes Beispiel wie folgt geben:

BeanDefinitionDie Existenz der Möbel ähnelt eher einer individuellen Möbelzeichnung, Beanalso einem bestimmten Möbelstück. Im Frühling handelt es sich, wie wir später erfahren werden ApplicationContext, um den Möbelhersteller. Mit dieser Analogie sollten Sie verstehen, warum Sie BeanDefinition benötigen.
Um einen Satz zusammenzufassen: ApplicationContext-Hersteller generieren eine bestimmte Möbel-Bean gemäß der BeanDefinition-Zeichnung(PS: ApplicationContext enthält BeanFactory, das sind alles Bean-Fabriken)

Zweitens: BeanDefinitionReader: Zeichnungsregister – eine der Spring-Factory-Infrastrukturen

BeanDefinitionReader, wörtlich übersetzt: BeanDefinition-Leser, aber das ist eigentlich so etwas wie eine englische semantische Gewohnheit. Ich schlage vor, dass Sie es als [Parser], [Register] und [Generator] verstehen. Diese BeanDefinitionReader werden weniger verwendet, wenn wir Spring verwenden, aber mehr im Spring-Quellcode, der der Infrastruktur des Spring-Quellcodes entspricht. Es handelt sich um eine Schnittstelle, die verschiedene Implementierungsklassen bereitstellt.
(PS: Tatsächlich übersetze ich es lieber als [Parser], aber ich habe festgestellt, dass viele unerfahrene Freunde über das Konzept von [Analyse] etwas verwirrt sind, hauptsächlich weil der Begriff [Analyse] an vielen Stellen vorkommt. Tatsächlich im Programm Im Design interpretiert [Parsing] normalerweise eine Sache als eine andere, aber normalerweise hängen diese beiden Dinge zusammen, das ist alles. Hier interpretiert es die .classin der Datei definierte Klasse als BeanDfinition)
Fügen Sie hier eine Bildbeschreibung ein

Wie gesagt, BeanDefinitionReader ist ein Zeichenregister, aber da es verschiedene Werkzeuge zum Zeichnen von Zeichnungen gibt, gibt es auch verschiedene Register. Lassen Sie mich Ihnen eine kurze Einführung geben.
(PS: Ein ausgezeichneter Quellcode sollte so aussehen. Sie können die Funktion anhand des Namens erkennen. Sie ist optisch ansprechend.)

2.1 AnnotatedBeanDefinitionReader

Sie können eine Klasse direkt in BeanDefinition konvertieren und die Anmerkungen zur Klasse analysieren, z. B.:

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

AnnotatedBeanDefinitionReader annotatedBeanDefinitionReader = new AnnotatedBeanDefinitionReader(context);

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

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

Hinweis: Die Anmerkungen, die analysiert werden können, sind: @Conditional, @Scope, @Lazy, @Primary, @DependsOn, @Role, @Description

2.2 XmlBeanDefinitionReader

Das <bean/>-Tag kann beispielsweise analysiert werden:

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

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

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

2.3 ClassPathBeanDefinitionScanner

grundlegende Einführung

ClassPathBeanDefinitionScanner ist ein Scanner, aber seine Funktion ähnelt BeanDefinitionReader. Er kann scannen, einen Paketpfad scannen und die gescannte Klasse analysieren. Wenn beispielsweise eine @Component-Annotation für die gescannte Klasse vorhanden ist, wird diese Klasse in eine BeanDefinition geparst.
Die offizielle Definition und Anmerkungen lauten wie folgt:

/**
 * 一个bean定义扫描器,它检测类路径上的候选bean,用给定的注册中心(BeanFactory或ApplicationContext)注册相应的bean定义。
 * 候选类是通过可配置的类型筛选器检测的。默认过滤器包括用Spring的@Component、@Repository、@Service或@Controller构造型注释的类。
 * 还支持Java EE 6的javax.annotation.ManagedBean和JSR-330的javax.inject.Named注释(如果可用)。
 */
public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateComponentProvider {
    
    
}

Zusammenfassen

Aus der obigen Definition kann es wie folgt zusammengefasst werden:

  1. Es handelt sich um einen Bean-Definitionsscanner
  2. Im Standard-Scanpfad Klassen, die @Component-, @Repository-, @Service- oder @Controller-Stereotypanmerkungen enthalten. Unterstützt auch die Annotationen javax.annotation.ManagedBean von Java EE 6 und javax.inject.Named von JSR-330

Anwendungsbeispiel

Das Codebeispiel lautet wie folgt:

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

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

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

3. BeanFactory: Produktionslinie – eine der Spring-Infrastrukturen

BeanFactory bedeutet Bean-Factory, daher ist BeanFactory offensichtlich für die Erstellung von Beans verantwortlich und stellt eine API für den Erhalt von Beans bereit. Der ApplicationContext ist eine Art BeanFactory, die später vorgestellt wird.

Im Spring-Quellcode gibt es eine sehr wichtige Implementierungsklasse der BeanFactory-Schnittstelle: DefaultListableBeanFactory, die ebenfalls sehr wichtig ist . Die besondere Bedeutung wird in den Folgekursen noch deutlicher zum Ausdruck kommen.
Daher können wir DefaultListableBeanFactory direkt verwenden, anstatt eine Implementierungsklasse von ApplicationContext zu verwenden, wie zum Beispiel:

DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();

// 注册一个Bean定义
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
beanDefinition.setBeanClass(User.class);
beanFactory.registerBeanDefinition("user", beanDefinition);

// 生产
System.out.println(beanFactory.getBean("user"));

DefaultListableBeanFactory ist sehr leistungsstark und unterstützt viele Funktionen. Sie können es sehen, indem Sie sich die Implementierungsstruktur der Klassenvererbung von DefaultListableBeanFactory ansehen: Es macht
Fügen Sie hier eine Bildbeschreibung ein
nichts, wenn Sie diesen Teil jetzt nicht verstehen, Sie können ihn sich noch einmal ansehen, nachdem Sie sich damit vertraut gemacht haben mit dem Quellcode. Es implementiert viele Schnittstellen, was darauf hinweist, dass es viele Funktionen hat:

  1. AliasRegistry: unterstützt die Alias-Funktion, ein Name kann mehreren Aliasen entsprechen
  2. BeanDefinitionRegistry: Sie können eine BeanDefinition registrieren, speichern, entfernen und abrufen
  3. BeanFactory: Bean Factory, Sie können ein Bean-Objekt entsprechend dem Namen, Typ oder Alias ​​einer Bean erhalten
  4. SingletonBeanRegistry: Sie können sich direkt registrieren und eine Singleton-Bean erhalten
  5. SimpleAliasRegistry: Es handelt sich um eine Klasse, die die in der AliasRegistry-Schnittstelle definierten Funktionen implementiert und die Alias-Funktion unterstützt
  6. ListableBeanFactory: Basierend auf BeanFactory werden weitere Funktionen hinzugefügt: Sie können die BeanNames aller BeanDefinitionen abrufen, die entsprechenden BeanNames gemäß einem bestimmten Typ abrufen und die Zuordnungsbeziehung von {Typ: entsprechende Bean} gemäß einem bestimmten Typ abrufen
  7. HierarchicalBeanFactory: Basierend auf BeanFactory wird die Funktion zum Abrufen der übergeordneten BeanFactory hinzugefügt
  8. DefaultSingletonBeanRegistry: Es handelt sich um eine Klasse, die die SingletonBeanRegistry-Schnittstelle implementiert und die Funktion hat, eine Singleton-Bean direkt zu registrieren und abzurufen
  9. ConfigurableBeanFactory: Fügen Sie auf der Grundlage von HierarchicalBeanFactory und SingletonBeanRegistry die übergeordnete BeanFactory-Einstellung, den Klassenlader (der angibt, dass ein bestimmter Klassenlader zum Laden der Klasse angegeben werden kann) und den Spring EL-Ausdrucksparser (der angibt, dass BeanFactory EL-Ausdrücke analysieren kann) und den Typsatz hinzu Konvertierungsdienst (zeigt an, dass die BeanFactory eine Typkonvertierung durchführen kann), kann BeanPostProcessor hinzufügen (zeigt an, dass die BeanFactory den Bean-Postprozessor unterstützt), kann BeanDefinition zusammenführen, eine Bean zerstören usw.
  10. FactoryBeanRegistrySupport: Unterstützt die Funktion von FactoryBean
  11. AutowireCapableBeanFactory: Es erbt BeanFactory direkt und unterstützt auf Basis von BeanFactory die automatische Zusammenstellung von Beans beim Erstellen von Beans
  12. AbstractBeanFactory: Implementiert die ConfigurableBeanFactory-Schnittstelle und erbt FactoryBeanRegistrySupport. Diese BeanFactory verfügt über umfassende Funktionen, kann jedoch BeanNames nicht automatisch zusammenstellen und abrufen
  13. ConfigurableListableBeanFactory: Beispiele für ListableBeanFactory, AutowireCapableBeanFactory und ConfigurableBeanFactory
  14. AbstractAutowireCapableBeanFactory: erbt AbstractBeanFactory, implementiert AutowireCapableBeanFactory und verfügt über die Funktion der automatischen Montage
  15. DefaultListableBeanFactory: erbt AbstractAutowireCapableBeanFactory und implementiert die Schnittstelle ConfigurableListableBeanFactory und die Schnittstelle BeanDefinitionRegistry, sodass DefaultListableBeanFactory sehr leistungsstark ist

*4, ApplicationContext: Produktionswerkstatt – eine der Spring-Infrastrukturen

ApplicationContext ist eine Schnittstelle und eigentlich eine BeanFactory, aber leistungsfähiger als BeanFactory.
Wenn wir in der Quellcode-Implementierung von Spring einen neuen ApplicationContext erstellen, wird auf der unteren Ebene eine BeanFactory erstellt. Bei Verwendung einiger Methoden von ApplicationContext, wie z. B. getBean(), ruft die untere Ebene die getBean()-Methode von BeanFactory auf. Es ist wie folgt definiert:

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

            ...
}

PS: Durch die oben genannten Punkte sollte jeder in der Lage sein, den Unterschied ApplicationContextzwischen den beiden ungefähr zu erkennen, BeanFactoryoder? Dies ist einer der Testpunkte für das Frühjahrsinterview..
Offensichtlich verfügt ApplicationContext über die Fähigkeiten von BeanFactory und umfangreichere Funktionen . Einzelheiten wie folgt:

  1. HierarchicalBeanFactory: hat die Funktion, die übergeordnete BeanFactory abzurufen
  2. ListableBeanFactory: hat die Funktion, BeanNames abzurufen
  3. ResourcePatternResolver: Ressourcenlader, der mehrere Ressourcen (Dateiressourcen usw.) gleichzeitig abrufen kann
  4. EnvironmentCapable: Die Laufzeitumgebung kann abgerufen werden (die Laufzeitumgebungsfunktion ist nicht festgelegt).
  5. ApplicationEventPublisher: hat die Funktion, Ereignisse zu übertragen (keine Funktion zum Hinzufügen von Ereignis-Listenern)
  6. MessageSource: verfügt über eine Internationalisierungsfunktion

Es folgen konkrete Funktionsdemonstrationen.

Schauen wir uns zunächst zwei wichtige Implementierungsklassen von ApplicationContext an:

  • AnnotationConfigApplicationContext
  • ClassPathXmlApplicationContext

4.1 AnnotationConfigApplicationContext

Fügen Sie hier eine Bildbeschreibung ein
Wie in der Abbildung oben gezeigt, erbt AnnotationConfigApplicationContext die oben genannten Klassen und sollte daher über die Fähigkeiten der oben genannten Klassen verfügen. Sie sind wie folgt:

  1. ConfigurableApplicationContext: erbt die ApplicationContext-Schnittstelle, fügt Funktionen hinzu, z. B. das Hinzufügen von Ereignis-Listenern, das Hinzufügen von BeanFactoryPostProcessor, das Festlegen der Umgebung und das Abrufen von ConfigurableListableBeanFactory
  2. AbstractApplicationContext: implementiert die ConfigurableApplicationContext-Schnittstelle
  3. GenericApplicationContext: erbt AbstractApplicationContext, implementiert die BeanDefinitionRegistry-Schnittstelle, verfügt über alle Funktionen von ApplicationContext und kann BeanDefinition registrieren. Beachten Sie, dass es in dieser Klasse eine Eigenschaft gibt (DefaultListableBeanFactory beanFactory).
  4. AnnotationConfigRegistry: Sie können eine Klasse separat als BeanDefinition registrieren (kann **@Configuration-Annotation** für diese Klasse verarbeiten und kann bereits **@Bean-Annotation** verarbeiten) und gleichzeitig scannen
  5. AnnotationConfigApplicationContext: erbt GenericApplicationContext, implementiert die AnnotationConfigRegistry-Schnittstelle und verfügt über alle oben genannten Funktionen

4.2 ClassPathXmlApplicationContext

Fügen Sie hier eine Bildbeschreibung ein
Es erbt auch AbstractApplicationContext, aber im Vergleich zu AnnotationConfigApplicationContext sind seine Funktionen nicht so leistungsstark wie AnnotationConfigApplicationContext, z. B. kann BeanDefinition nicht registriert werden

5. Internationalisierung

Definieren Sie zunächst eine MessageSource:

@Bean
public MessageSource messageSource() {
    
    
 ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
 messageSource.setBasename("messages");
 return messageSource;
}

Mit dieser Bean können Sie die MessageSource überall dort verwenden, wo Sie internationalisieren möchten.
Da ApplicationContext gleichzeitig auch die Funktion der Verstaatlichung hat, kann es direkt wie folgt verwendet werden:

context.getMessage("test", null, new Locale("en_CN"))

6. Laden von Ressourcen

ApplicationContext hat auch die Funktion, Ressourcen zu laden. Beispielsweise können Sie ApplicationContext direkt verwenden, um den Inhalt einer Datei abzurufen:

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

Resource resource = context.getResource("file://D:\\IdeaProjects\\spring-framework\\luban\\src\\main\\java\\com\\luban\\entity\\User.java");
System.out.println(resource.contentLength());

Sie können darüber nachdenken: Wenn Sie ApplicationContext nicht verwenden, sondern diese Funktion selbst implementieren, ist dies zeitaufwändiger.

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

Resource resource = context.getResource("file://D:\\IdeaProjects\\spring-framework-5.3.10\\tuling\\src\\main\\java\\com\\zhouyu\\service\\UserService.java");
System.out.println(resource.contentLength());
System.out.println(resource.getFilename());

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

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

Sie können auch mehrere auf einmal erhalten:

Resource[] resources = context.getResources("classpath:com/zhouyu/*.class");
for (Resource resource : resources) {
    
    
 System.out.println(resource.contentLength());
 System.out.println(resource.getFilename());
}

7. Besorgen Sie sich die Laufzeitumgebung

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

Map<String, Object> systemEnvironment = context.getEnvironment().getSystemEnvironment();
System.out.println(systemEnvironment);

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

Map<String, Object> systemProperties = context.getEnvironment().getSystemProperties();
System.out.println(systemProperties);

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

MutablePropertySources propertySources = context.getEnvironment().getPropertySources();
System.out.println(propertySources);

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

Beachten Sie, dass @PropertySource("classpath:spring.properties")Parameter in einer Eigenschaftendatei mithilfe von zur Laufzeitumgebung hinzugefügt werden können

8. Veröffentlichung der Veranstaltung

Spring implementiert intern einen Event-Publisher. Es wird verwendet, um ein Ereignis abzuhören und zu reagieren, wenn Spring asynchron startet. Ein klassisches Beispiel ist beispielsweise, dass eine ContextRefreshedEventVeranstaltung nach dem erfolgreichen Frühlingsstart veröffentlicht wird. Dann können wir es in unserem eigenen Geschäftscode implementieren implements ApplicationListener<ContextRefreshedEvent>und dann onApplicationEvent()das benutzerdefinierte Geschäft über die Implementierungsmethode abschließen.
Beispielverwendung:
Definieren Sie zunächst einen Ereignis-Listener:

@Bean
public ApplicationListener applicationListener() {
    
    
 return new ApplicationListener() {
    
    
  @Override
  public void onApplicationEvent(ApplicationEvent event) {
    
    
   System.out.println("接收到了一个事件");
  }
 };
}

Dann veröffentlichen Sie die Veranstaltung:

public class MyApplicationTest {
    
    
    public static void main(String[] args) {
    
    
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        context.publishEvent("kkk");
    }
}

Fügen Sie hier eine Bildbeschreibung ein
Das erste rote Kästchen ist das von uns erwähnte Ereignis, das intern nach dem Start von Spring veröffentlicht wird; das zweite wird von uns manuell aufgerufen und ist verpackt PayloadApplicationEvent.

Neun, Typkonvertierung

Im Spring-Quellcode kann es erforderlich sein, String in andere Typen zu konvertieren. Daher werden im Spring-Quellcode einige Technologien bereitgestellt, um die Konvertierung von Objekttypen komfortabler zu gestalten. In Bezug auf das Anwendungsszenario der Typkonvertierung werden Sie dabei darauf stoßen später einen Blick auf den Quellcode zu werfen. Vieles.

9.1 PropertyEditor

Dies ist eigentlich eine Typkonvertierungs-Toolklasse, die im JDK bereitgestellt wird.

Benutzerdefinierte Typkonverter:

public class StringToUserPropertyEditor extends PropertyEditorSupport implements PropertyEditor {
    
    

 @Override
 public void setAsText(String text) throws IllegalArgumentException {
    
    
  User user = new User();
  user.setName(text);
  this.setValue(user);
 }
}

Registrieren Sie PropertyEditor bei Spring:

@Bean
public CustomEditorConfigurer customEditorConfigurer() {
    
    
 CustomEditorConfigurer customEditorConfigurer = new CustomEditorConfigurer();
 Map<Class<?>, Class<? extends PropertyEditor>> propertyEditorMap = new HashMap<>();
    
    // 表示StringToUserPropertyEditor可以将String转化成User类型,在Spring源码中,如果发现当前对象是String,而需要的类型是User,就会使用该PropertyEditor来做类型转化
 propertyEditorMap.put(User.class, StringToUserPropertyEditor.class);
 customEditorConfigurer.setCustomEditors(propertyEditorMap);
 return customEditorConfigurer;
}

Testbohne:

@Component
public class UserService {
    
    

 @Value("深哥")
 private User user;

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

}

überweisen:

public class MyApplicationTest {
    
    
    public static void main(String[] args) {
    
    
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        Object userService = context.getBean("userService");
        System.out.println(userService);
    }
}

Das endgültige Debug lautet wie folgt:
Fügen Sie hier eine Bildbeschreibung ein

9.2 ConversionService

Wörtliche Übersetzung: Konvertierungsgerät, Konvertierungsdienst. Der in Spring bereitgestellte Typkonvertierungsdienst ist leistungsfähiger als PropertyEditor.
Benutzerdefinierter Typkonverter:

public class StringToUserConverter implements ConditionalGenericConverter {
    
    

 @Override
 public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
    
    
  return sourceType.getType().equals(String.class) && targetType.getType().equals(User.class);
 }

 @Override
 public Set<ConvertiblePair> getConvertibleTypes() {
    
    
  return Collections.singleton(new ConvertiblePair(String.class, User.class));
 }

 @Override
 public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
    
    
  User user = new User();
  user.setName((String)source);
  return user;
 }
}

Registrieren Sie ConversionService bei Spring:

@Bean
public ConversionServiceFactoryBean conversionService() {
    
    
 ConversionServiceFactoryBean conversionServiceFactoryBean = new ConversionServiceFactoryBean();
 conversionServiceFactoryBean.setConverters(Collections.singleton(new StringToUserConverter()));

 return conversionServiceFactoryBean;
}

Testbohne:

@Component
public class UserService {
    
    

 @Value("深哥")
 private User user;

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

}

überweisen:

public class MyApplicationTest {
    
    
    public static void main(String[] args) {
    
    
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        Object userService = context.getBean("userService");
        System.out.println(userService);
    }
}

Das endgültige Debug lautet wie folgt:
Fügen Sie hier eine Bildbeschreibung ein

9.3 Typkonverter

TypeConverter integriert die Funktionen von PropertyEditor und ConversionService, die intern von Spring verwendet werden:

SimpleTypeConverter typeConverter = new SimpleTypeConverter();
typeConverter.registerCustomEditor(User.class, new StringToUserPropertyEditor());
//typeConverter.setConversionService(conversionService);
User value = typeConverter.convertIfNecessary("1", User.class);
System.out.println(value);

10. Bestellvergleicher

OrderComparator ist ein von Spring bereitgestellter Komparator, mit dem Wertnotizen gemäß der @Order-Annotation durchgeführt oder die Ordered-Schnittstelle implementiert werden können, damit diese sortiert werden können. Zum Beispiel:

public class A implements Ordered {
    
    

 @Override
 public int getOrder() {
    
    
  return 3;
 }

 @Override
 public String toString() {
    
    
  return this.getClass().getSimpleName();
 }
}

public class B implements Ordered {
    
    

 @Override
 public int getOrder() {
    
    
  return 2;
 }

 @Override
 public String toString() {
    
    
  return this.getClass().getSimpleName();
 }
}

public class Main {
    
    

 public static void main(String[] args) {
    
    
  A a = new A(); // order=3
  B b = new B(); // order=2

  OrderComparator comparator = new OrderComparator();
  System.out.println(comparator.compare(a, b));  // 1

  List list = new ArrayList<>();
  list.add(a);
  list.add(b);

  // 按order值升序排序
  list.sort(comparator);

  System.out.println(list);  // B,A
 }
}

Darüber hinaus bietet Spring auch eine Unterklasse von OrderComparator: AnnotationAwareOrderComparator, die @Order zur Angabe des Bestellwerts unterstützt. Zum Beispiel:

@Order(3)
public class A {
    
    

 @Override
 public String toString() {
    
    
  return this.getClass().getSimpleName();
 }

}

@Order(2)
public class B {
    
    

 @Override
 public String toString() {
    
    
  return this.getClass().getSimpleName();
 }

}

public class Main {
    
    

 public static void main(String[] args) {
    
    
  A a = new A(); // order=3
  B b = new B(); // order=2

  AnnotationAwareOrderComparator comparator = new AnnotationAwareOrderComparator();
  System.out.println(comparator.compare(a, b)); // 1

  List list = new ArrayList<>();
  list.add(a);
  list.add(b);

  // 按order值升序排序
  list.sort(comparator);

  System.out.println(list); // B,A
 }
}

*Besondere Erklärung

Die Rolle der Schnittstelle wird manchmal dazu genutzt, Verhalten einzuschränken und zu regulieren. Hervorragender Quellcode wie Spring wird gemäß der Schnittstellenbeschreibung ausgeführt. Daher kann uns die Betrachtung von Schnittstellenanmerkungen helfen, die Fähigkeiten einer bestimmten Klasse zu verstehen!
Erinnern!
Erinnern!
Erinnern!
Erinnern!
Erinnern!
Erinnern!

BeanPostProcessorDarüber hinaus die , die im Folgenden vorgestellt werden BeanFactoryPostProcessor, da es mir beim ersten Lesen schwerfiel, sie zu verstehen, daher möchte ich Ihnen vorab die Schwierigkeiten mitteilen, auf die ich beim Verständnis gestoßen bin. Schließlich sollte es jeder tun [Gerichte sind alle gleich].

  1. Sie werden übersetzt in: Hook, Hook im Kommentar des Spring-Autors.Hook, Hook-Funktion In unserer Programmierung lautet die Semantik: Wenn die Bedingung wahr ist, erhöhen oder ändern Sie das ursprüngliche Verhalten des Systems!. Daher können wir grundsätzlich wissen, dass uns diese beiden Postprozessoren von Spring zur Verfügung gestellt werden, um das Verhalten und die Eigenschaften eines Objekts oder sogar des Systems zu einem bestimmten Zeitpunkt zu ändern.
  2. BeanPostProcessorDer Gegenstand des Handelns ist Bean, BeanFactoryPostProcessorder Gegenstand des Handelns istBeanFactory

*11. BeanPostProcessor: Ein wichtiger Erweiterungspunkt von Spring

grundlegende Einführung

BeanPostProcessor, wörtlich übersetzt als: Beans Postprozessor (PS: Um ehrlich zu sein, wird diese Benennung zum ersten Mal abstrakter sein. Wenn Sie sagen, dass es sich um den Postprozessor des Beans handelt, denke ich, dass es sich um die Nachbearbeitung handelt, die nach der Erstellung des Beans durchgeführt wird. Aber die Beans werden alle erstellt. Warum wird der Erweiterungspunkt [vor und nach der Initialisierung] bereitgestellt? ? ? Später stellte sich heraus, dass die Bohne, von der es hieß, erschaffen wurde und dass new Bean()die Bohne von Anfang an existierte, aber sie war [unvollständig], ich weinte zu Tode). Werfen wir einen Blick auf die Schnittstellendefinitionsmethode:

/**
 * 工厂钩子。
 * 允许自定义修改新bean实例的工厂钩子——例如,检查标记接口或用代理包装bean。
 * 通常,通过标记接口或类似的方式填充bean的后处理器将实现postProcessBeforeInitialization,而用代理包装bean的后处理器通常将实现postProcessAfterInitialization。
 * 登记
 * ApplicationContext可以在其bean定义中自动检测BeanPostProcessor bean,并将这些后处理程序应用于随后创建的任何bean。普通的BeanFactory允许对后处理器进行编程注册,将它们应用于通过bean工厂创建的所有bean。
 * 订购
 * 在ApplicationContext中自动检测到的BeanPostProcessor bean将根据org.springframework.core. priorityorordered和org.springframework.core.Ordered语义进行排序。相反,通过BeanFactory以编程方式注册的BeanPostProcessor bean将按照注册的顺序应用;通过实现priityordered或Ordered接口表达的任何排序语义将被编程注册的后处理器忽略。此外,@Order注释没有考虑到BeanPostProcessor bean。
 * 自:
 * 10.10.2003
 * 参见:
 * InstantiationAwareBeanPostProcessor, DestructionAwareBeanPostProcessor, ConfigurableBeanFactory。addBeanPostProcessor, BeanFactoryPostProcessor
 * 作者:
 * 于尔根·霍勒,山姆·布兰南
 */
public interface BeanPostProcessor {
    
    

    /**
     * 在任何bean初始化回调(如InitializingBean的afterPropertiesSet或自定义初始化方法)之前,将此BeanPostProcessor应用于给定的新bean实例。这个bean已经被属性值填充了。返回的bean实例可能是原始bean实例的包装器。
     * 默认实现按原样返回给定的bean。
     * 参数:
     * Bean——新的Bean实例
     * beanName—bean的名称
     * 返回:
     * 要使用的bean实例,无论是原始的还是包装的;如果为空,则不会调用后续的BeanPostProcessors
     * 抛出:
     * BeansException -在错误的情况下
     */
    default Object postProcessBeforeInitialization(Object bean, String beanName) {
    
    
        return bean;
    }

    /**
     * 在任何bean初始化回调(如InitializingBean的afterPropertiesSet或自定义init-method)之后,将此BeanPostProcessor应用于给定的新bean实例。这个bean已经被属性值填充了。返回的bean实例可能是原始bean实例的包装器。
     * 对于FactoryBean,将为FactoryBean实例和由FactoryBean创建的对象调用这个回调(从Spring 2.0开始)。后处理器可以通过相应的FactoryBean instanceof检查来决定是应用于FactoryBean还是已创建的对象,或者两者都应用。
     * 这个回调也将在由InstantiationAwareBeanPostProcessor触发的短路之后被调用。postProcessBeforeInstantiation方法,与所有其他BeanPostProcessor回调相反。
     * 默认实现按原样返回给定的bean。
     * 参数:
     * Bean——新的Bean实例
     * beanName—bean的名称
     * 返回:
     * 要使用的bean实例,无论是原始的还是包装的;如果为空,则不会调用后续的BeanPostProcessors
     * 抛出:
     * BeansException -在错误的情况下
     * 参见:
     * org.springframework.beans.factory.InitializingBean。afterPropertiesSet, org.springframework.beans.factory.FactoryBean
     * 以上翻译结果来自有道神经网络翻译(YNMT)· 通用场景
     */
    default Object postProcessAfterInitialization(Object bean, String beanName) {
    
    
        return bean;
    }
}

Zusammenfassend lässt sich sagen: BeanPostProcessor ist eine Schnittstelle, die zwei Methoden (Erweiterungsmöglichkeiten) bereitstellt und jeweils auf [vor der Initialisierung] [nach der Initialisierung] reagiert.

Anwendungsszenario

Durch das Lesen der Kommentare kann grundsätzlich festgestellt werden, dass die Implementierung von [Agent Creation] im [AOP]-Prozess auf diesem Erweiterungspunkt basiert (ich habe den Quellcode ein wenig überprüft und er wird grundsätzlich bestätigt).
Darüber hinaus ist es notwendig, einen besonderen Punkt hervorzuheben. Tatsächlich stellt Spring viel bereit XxxPostProcessorund erbt dann von oder implementiert BeanPostProcessor. Obwohl die Funktionserweiterung von [vor und nach der Initialisierung] weiterhin beibehalten wird, gilt dies nicht nur für dieses Leben Zyklus. Zum Beispiel: InstantiationAwareBeanPostProcessor(Die wörtliche Übersetzung lautet:BeanPostProcessor ist sich der Instanziierung bewusst), ist die Instanziierung nicht nur ein weiterer Lebenszyklus der Bean? Es fügt eine Reihe zusätzlicher Erweiterungspunkte hinzu: [vor der Instanziierung], [nach der Instanziierung] usw.Wenn Sie also in Zukunft viel im Spring-Quellcode sehen XxxPostProcessor, denken Sie nicht, dass er nur über den Erweiterungspunkt [vor und nach der Initialisierung] verfügt und möglicherweise auch andere enthält

Einfaches Anwendungsbeispiel

Im Folgenden definieren wir ein BeanPostProcessor-Beispiel zum Spielen:

@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
    
    

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

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

Mit den oben genannten Mitteln können wir durch die Definition von BeanPostProcessor in den Prozess der Bean-Erstellung von Spring eingreifen.

*12. BeanFactoryPostProcessor: Der wichtige Erweiterungspunkt von Spring

grundlegende Einführung

BeanFactoryPostProcessor, wörtliche Übersetzung: Der Postprozessor der Bean Factory ähnelt tatsächlich BeanPostProcessor. Es ist nur so, dass BeanPostProcessor den Bean-Erstellungsprozess stört und BeanFactoryPostProcessor den BeanFactory-Erstellungsprozess stört. Schauen Sie sich die Schnittstellendefinition an:

/**
 * 工厂钩子。
 * 允许自定义修改应用程序上下文的bean定义,调整上下文的底层bean工厂的bean属性值。
 * 对于针对系统管理员的自定义配置文件非常有用,这些配置文件覆盖在应用程序上下文中配置的bean属性。有关解决此类配置需求的开箱即用解决方案,请参阅propertyresourcecconfigururer及其具体实现。
 * BeanFactoryPostProcessor可以与bean定义交互和修改,但不能与bean实例交互。这样做可能会导致过早的bean实例化,违反容器并导致意想不到的副作用。如果需要bean实例交互,请考虑实现BeanPostProcessor。
 * 登记
 * ApplicationContext在其bean定义中自动检测BeanFactoryPostProcessor bean,并在创建任何其他bean之前应用它们。BeanFactoryPostProcessor也可以通过编程方式注册到ConfigurableApplicationContext中。
 * 订购
 * 在ApplicationContext中自动检测到的BeanFactoryPostProcessor bean将根据org.springframework.core. priorityorordered和org.springframework.core.Ordered语义进行排序。与此相反,BeanFactoryPostProcessor bean是通过ConfigurableApplicationContext以编程方式注册的,它将按照注册的顺序应用;通过实现priityordered或Ordered接口表达的任何排序语义将被编程注册的后处理器忽略。此外,@Order注释不会被BeanFactoryPostProcessor bean考虑在内。
 * 自:
 * 06.07.2003
 * 参见:
 * BeanPostProcessor, PropertyResourceConfigurer
 * 作者:
 * 于尔根·霍勒,山姆·布兰南
 */
@FunctionalInterface
public interface BeanFactoryPostProcessor {
    
    

	/**
	 * 在标准初始化之后修改应用程序上下文的内部bean工厂。所有的bean定义都已加载,但还没有实例化任何bean。这允许覆盖或添加属性,甚至是对急于初始化的bean。
	 * 参数:
	 * beanFactory——应用程序上下文使用的bean工厂
	 * 抛出:
	 * BeansException -在错误的情况下
	 */
	void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;

}

Zusammenfassend lässt sich sagen: BeanFactoryPostProcessor ist eine Schnittstelle, die eine Methode (Erweiterungsmöglichkeit) bereitstellt, die es uns ermöglicht: anzuwenden, bevor alle Beans instanziiert werden, und Entwicklern die Möglichkeit bietet, Bean-Definitionen zu ändern, sodass Bean-Instanzen auf ihre eigene Weise generiert werden können Zweck .

Anwendungsszenario

Schauen Sie sich die Klassenanmerkungen und Implementierungsklassen an. @ConfigurationDie Anmerkungen nutzen diese Erweiterungsmöglichkeit. Vielleicht @Beangibt es auch hier Unterstützung
. Darüber hinaus scheint es, dass [Weben] im [AOP]-Prozess an diesem Erweiterungspunkt realisiert wird

Einfaches Anwendungsbeispiel

Beispielsweise können wir einen BeanFactoryPostProcessor wie folgt definieren:

@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    
    
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    
    
        System.out.println("加工beanFactory");
    }
}

Wir können die BeanFactory in der Methode postProcessBeanFactory() verarbeiten.

Dreizehn, FactoryBean

Wie oben erwähnt, können wir BeanPostPorcessor verwenden, um in den Prozess der Bean-Erstellung in Spring einzugreifen. Wenn wir jedoch eine Bean vollständig selbst erstellen möchten, ist dies auch möglich, beispielsweise über FactoryBean: (Dies ist ebenfalls schwierig zu verstehen.) Das Konzept, und es ist auch ein
Spring Einer der Interviewtestpunkte. Zuerst müssen Sie verstehen, dass es sich um eine Bean handelt. Da es sich um eine Bean handelt, muss sie von Spring verwaltet werden. Zweitens kommt sie aus einer Factory. Das heißt: eine Fabrik. Jeder sollte die Fabrik im Entwurfsmustermodus kennen, oder? Es ist ein Ort zum Generieren von Objekten. Zusammenfassend ist hier eine Fabrik-Bean, die zum Erzeugen bestimmter Bean-Objekte verwendet wird. Diese Fabrik-Bean durchläuft keinen vollständigen Prozess Lebenszyklus)

@Component
public class ZhouyuFactoryBean implements FactoryBean {
    
    

 @Override
 public Object getObject() throws Exception {
    
    
  UserService userService = new UserService();

  // 属性赋值
  return userService;
 }

 @Override
 public Class<?> getObjectType() {
    
    
  return UserService.class;
 }
}

Mit dem obigen Code haben wir selbst ein UserService-Objekt erstellt, das zu einer Bean wird.Die auf diese Weise erstellte Bean von UserService wird jedoch nur initialisiert und andere Schritte des Spring-Lebenszyklus, wie z. B. die Abhängigkeitsinjektion, werden nicht durchlaufen.
Einige Schüler denken möglicherweise, dass Sie über @Bean auch ein Objekt als Bean generieren können. Was ist also der Unterschied zu FactoryBean? Tatsächlich können sie in vielen Szenarien ersetzt werden, aber aus prinzipieller Sicht ist der Unterschied offensichtlich.Die von @Bean definierte Bean durchläuft den gesamten Bean-Lebenszyklus

Vierzehn, ExcludeFilter und IncludeFilter

Diese beiden Filter werden zum Filtern während des Spring-Scannens verwendet. ExcludeFilter bedeutet Ausschlussfilter und IncludeFilter bedeutet Einschlussfilter.
Die folgende Konfiguration bedeutet beispielsweise, dass alle Klassen im Paket com.zhouyu gescannt werden, jedoch die UserService-Klasse ausgeschlossen wird, d. h. sie wird nicht zu einer Bean, selbst wenn sie die Annotation @Component enthält.

@ComponentScan(value = "com.zhouyu",
  excludeFilters = {
    
    @ComponentScan.Filter(
             type = FilterType.ASSIGNABLE_TYPE, 
             classes = UserService.class)}.)
public class AppConfig {
    
    
}

Ein weiteres Beispiel ist die folgende Konfiguration. Auch wenn in der UserService-Klasse keine @Component-Annotation vorhanden ist, wird sie als Bean gescannt.

@ComponentScan(value = "com.zhouyu",
  includeFilters = {
    
    @ComponentScan.Filter(
             type = FilterType.ASSIGNABLE_TYPE, 
             classes = UserService.class)})
public class AppConfig {
    
    
}

FilterType ist unterteilt in:

  1. ANMERKUNG: Gibt an, ob eine Anmerkung eingefügt werden soll
  2. ASSIGNABLE_TYPE: Gibt an, ob es sich um eine bestimmte Klasse handelt
  3. ASPECTJ: Gibt an, ob es einem Aspectj-Ausdruck entspricht
  4. REGEX: Gibt an, ob ein regulärer Ausdruck erfüllt ist
  5. BENUTZERDEFINIERT: benutzerdefiniert

In der Scan-Logik von Spring wird standardmäßig ein AnnotationTypeFilter zu includeFilters hinzugefügt, was bedeutet, dass die @Component-Annotation der Klasse während des Spring-Scanvorgangs standardmäßig als Bean betrachtet wird.

Beispiele: MetadataReader, ClassMetadata und AnnotationMetadata

In Spring müssen Klasseninformationen wie Klassenname, Methoden in der Klasse und Anmerkungen zur Klasse analysiert werden. Diese können als Metadaten der Klasse bezeichnet werden, sodass Spring die Metadaten der Klasse abstrahiert und einige Tools bereitstellt. Die Schnittstellendefinition von MetadataReader lautet wie folgt:


/**
 * Simple facade for accessing class metadata,
 * as read by an ASM {@link org.springframework.asm.ClassReader}.
 *
 * @author Juergen Hoeller
 * @since 2.5
 */
public interface MetadataReader {
    
    

	/**
	 * Return the resource reference for the class file.
	 */
	Resource getResource();

	/**
	 * Read basic class metadata for the underlying class.
	 */
	ClassMetadata getClassMetadata();

	/**
	 * Read full annotation metadata for the underlying class,
	 * including metadata for annotated methods.
	 */
	AnnotationMetadata getAnnotationMetadata();

}

MetadataReader stellt den Metadatenleser der Klasse dar, und die Standardimplementierungsklasse ist SimpleMetadataReader. Zum Beispiel:

public class MySpringApplicationTest {
    
    
    public static void main(String[] args) throws IOException {
    
    
        SimpleMetadataReaderFactory simpleMetadataReaderFactory = new SimpleMetadataReaderFactory();

        // 构造一个MetadataReader
        MetadataReader metadataReader = simpleMetadataReaderFactory.getMetadataReader("org.example.spring.bean.UserService");

        // 得到一个ClassMetadata,并获取了类名
        ClassMetadata classMetadata = metadataReader.getClassMetadata();

        System.out.println(classMetadata.getClassName());

        // 获取一个AnnotationMetadata,并获取类上的注解信息
        AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
        for (String annotationType : annotationMetadata.getAnnotationTypes()) {
    
    
            System.out.println(annotationType);
        }

    }
}

Es ist zu beachten, dass SimpleMetadataReader beim Parsen von Klassen die ASM-Technologie verwendet.
Warum ASM-Technologie verwenden? Spring muss beim Start scannen. Wenn der angegebene Paketpfad relativ breit ist, müssen viele Klassen gescannt werden. Wenn alle diese Klassen beim Start von Spring in die JVM geladen werden, ist dies nicht der Fall Sehr gut, daher wird die ASM-Technik verwendet.

zusammenfassen

おすすめ

転載: blog.csdn.net/qq_32681589/article/details/132176000