[Fragen zum Frühjahrsinterview (35 Fragen)]

Artikelverzeichnis

Fragen zum Frühlingsinterview (35)

1

Base

1.Was ist Frühling? charakteristisch? Welche Module gibt es?

In einem Satz: Spring ist ein leichtes, nicht-intrusives Inversion of Control (loC) und aspektorientiertes (AOP) Framework .

Im Jahr 2003 beschloss ein Musiker namens Rod Johnson, ein leichtes Java-Entwicklungsframework zu entwickeln. Spring trat nach und nach als Dragoner auf dem Java-Schlachtfeld hervor und eliminierte die traditionelle schwere Kavallerie von EJB.

2

Bisher ist die Standardkonfiguration für die Entwicklung auf Unternehmensebene im Wesentlichen Spring5 + Spring Boot 2 + JDK 8

Welche Funktionen hat Spring?

Der Frühling hat viele Vorteile:

3

IOC: Umkehrung der Kontrolle Umkehrung der Kontrolle

DI: Abhängigkeitsinjektion Abhängigkeitsinjektion

AOP: Aspektorientierte Programmierung, scheibenorientierte Programmierung

  1. IOC- und DI-Unterstützung

Der Kern von Spring ist ein großer Fabrikcontainer , der die Erstellungs- und Abhängigkeitsbeziehungen aller Objekte verwalten kann. Die Spring-Fabrik wird zum Generieren von Beans und zum Verwalten des Lebenszyklus von Beans verwendet, um das Designkonzept mit hoher Kohäsion und geringer Kopplung zu erreichen.

  1. AOP-Programmierunterstützung

Spring bietet aspektorientierte Programmierung , mit der Aspektfunktionen wie das Abfangen von Berechtigungen und die Betriebsüberwachung von Programmen problemlos implementiert werden können.

  1. Deklarative Transaktionsunterstützung

Es unterstützt die Transaktionsverwaltung durch Konfiguration statt durch harte Codierung. Sie müssen nicht mehr einige JDBC-Codes für die Transaktionsübermittlung und das Rollback schreiben, die in der Vergangenheit wiederholt wurden.

  1. Schnelle Testunterstützung

Spring bietet Unterstützung für Junit und Sie können Spring-Programme mithilfe von Anmerkungen schnell testen .

  1. Funktionen schnell integrieren

Es ist bequem, verschiedene hervorragende Frameworks zu integrieren . Spring schließt verschiedene hervorragende Open-Source-Frameworks nicht aus und bietet direkte Unterstützung für verschiedene hervorragende Frameworks (wie Struts, Hibernate, MyBatis, Quartz usw.).

  1. Komplexe API-Vorlagenkapselung

Spring bietet eine vorlagenbasierte Kapselung für einige APIs, die in der JavaEE-Entwicklung sehr schwierig zu verwenden sind (JDBC, JavaMail, Remote-Aufrufe usw.) . Die Bereitstellung dieser gekapselten APIs verringert die Anwendungsschwierigkeiten erheblich.

2.Welche Module hat Spring?

Das Spring-Framework besteht aus Modulen. Außer den Kernmodulen spring Core Containersind weitere Module enthalten 可选. Es gibt etwa 20 Module.

Fügen Sie hier eine Bildbeschreibung ein

Die sieben wichtigsten Module:

  1. Spring Core : Spring Core, der grundlegendste Teil des Frameworks, bietet IOC- und Abhängigkeitsinjektions-DI-Funktionen.
  2. Spring-Kontext : Spring-Kontextcontainer, eine Unterschnittstelle mit erweiterter Funktionalität von BeanFactory.
  3. Spring Web : Es bietet Unterstützung für die Entwicklung von Webanwendungen.
  4. Spring MVC : Ziel ist die Umsetzung von MVC-Ideen in Webanwendungen.
  5. Spring DAO : Bietet eine Abstraktionsschicht für JDBC, vereinfacht die JDBC-Codierung und ist gleichzeitig robuster.
  6. Spring ORM : Es unterstützt die Integration beliebter ORM-Frameworks wie: Spring + Hibernate, Spring + iBatis, Spring + JDO-Integration usw.
  7. Spring AOP : Aspektorientierte Programmierung, die eine mit der AOP Alliance kompatible Programmierimplementierung bereitstellt.

3.Welche Anmerkungen werden im Frühling häufig verwendet?

Spring verfügt über viele Module, und selbst das verallgemeinerte SpringBoot und SpringCloud werden als Teil von Spring betrachtet. Lassen Sie uns die Module in Module unterteilen und einen Blick auf einige häufig verwendete Anmerkungen nach Funktion werfen:

Fügen Sie hier eine Bildbeschreibung ein

Netz:

  • @Controller: Kombinierte Annotationen (kombiniert mit @Component-Annotationen), angewendet in der MVC-Ebene (Kontrollebene).
  • @RestController: Diese Annotation ist eine kombinierte Annotation, die der Kombination von @Controller und @ResponseBody entspricht. Die Annotation befindet sich in der Klasse, was bedeutet, dass alle Methoden des Controllers standardmäßig mit @ResponseBody hinzugefügt werden.
  • @RequestMapping: Wird zum Zuordnen von Webanfragen verwendet, einschließlich Zugriffspfaden und Parametern. Wenn es sich um eine Schnittstelle im Restful-Stil handelt, können Sie je nach Anforderungstyp auch unterschiedliche Annotationen verwenden:
    • @GetMapping
    • @PostMapping
    • @PutMapping
    • @DeleteMapping
  • @ResponseBody: Unterstützt die Platzierung des Rückgabewerts innerhalb der Antwort anstelle einer Seite. Normalerweise gibt der Benutzer JSON-Daten zurück.
  • @RequestBody: Ermöglicht, dass sich Anforderungsparameter im Anforderungstext befinden, anstatt direkt hinter der Adresse verbunden zu sein.
  • @PathVariable: Wird zum Empfangen von Pfadparametern verwendet, z. B. des von @RequestMapping („/hello/{name)“) deklarierten Pfads. Sie können den Wert erhalten, indem Sie die Annotation vor dem Parameter platzieren. Wird normalerweise als Restful verwendet Methode zur Schnittstellenimplementierung.

Container:

  • @Component: Gibt an, dass eine mit Anmerkungen versehene Klasse eine „Komponente“ ist und zu einer von Spring verwalteten Bean wird. Diese Klassen gelten als Kandidaten für die automatische Erkennung, wenn annotationsbasierte Konfiguration und Klassenpfad-Scanning verwendet werden. Gleichzeitig ist @Component auch eine Meta-Annotation.

  • @Service: kombinierte Annotation (kombiniert mit @Component-Annotation), angewendet in der Serviceschicht (Geschäftslogikschicht).

  • @Repository: kombinierte Annotation (kombiniert mit @Component-Annotation), angewendet in der Dao-Schicht (Datenzugriffsschicht).

  • @Autowired: Von Spring bereitgestellte Tools (automatisch injiziert durch die Abhängigkeitsinjektionstools von Spring (BeanPostProcessor, BeanFactoryPostProcessor)).

  • @Qualifier: Diese Annotation wird normalerweise zusammen mit @Autowired verwendet. Wenn Sie mehr Kontrolle über den Injektionsprozess haben möchten, kann @Qualifier bei der Konfiguration helfen. Wenn beispielsweise zwei oder mehr Beans desselben Typs vorhanden sind, kann Spring keine Auswahl treffen , also verwenden Sie diese Anmerkung.

  • @Configuration: Deklariert, dass die aktuelle Klasse eine Konfigurationsklasse ist (entspricht einer Spring-Konfigurations-XML-Datei).

  • @Value: Kann in Feldern, Konstruktorparametern und Methodenparametern verwendet werden, um einen Standardwert anzugeben. Es unterstützt zwei Methoden: #{} und ${}. Im Allgemeinen werden die in application.properties in SpringbBoot konfigurierten Eigenschaftswerte Variablen zugewiesen.

  • @Bean: In der Methode mit Anmerkungen versehen, deklariert es, dass der Rückgabewert der aktuellen Methode eine Bean ist. Die Methoden init() und destroy() können in der Klasse definiert werden, die der zurückgegebenen Bean entspricht, und dann in

    ​Definition@Bean (initMethod="init", destroyMethod="destroy") : init wird nach der Konstruktion ausgeführt und destroy wird vor der Zerstörung ausgeführt.

  • @Scope: Definieren Sie, welchen Modus wir zum Erstellen von Beans verwenden (Methode, es muss @Bean vorhanden sein). Zu den Einstellungstypen gehören: Singleton, Prototype, Request, Session, GlobalSession.

AOP:

  • @Aspect: Deklarieren Sie einen Aspekt (in der Klasse) mithilfe von @After, @Before und @Around, um Ratschläge (Advice) zu definieren, und Sie können die Abfangregel (Pointcut) direkt als Parameter verwenden.
    • @After: Wird ausgeführt, nachdem die Methode ausgeführt wurde (auf der Methode).
    • @Before: Wird ausgeführt, bevor die Methode ausgeführt wird (auf der Methode).
    • @Around: Vor und nach der Methodenausführung (auf der Methode) ausführen.
    • @Pointcut: Um Pointcuts zu deklarieren, verwenden Sie die Annotation @EnableAspectJAutoProxy in der Java-Konfigurationsklasse, um Springs Unterstützung für den Aspectj-Proxy (in der Klasse) zu aktivieren.

Transaktion:

  • @Transactional: Verwenden Sie die Annotation @Transactional für die Methode zum Starten der Transaktion, um die Transaktion deklarativ zu starten.

4.Welche Designmuster werden im Frühling verwendet?

Im Spring-Framework werden häufig verschiedene Arten von Entwurfsmustern verwendet. Werfen wir einen Blick darauf, welche Entwurfsmuster es gibt.

Fügen Sie hier eine Bildbeschreibung ein

  1. Fabrikmuster: Der Spring-Container ist im Wesentlichen eine große Fabrik. Verwenden Sie das Fabrikmuster, um Bean-Objekte über BeanFactory und ApplicationContext zu erstellen.
  2. Proxy-Modus: Spring AOP-Funktionen werden über den Proxy-Modus implementiert, der in dynamischen Proxy und statischen Proxy unterteilt ist.
  3. Singleton-Modus: Beans in Spring sind standardmäßig Singletons, was sich positiv auf die Bean-Verwaltung des Containers auswirkt.
  4. Vorlagenmodus: JdbcTemplate, RestTemplate und andere Vorlagenklassen, die in Spring mit „Template“ enden und auf Datenbanken, Netzwerken usw. arbeiten, verwenden den Vorlagenmodus.
  5. Beobachtermuster: Das ereignisgesteuerte Spring-Modell ist eine klassische Anwendung des Beobachtermusters.
  6. Adaptermodus: Die Erweiterung oder Benachrichtigung (Advice) von Spring AOP verwendet den Adaptermodus, und Spring MVC verwendet auch den Adaptermodus, um den Controller anzupassen.
  7. Strategiemuster: In Spring gibt es eine Ressourcenschnittstelle, und ihre verschiedenen Implementierungsklassen greifen gemäß unterschiedlichen Strategien auf Ressourcen zu.

IOC

5. Sag mir, was ist IOC? Was ist DI?

Java ist eine objektorientierte Programmiersprache. Instanzobjekte kooperieren miteinander, um Geschäftslogik zu bilden. Es stellt sich heraus, dass wir alle Objekte und Objektabhängigkeiten im Code erstellen.

Das sogenannte IOC (Inversion of Control) : Der Container ist für die Steuerung des Lebenszyklus von Objekten und der Beziehung zwischen Objekten verantwortlich . Früher konnten wir alles erschaffen, was wir wollten. Jetzt schickt uns der Container alles, was wir brauchen.

Fügen Sie hier eine Bildbeschreibung ein

Mit anderen Worten: Was den Lebenszyklus eines Objekts steuert, ist nicht mehr das Objekt, das darauf verweist, sondern der Container. Früher wurden für ein bestimmtes Objekt andere Objekte gesteuert. Jetzt werden jedoch alle Objekte vom Container gesteuert. Dies wird daher als Umkehrung der Steuerung bezeichnet .

Fügen Sie hier eine Bildbeschreibung ein

DI (Dependency Injection) : bezieht sich auf den Container, der die Klassen einfügt, von denen er abhängt, wenn ein Objekt instanziiert wird . Einige sagen, dass IOC und DI dasselbe sind, andere sagen, dass IOC die Idee und DI die Umsetzung von IOC ist.

Warum IOC verwenden?

Das Wichtigste ist, die beiden Wörter zu entkoppeln . Hartes Codieren führt zu einer übermäßigen Kopplung zwischen Objekten. Nach der Verwendung von IOC müssen wir uns nicht mehr um die Abhängigkeiten zwischen Objekten kümmern und können uns auf die Entwicklung von Anwendungen konzentrieren.

6·Können Sie kurz über den Implementierungsmechanismus von Spring IOC sprechen?

PS: Oder die Frage lautet: „Haben Sie schon einmal Simple Spring selbst implementiert?“

Das IOC von Spring ist im Wesentlichen eine große Fabrik. Lassen Sie uns darüber nachdenken, wie eine Fabrik funktioniert.

Fügen Sie hier eine Bildbeschreibung ein

  • Produzieren von Produkten: Die Kernfunktion einer Fabrik ist die Produktion von Produkten. Anstatt das Bean selbst zu instanziieren, wird es im Spring an Spring übergeben. Wie soll dies implementiert werden? ——Die Antwort ist zweifellos Nachdenken .

    Wie erfolgt also das Produktionsmanagement dieser Fabrik? Sie sollten auch wissen – Fabrikmuster .

  • Lagerprodukte : Fabriken verfügen in der Regel über Lager zur Lagerung von Produkten. Schließlich können die produzierten Produkte nicht sofort weggenommen werden. Wir alle wissen, dass Spring ein Container ist und Objekte in diesem Container gespeichert werden. Sie können Objekte nicht jedes Mal, wenn Sie sie abrufen, durch Reflexion an Ort und Stelle erstellen, sondern müssen die erstellten Objekte speichern.

  • Auftragsabwicklung : Und der wichtigste Punkt ist, auf welcher Grundlage liefert die Fabrik Produkte? Befehl. Diese Bestellungen können unterschiedlicher Art sein, einige werden online unterschrieben, einige werden im Werk unterschrieben und wieder andere werden an der Tür des Werksverkaufs unterschrieben ... Schließlich werden sie bearbeitet und zum Versand an das Werk weitergeleitet.

    Im Frühling gibt es auch eine solche Reihenfolge, nämlich die Definition und Abhängigkeit unserer Bohnen. Sie kann in XML-Form oder in der Annotationsform vorliegen, mit der wir am besten vertraut sind.

Wir implementieren einfach eine Mini-Version von Spring IOC:

Fügen Sie hier eine Bildbeschreibung ein

Bohnendefinition:

Eine Bean wird über eine Konfigurationsdatei definiert und in einen Typ geparst.

  • Beans.properties ist faul. Hier verwenden wir direkt die bequemsten Eigenschaften zum Parsen. Hier verwenden wir direkt eine Konfiguration vom Typ <Schlüssel, Wert>, um die Definition von Bean darzustellen, wobei der Schlüssel beanName und der Wert die Klasse ist.
userDao:cn.fighter3.bean.UserDao
  • BeanDefinition.java

    Bean-Definitionsklasse, die Entität, die der Bean-Definition in der Konfigurationsdatei entspricht

public class BeanDefinition {
    
    
    private String beanName;
    private Class beanClass;
    //省略略getter、setter
}
  • ResourceLoader.java

    Ressourcenlader, der zum Abschließen des Ladens von Konfigurationen in Konfigurationsdateien verwendet wird

public class ResourceLoader {
    
    
    public static Map<String, BeanDefinition> getResource() {
    
    
        Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>(16);
        Properties properties = new Properties();
        try {
    
    
            InputStream inputStream =
            ResourceLoader.class.getResourceAsStream("/beans.properties");
            properties.load(inputStream);
            Iterator<String> it = properties.stringPropertyNames().iterator();
            while (it.hasNext()) {
    
    
                String key = it.next();
                String className = properties.getProperty(key);
                BeanDefinition beanDefinition = new BeanDefinition();
                beanDefinition.setBeanName(key);
                Class clazz = Class.forName(className);
                beanDefinition.setBeanClass(clazz);
                beanDefinitionMap.put(key, beanDefinition);
            }
            inputStream.close();
        } catch (IOException | ClassNotFoundException e) {
    
    
        	e.printStackTrace();
        }
        return beanDefinitionMap;
    }
}
  • BeanRegister.java

    Das Objektregister wird zum Zwischenspeichern von Singleton-Beans verwendet. Wir haben es stark vereinfacht. Standardmäßig sind alle Beans Singletons. Sie sehen, dass auch die sogenannte Singleton-Registrierung sehr einfach ist: Sie speichert lediglich Objekte in HashMap.

public class BeanRegister {
    
    
    //单例Bean缓存
    private Map<String, Object> singletonMap = new HashMap<>(32);
    /**
    * 获取单例Bean
    *
    * @param beanName bean名称
    * @return
    */
    public Object getSingletonBean(String beanName) {
    
    
    	return singletonMap.get(beanName);
    }
    /**
    * 注册单例bean
    *
    * @param beanName
    * @param bean
    */
    public void registerSingletonBean(String beanName, Object bean) {
    
    
        if (singletonMap.containsKey(beanName)) {
    
    
            return;
        }
        singletonMap.put(beanName, bean);
    }
}
  • BeanFactory.java

Fügen Sie hier eine Bildbeschreibung ein

Object Factory, eine unserer Kernklassen, erstellt ein Bean-Register und schließt das Laden der Ressourcen ab, wenn es initialisiert wird.

Wenn Sie eine Bean erhalten, rufen Sie sie zunächst aus dem Singleton-Cache ab. Wenn sie nicht abgerufen wird, erstellen und registrieren Sie eine Bean.

public class BeanFactory {
    
    
    private Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>();
    private BeanRegister beanRegister;
    public BeanFactory() {
    
    
        //创建bean注册器
        beanRegister = new BeanRegister();
        //加载资源
        this.beanDefinitionMap = new ResourceLoader().getResource();
    }
    /**
    * 获取bean
    *
    * @param beanName bean名称
    * @return
    */
    public Object getBean(String beanName) {
    
    
        //从bean缓存中取
        Object bean = beanRegister.getSingletonBean(beanName);
        if (bean != null) {
    
    
            return bean;
        }
        //根据bean定义,创建bean
        return createBean(beanDefinitionMap.get(beanName));
    }
    /**
    * 创建Bean
    * @param beanDefinition bean定义
    * @return
    */
    private Object createBean(BeanDefinition beanDefinition) {
    
    
        try {
    
    
            Object bean = beanDefinition.getBeanClass().newInstance();
            //缓存bean
            beanRegister.registerSingletonBean(beanDefinition.getBeanName(), bean);
            return bean;
        } catch (InstantiationException | IllegalAccessException e) {
    
    
        	e.printStackTrace();
        }
        return null;
    }
}
  • prüfen
  • UserDao.java Unsere Bean-Klasse, sehr einfach
  • Gerätetest
  • Operationsergebnis
public class UserDao {
    
    
    public void queryUserInfo(){
    
    
    	System.out.println("A good man.");
    }
}
public class ApiTest {
    
    
    @Test
    public void test_BeanFactory() {
    
    
        //1.创建bean工厂(同时完成了加载资源、创建注册单例bean注册器的操作)
        BeanFactory beanFactory = new BeanFactory();
        //2.第一次获取bean(通过反射创建bean,缓存bean)
        UserDao userDao1 = (UserDao) beanFactory.getBean("userDao");
        userDao1.queryUserInfo();
        //3.第二次获取bean(从缓存中获取bean)
        UserDao userDao2 = (UserDao) beanFactory.getBean("userDao");
        userDao2.queryUserInfo();
    }
}
A good man.
A good man.

Zu diesem Zeitpunkt ist unsere Bettler + Broken Ship-Version von Spring fertig und der Code ist relativ vollständig. Wenn möglich, können Sie ihn ausführen.

7. Sprechen Sie über BeanFactory und ApplicantContext?

Man kann sagen, dass BeanFactory das „Herz“ von Spring und ApplicantContext der vollständige „Körper“ ist.

  • BeanFactory (Bean Factory) ist die Infrastruktur des Spring-Frameworks und steht Spring selbst gegenüber.
  • ApplicantContext (Anwendungskontext) basiert auf BeanFactoty und richtet sich an Entwickler, die das Spring-Framework verwenden.

BeanFactory-Schnittstelle

BeanFactory ist eine allgemeine Fabrik für Klassen, die Objekte verschiedener Klassen erstellen und verwalten kann.

Spring bietet viele Implementierungen für BeanFactory. Die am häufigsten verwendete ist XmlBeanFactory, wurde jedoch in Spring 3.2 aufgegeben. Es wird empfohlen, XmlBeanDefinitionReader und DefaultListableBeanFactory zu verwenden.

Fügen Sie hier eine Bildbeschreibung ein

Die BeanFactory-Schnittstelle befindet sich oben im Klassenstrukturbaum. Ihre Hauptmethode ist getBean(String var1). Diese Methode gibt eine Bean mit einem bestimmten Namen aus dem Container zurück.

Die Funktionen von BeanFactory wurden kontinuierlich durch andere Schnittstellen erweitert. Beispielsweise definiert AbstractAutowireCapableBeanFactory eine Methode, um die Beans im Container automatisch nach bestimmten Regeln zusammenzustellen (z. B. Übereinstimmung nach Namen, Übereinstimmung nach Typ usw.).

Hier ist ein Beispiel für das Abrufen von Beans aus XMLBeanFactory (abgelaufen):

public class HelloWorldApp{
    
    
    public static void main(String[] args) {
    
    
        BeanFactory factory = new XmlBeanFactory (new ClassPathResource("beans.xml"));
        HelloWorld obj = (HelloWorld) factory.getBean("helloWorld");
        obj.getMessage();
    }
}

ApplicationContext-Schnittstelle

ApplicationContext ist von BeanFactory abgeleitet und bietet praktischere anwendungsorientierte Funktionen. Man kann sagen, dass die Verwendung von BeanFactory eine manuelle Datei und die Verwendung von ApplicationContext eine automatische Datei ist.

Fügen Sie hier eine Bildbeschreibung ein

ApplicationContext erbt die Schnittstellen HierachicalBeanFactory und ListableBeanFactory. Auf dieser Basis erweitert es auch die Funktionen von BeanFactory durch andere Schnittstellen, darunter:

  • Bean-Instanziierung/Verkabelung
  • Bean-Instanziierung/Verkettung
  • Automatische BeanPostProcessor-Registrierung
  • Automatische BeanFactoryPostProcessor-Registrierung
  • Bequemer MessageSource-Zugriff (i18n)
  • Die Veröffentlichung von ApplicationEvent unterscheidet sich vom verzögerten Laden von BeanFactory. Es ist vorab geladen, sodass jede Bean nach dem Start von ApplicationContext instanziiert wird.

Dies ist ein Beispiel für die Verwendung von ApplicationContext:

public class HelloWorldApp{
    
    
    public static void main(String[] args) {
    
    
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        HelloWorld obj = (HelloWorld) context.getBean("helloWorld");
        obj.getMessage();
    }
}

ApplicationContext enthält alle Funktionen von BeanFactory und es wird allgemein empfohlen, ersteres zu verwenden.

8. Wissen Sie, was der Spring-Container während der Startphase tun wird?

Der Arbeitsprozess des IOC-Containers von Spring kann tatsächlich in zwei Phasen unterteilt werden: die Container-Startphase und die Bean-Instanziierungsphase .

Die Hauptarbeit in der Container-Startphase besteht darin , die Konfigurationsdatei zu laden, zu analysieren und in der entsprechenden Bean-Definition zu speichern .

Fügen Sie hier eine Bildbeschreibung ein

Wenn der Container startet, lädt er zunächst die Konfigurationsmetadaten auf irgendeine Weise. In den meisten Fällen muss sich der Container auf bestimmte Toolklassen (BeanDefinitionReader) verlassen, um die geladenen Konfigurationsmetadaten zu analysieren und zu analysieren und die analysierten Informationen in entsprechenden BeanDefinitionen zu gruppieren

Fügen Sie hier eine Bildbeschreibung ein

Abschließend werden diese BeanDefinitions, die die notwendigen Informationen für die Bean-Definition speichern, in der entsprechenden BeanDefinitionRegistry registriert, sodass der Container-Start abgeschlossen ist.

9. Können Sie etwas über den Lebenszyklus von Spring Beans sagen?

Im Frühjahr ist der Zeitpunkt der Instanziierung des Basiscontainers BeanFactory und des erweiterten Containers ApplicationContext unterschiedlich. BeanFactory verwendet eine verzögerte Initialisierung, das heißt, die Bean wird nur instanziiert, wenn das erste getBean() gestartet wird; nach dem Start von ApplicationContext werden alle Bean-Definitionen ausgeführt wird instanziiert.

Der Lebenszyklus einer Bean im Spring IOC ist grob in vier Phasen unterteilt: Instanziierung, Attributzuweisung (Populate), Initialisierung und Zerstörung (Destruction) .

Fügen Sie hier eine Bildbeschreibung ein

Schauen wir uns einen etwas detaillierteren Prozess an:

  • Instanziierung : Schritt 1: Instanziieren Sie ein Bean-Objekt
  • Attributzuweisung : Schritt 2: Legen Sie zugehörige Attribute und Abhängigkeiten für die Bean fest
  • Initialisierung : In der Initialisierungsphase gibt es viele Schritte. Die Schritte 5 und 6 sind die eigentliche Initialisierung. Die Schritte 3 und 4 werden vor der Initialisierung ausgeführt. Schritt 7 wird nach der Initialisierung ausgeführt. Nach Abschluss der Initialisierung kann die Bean verwendet werden.
  • Zerstörung : Schritte 8-10. Schritt 8 kann eigentlich als Zerstörungsstufe gezählt werden, stellt jedoch keine Zerstörung im eigentlichen Sinne dar. Stattdessen wird die entsprechende aufrufende Schnittstelle für die Zerstörung vor der Verwendung registriert, sodass die folgenden Schritte 9 und 10 ausgeführt werden können Zerstöre es tatsächlich. Bean und führe dann die entsprechende Methode aus

Fügen Sie hier eine Bildbeschreibung ein

Um es kurz zusammenzufassen: Es gibt weitere Schritte im Initialisierungsprozess im Bean-Lebenszyklus, wie z. B. die Vor- und Nachbearbeitung.

Schauen wir uns abschließend die spezifischen Details anhand eines Beispiels an:

Fügen Sie hier eine Bildbeschreibung ein

Eine detaillierte Code-Implementierung von PersonBean-Klasseninstanzen finden Sie in diesem Artikel: Der Lebenszyklus eines Bean-Containers ist wie ein menschliches Leben.

10.Welche Methoden gibt es zur Bean-Definition und Abhängigkeitsdefinition?

Es gibt drei Methoden: direkte Codierungsmethode, Konfigurationsdateimethode und Anmerkungsmethode .

Fügen Sie hier eine Bildbeschreibung ein

  • Direkte Kodierungsmethode: Wir haben im Allgemeinen keinen Zugriff auf die direkte Kodierungsmethode, aber tatsächlich werden letztendlich andere Methoden durch direkte Kodierung implementiert.
  • Konfigurationsdateimethode: Konfigurieren Sie die entsprechenden Abhängigkeiten über XML- und Eigenschaftentyp-Konfigurationsdateien, und Spring liest die Konfigurationsdateien, um die Abhängigkeitsinjektion abzuschließen.
  • Annotationsmethode: Die Annotationsmethode sollte die am häufigsten verwendete Methode sein. Verwenden Sie Annotationsänderungen an den entsprechenden Stellen, und Spring scannt die Annotationen und schließt die Abhängigkeitsinjektion ab.

11.Welche Abhängigkeitsinjektionsmethoden gibt es?

Spring unterstützt die Konstruktormethodeninjektion , Eigenschaftsinjektion und Fabrikmethodeninjektion . Die Fabrikmethodeninjektion kann in statische Fabrikmethodeninjektion und nicht statische Fabrikmethodeninjektion unterteilt werden .

Fügen Sie hier eine Bildbeschreibung ein

  • Konstruktorinjektion:
    Durch Aufrufen des Konstruktors der Klasse wird die Schnittstellenimplementierungsklasse über die Konstruktorvariable übergeben.
public CatDaoImpl(String message){
    
    
	this. message = message;
}
<bean id="CatDaoImpl" class="com.CatDaoImpl">
	<constructor-arg value=" message "></constructor-arg>
</bean>
  • Die Eigenschaftsinjektion
    vervollständigt die Injektion von Abhängigkeiten, die von der aufrufenden Klasse über die Setter-Methode benötigt werden.
public class Id {
    
    
    private int id;
    public int getId() {
    
     return id; }
    public void setId(int id) {
    
     this.id = id; }
}
<bean id="id" class="com.id ">
	<property name="id" value="123"></property>
</bean>
  • Injektion mit werkseitiger Methode

    • Statische Werkzeuginjektion

      Wie der Name schon sagt, besteht die statische Fabrik darin, die von Ihnen benötigten Objekte durch Aufrufen der statischen Fabrikmethode abzurufen. Damit Spring alle Objekte verwalten kann, können wir die Objekte nicht 工程类.静态方法()direkt über „“ abrufen, sondern erhalten sie dennoch durch Spring-Injection:

      public class DaoFactory {
              
               //静态工厂
          public static final FactoryDao getStaticFactoryDaoImpl(){
              
              
          	return new StaticFacotryDaoImpl();
          }
      }
      public class SpringAction {
              
              
          //注入对象
          private FactoryDao staticFactoryDao;
          //注入对象的 set 方法
          public void setStaticFactoryDao(FactoryDao staticFactoryDao) {
              
              
          	this.staticFactoryDao = staticFactoryDao;
          }
      }
      
      <!--factory-method="getStaticFactoryDaoImpl"指定调用哪个工厂方法>
      
      <bean name="springAction" class=" SpringAction" >
          <!--使⽤用静态工厂的方法注入对象,对应下面的配置⽂文件-->
          <property name="staticFactoryDao" ref="staticFactoryDao"></property>
      </bean>
      
      <!--此处获取对象的方式是从工厂类中获取静态方法-->
      <bean name="staticFactoryDao" class="DaoFactory" factory-method="getStaticFactoryDaoImpl"></bean>
      
    • Nicht statische Fabrikeinspritzung

      Eine nicht statische Fabrik, auch Instanzfabrik genannt, bedeutet, dass die Fabrikmethode nicht statisch ist. Daher müssen wir zuerst eine neue Fabrikinstanz erstellen und dann die normale Instanzmethode aufrufen.

      //非静态工厂
      public class DaoFactory {
              
              
          public FactoryDao getFactoryDaoImpl(){
              
              
          	return new FactoryDaoImpl();
          }
      }
      public class SpringAction {
              
              
          //注入对象
          private FactoryDao factoryDao;
          public void setFactoryDao(FactoryDao factoryDao) {
              
              
          	this.factoryDao = factoryDao;
          }
      }
      
      <bean name="springAction" class="SpringAction">
          <!--使用非静态工厂的方法注入对象,对应下面的配置文件-->
          <property name="factoryDao" ref="factoryDao"></property>
      </bean>
      
      <!--此处获取对象的方式是从工厂类中获取实例方法-->
      <bean name="daoFactory" class="com.DaoFactory"></bean>
      <bean name="factoryDao" factory-bean="daoFactory" factory-method="getFactoryDaoImpl"></bean>
      

12.Welche automatischen Montagemethoden bietet Spring?

Was ist Autowiring?

Der Spring IOC-Container kennt die Konfigurationsinformationen aller Beans. Darüber hinaus können die Strukturinformationen der Implementierungsklasse, wie z. B. die Struktur und Attribute der Konstruktormethode, auch über den Java-Reflexionsmechanismus abgerufen werden. Nachdem er diese Informationen zu allen Beans beherrscht, kann der Spring IOC-Container die Beans im Container automatisch nach bestimmten Regeln zusammenstellen, ohne explizit Abhängigkeiten zu konfigurieren.

Diese von Spring bereitgestellte Methode kann Beans automatisch nach bestimmten Regeln zusammenstellen. Das <bean>-Element stellt ein Attribut bereit, das den Autoassembly-Typ angibt: autowire="<autowiring type>"

Welche Arten der automatischen Verkabelung bietet Spring an?

Spring bietet 4 Arten der automatischen Verkabelung:

Fügen Sie hier eine Bildbeschreibung ein

  • byName: Automatischer Abgleich basierend auf dem Namen. Angenommen, Boss hat ein anderes Attribut mit dem Namen car. Wenn sich zufällig eine Bean mit dem Namen car im Container befindet, fügt Spring sie automatisch dem Autoattribut des Bosses hinzu.
  • byType: Automatischer Abgleich basierend auf dem Typ. Angenommen, Boss hat ein Autotyp-Attribut. Wenn sich zufällig eine Bean vom Typ Auto im Container befindet, fügt Spring sie automatisch dem Boss-Attribut hinzu.
  • Konstruktor: Ähnlich wie byType, außer dass es für die Konstruktorinjektion gedacht ist. Wenn Boss einen Konstruktor hat, enthält der Konstruktor einen Eingabeparameter vom Typ „Car“. Wenn sich im Container eine Bean vom Typ „Car“ befindet, verwendet Spring diese Bean automatisch als Eingabeparameter des Boss-Konstruktors. Wenn im Container kein Konstruktor gefunden wird, Wenn der Eingabeparameter mit dem Bean-Typ übereinstimmt, löst Spring eine Ausnahme aus.
  • Autodetect: Bestimmen Sie basierend auf dem Selbstprüfungsmechanismus der Bean, ob byType oder ein Konstruktor für die automatische Assemblierung verwendet werden soll. Wenn die Bean einen Standardkonstruktor bereitstellt, wird byType verwendet, andernfalls wird der Konstruktor verwendet.

13. Welchen Umfang haben Bohnen im Frühling?

Spring's Beans unterstützen hauptsächlich fünf Bereiche:

Fügen Sie hier eine Bildbeschreibung ein

  • Singleton : Es gibt nur eine Bean-Instanz im Spring-Container. Die Bean existiert als einzelne Instanz und ist der Standardbereich der Bean.
  • Prototyp : Jedes Mal, wenn eine Bean aus dem Container aufgerufen wird, wird eine neue Instanz zurückgegeben.

Die folgenden drei Bereiche gelten nur in Webanwendungen:

  • Anfrage : Jede HTTP-Anfrage generiert ein neues Bean, das nur innerhalb der aktuellen HTTP-Anfrage gültig ist.
  • Sitzung : Dieselbe HTTP-Sitzung teilt sich ein Bean, und verschiedene HTTP-Sitzungen verwenden unterschiedliche Beans.
  • globalSession : Dieselbe globale Sitzung teilt sich ein Bean und wird nur für Protlet-basierte Webanwendungen verwendet. Sie existiert in Spring 5 nicht mehr.

14. Wird es bei Singleton-Beans im Frühjahr Probleme mit der Thread-Sicherheit geben?

Hier zunächst die Schlussfolgerung: Singleton Beans im Frühling sind nicht threadsicher .

Da ein Singleton-Bean nur ein globales Bean hat, wird es von allen Threads gemeinsam genutzt.

Wenn eine Singleton-Bean zustandslos ist , das heißt, die Operationen im Thread führen keine anderen Vorgänge als die Abfrage der Mitgliedsvariablen in der Bean aus , dann ist diese Singleton-Bean threadsicher. Beispielsweise sind Controller, Service, Dao usw. von Spring MVC die meisten dieser Beans zustandslos und konzentrieren sich nur auf die Methode selbst.

Wenn die Bean zustandsbehaftet ist , das heißt, die Mitgliedsvariablen in der Bean werden geschrieben , liegt möglicherweise ein Thread-Sicherheitsproblem vor.

Fügen Sie hier eine Bildbeschreibung ein

Wie kann das Thread-Sicherheitsproblem von Singleton Bean gelöst werden?

Zu den gängigen Lösungen gehören:

  1. Definieren Sie die Bean als mehrere Instanzen
    , sodass für jede Thread-Anfrage eine neue Bean erstellt wird. Dies erschwert jedoch die Verwaltung der Bean durch den Container und ist auf diese Weise nicht möglich .
  2. Vermeiden Sie die Definition veränderlicher Mitgliedsvariablen im Bean-Objekt.
    Dies ist selbst dann nicht möglich, wenn Sie es entsprechend zuschneiden.
  3. Speichern Sie die Mitgliedsvariablen in der Bean in ThreadLocal.
    Wir wissen, dass ThredLoca die Isolierung von Variablen unter Multithreading sicherstellen kann. Sie können eine ThreadLocal-Mitgliedsvariable in der Klasse definieren und die erforderlichen variablen Mitgliedsvariablen in ThreadLocal speichern. Dies ist die empfohlene Methode . Weg.

15. Sprechen Sie über zirkuläre Abhängigkeiten?

Was ist eine zirkuläre Abhängigkeit?

Fügen Sie hier eine Bildbeschreibung ein

Frühlingszirkelabhängigkeit: Einfach ausgedrückt hängt sie von sich selbst oder von anderen Bohnen ab.

Fügen Sie hier eine Bildbeschreibung ein

Nur Singleton-Beans haben zirkuläre Abhängigkeiten. Im Fall von Prototypen (Prototypen) löst Spring direkt eine Ausnahme aus. Der Grund ist sehr einfach: AB ist zirkulär abhängig. Wenn A instanziiert wird, wird festgestellt, dass es von B abhängt, und eine Instanz von B wird erstellt. Wenn B erstellt wird, wird festgestellt, dass A benötigt wird, und eine Instanz von A1 entsteht... Unendliche Matroschka-Puppen bringen das System direkt zum Einsturz.

In welchen Situationen kann Spring zirkuläre Abhängigkeiten auflösen?

Spring unterstützt keine zirkulären Abhängigkeiten basierend auf der Konstruktor-Injektion. Was aber, wenn AB-zirkuläre Abhängigkeiten eine Konstruktor-Injektion und die andere eine Setter-Injektion sind?

Schauen wir uns einige Szenarien an:

Fügen Sie hier eine Bildbeschreibung ein

Der Grund, warum das vierte möglich ist, das fünfte jedoch nicht, liegt darin, dass Spring Beans beim Erstellen standardmäßig in der natürlichen Reihenfolge erstellt, sodass A vor B erstellt wird.

Um es kurz zusammenzufassen: Wenn die Instanzen zirkulärer Abhängigkeiten mit der Setter-Methode injiziert werden, kann Spring dies unterstützen. Wenn sie mit dem Konstruktor injiziert werden, wird dies nicht unterstützt. Wenn Konstruktor-Injektion und Setter-Injektion gleichzeitig vorhanden sind, kommt es darauf an am Himmel.

16. Wie löst Spring also zirkuläre Abhängigkeiten?

PS: Tatsächlich ist die richtige Antwort, dass Entwickler gut entwerfen und Beans keine zyklischen Abhängigkeiten zulassen, aber das geht auf keinen Fall, der Interviewer möchte das nicht hören.

Wir alle wissen, dass es drei Schritte gibt, um die Initialisierung einer Singleton-Bean abzuschließen:

Fügen Sie hier eine Bildbeschreibung ein

Die Injektion erfolgt im zweiten Schritt, der Attributzuweisung. In Kombination mit diesem Prozess löst Spring die zirkuläre Abhängigkeit durch den Cache der dritten Ebene:

  1. Cache der Ebene 1: Map<String, Object> singletonObjects , Singleton-Pool, wird zum Speichern von Bean-Instanzen verwendet, die instanziiert, Eigenschaften zugewiesen (injiziert) und initialisiert wurden.
  2. Cache der zweiten Ebene: Map<String, Object> EarlySingletonObjects , frühes Belichtungsobjekt, das zum Speichern von instanziierten Bean-Instanzen verwendet wird
  3. Cache der Ebene 3: Map<String, ObjectFactory<?>> singletonFactories , früh verfügbar gemachte Objektfabrik, die zum Speichern der Bean-Erstellungsfabrik verwendet wird, damit spätere Erweiterungen die Möglichkeit haben, Proxy-Objekte zu erstellen.

Fügen Sie hier eine Bildbeschreibung ein

Werfen wir einen Blick auf den Prozess der Auflösung zirkulärer Abhängigkeiten im Cache der dritten Ebene:

Wenn zwei Klassen A und B zirkuläre Abhängigkeiten haben:

Fügen Sie hier eine Bildbeschreibung ein

Initialisierungsprozess einer Instanz:

  1. Erstellen Sie eine Instanz von A. Legen Sie beim Instanziieren die A-Objektfabrik in den Cache der dritten Ebene, was bedeutet, dass mit der Instanziierung von A begonnen wurde. Obwohl mein Objekt noch nicht vollständig ist, werde ich es zuerst offenlegen, um alle darüber zu informieren.

Fügen Sie hier eine Bildbeschreibung ein

  1. Wenn A Attribute einfügt, wird festgestellt, dass es von B abhängt. Zu diesem Zeitpunkt wurde B noch nicht erstellt und instanziiert daher B.
  2. Wenn B Attribute einfügt und feststellt, dass es von A abhängt, findet es in ähnlicher Weise das A-Objekt aus dem Cache. Fragen Sie A nacheinander vom Cache der ersten Ebene zum Cache der dritten Ebene ab, rufen Sie A über die Objektfabrik vom Cache der dritten Ebene ab und stellen Sie fest, dass A zwar nicht perfekt ist, aber existiert, und legen Sie A in den Cache der zweiten Ebene und löschen Sie gleichzeitig A im Cache der dritten Ebene. Wenn B instanziiert und initialisiert wurde, legen Sie B in den Cache der ersten Ebene.

Fügen Sie hier eine Bildbeschreibung ein

  1. Dann setzt A die Attributzuweisung fort und ruft erfolgreich das instanziierte und initialisierte B-Objekt aus dem Cache der ersten Ebene ab. Die Erstellung des A-Objekts ist ebenfalls abgeschlossen, A wird im Cache der zweiten Ebene gelöscht und A in den Cache der ersten Ebene verschoben .
  2. Schließlich speichert der Cache der ersten Ebene die A- und B-Objekte, die instanziiert und initialisiert wurden.

Fügen Sie hier eine Bildbeschreibung ein

Wir wissen also, warum Spring die zirkuläre Abhängigkeit der Setter-Injektion lösen kann, da Instanziierung und Eigenschaftszuweisung getrennt sind, sodass Raum für Operationen vorhanden ist. Wenn sie alle vom Konstruktor injiziert werden, muss die Injektion im Instanziierungsschritt abgeschlossen werden und kann daher natürlich nicht unterstützt werden.

17. Warum dreistufiger Cache? Funktioniert Level 2 nicht?

Nein, es geht hauptsächlich darum, Proxy-Objekte zu generieren . Wenn kein Proxy vorhanden ist, ist es in Ordnung, den Cache der zweiten Ebene zum Auflösen zirkulärer Abhängigkeiten zu verwenden. Wenn es jedoch einen Agenten gibt, gibt es auf Ebene drei kein Problem, auf Ebene zwei jedoch nicht.

Da der Cache der dritten Ebene anonyme innere Klassen enthält, die bestimmte Objekte generieren , kann er beim Abrufen eines Objekts ein Proxy-Objekt generieren oder ein normales Objekt zurückgeben . Der Hauptzweck der Verwendung des Caches der dritten Ebene besteht darin, sicherzustellen, dass jederzeit dasselbe Objekt verwendet wird .

Unter der Annahme, dass nur ein Cache der zweiten Ebene vorhanden ist, wird ein gewöhnliches Bean-Objekt im Cache der zweiten Ebene abgelegt. Während des Bean-Initialisierungsprozesses wird nach der Generierung des Proxy-Objekts durch den BeanPostProcessor das gewöhnliche Bean-Objekt im Cache der zweiten Ebene abgelegt wird überschrieben, was dazu führen kann, dass die erhaltenen Bean-Objekte inkonsistent sind.

Fügen Sie hier eine Bildbeschreibung ein

18. Was ist das Implementierungsprinzip von @Autowired?

Der Schlüssel zur Implementierung von @Autowired ist: AutowiredAnnotationBeanPostProcessor

Während der Initialisierungsphase des Beans werden einige Vor- und Nachbearbeitungen durch die Bean-Vor- und -Postprozessoren durchgeführt.

Die Funktion von @Autowired wird über den Postprozessor implementiert. Dieser Postprozessor ist AutowiredAnnotationBeanPostProcessor.

  • Beim Erstellen der Bean ruft Spring schließlich doCreateBean()die Methode auf, unddoCreateBean() die Methode wird in der Methode aufgerufen, populateBean()um die Eigenschaften der Bean auszufüllen und die automatische Montage und andere Arbeiten abzuschließen.

  • populateBean()In der Methode werden insgesamt zwei Postprozessoren aufgerufen. Das erste Mal besteht darin, festzustellen, ob eine Attributfüllung erforderlich ist. Wenn keine Attributfüllung erforderlich ist, erfolgt die Rückgabe direkt. Wenn eine Attributfüllung erforderlich ist, fährt die Methode fort Nach der Ausführung wird später der zweite Postprozessor aufgerufen. Zu diesem Zeitpunkt wird die Methode von AutowiredAnnotationBeanPostProcessor aufgerufenpostProcessPropertyValues() , in der die @Autowired-Annotation analysiert und anschließend die automatische Montage implementiert wird.

  • postProcessorPropertyValues()In der Methode findAutowiringMetadata()wird zuerst die Methode aufgerufen, um die Eigenschaften und Methoden mit der Annotation @Autowired, @Inject und @Value in der Bean zu analysieren. Rufen Sie dann metadata.inject()die Methode auf, um die Attribute einzugeben.

AOP

19. Was ist AOP?

AOP: Aspektorientierte Programmierung. Einfach ausgedrückt besteht es darin, denselben Code in einer Geschäftslogik in ein unabhängiges Modul zu extrahieren, um die Geschäftslogik klarer zu machen.

Fügen Sie hier eine Bildbeschreibung ein

Konkret: Wenn ich mit CRUD eine Reihe von Geschäftsberichten schreiben möchte, wie kann ich dann Protokolle drucken und Parameter vor und nach dem Geschäftscode überprüfen?

Wir können 日志记录wiederverwendbare 数据校验Funktionsmodule trennen und diese Codes dann dynamisch an geeigneten Stellen in der Programmausführung einfügen und ausführen. Dies vereinfacht das Schreiben von Code.

Fügen Sie hier eine Bildbeschreibung ein

Im Geschäftslogikcode ist kein Code an der allgemeinen Logik beteiligt. Das Geschäftsmodul ist prägnanter und enthält nur den Kerngeschäftscode. Es erreicht eine Codetrennung zwischen Geschäftslogik und allgemeiner Logik , erleichtert Wartung und Upgrades und reduziert die Kopplung zwischen Geschäftslogik und allgemeiner Logik.

AOP kann über die gesamte Anwendung verteilte Funktionen in wiederverwendbare Komponenten aufteilen. Fügen Sie dem Programm beim Kompilieren, Laden oder zur Laufzeit dynamisch Funktionalität hinzu , ohne den Quellcode zu ändern . Dadurch wird die Isolierung der Geschäftslogik erreicht und die Modularität des Codes verbessert.

Fügen Sie hier eine Bildbeschreibung ein

Der Kern von AOP ist eigentlich ein dynamischer Proxy . Wenn die Schnittstelle implementiert ist, wird der dynamische JDK-Proxy verwendet. Andernfalls wird der CGLIB-Proxy verwendet. Er wird hauptsächlich zur Verarbeitung einiger Dienste auf Systemebene mit übergreifenden Eigenschaften verwendet. wie Protokollsammlung, Transaktionsverwaltung, Sicherheitsprüfung, Caching, Objektpoolverwaltung usw.

Was sind die Kernkonzepte von AOP?

  • Aspekt : ​​Eine Klasse ist eine Abstraktion von Objekteigenschaften und ein Aspekt ist eine Abstraktion von Querschnittsthemen.

  • Verbindungspunkt : Der abgefangene Punkt. Da Spring nur Verbindungspunkte vom Methodentyp unterstützt, bezieht sich der Verbindungspunkt in Spring auf die abgefangene Methode . Tatsächlich kann der Verbindungspunkt auch ein Feld oder ein Konstruktor sein.

  • Pointcut : Positionierung zum Abfangen des Verbindungspunkts

  • Hinweis : Die sogenannte Benachrichtigung bezieht sich auf den Code, der nach dem Abfangen des Verbindungspunkts ausgeführt werden soll , und kann auch als Erweiterung bezeichnet werden.

  • Ziel : Das Zielobjekt des Agenten

  • Weabing : Beim Weabing werden Verbesserungen an bestimmten Verbindungspunkten einer Zielklasse hinzugefügt .

    • Weben zur Kompilierungszeit: Aspekte werden beim Kompilieren der Zielklasse eingebunden

    • Weben der Klassenladezeit: Aspekte werden gewebt, wenn die Zielklasse in die JVM geladen wird. Es sind spezielle Klassenlader erforderlich, die den Bytecode einer Zielklasse erweitern, bevor er in die Anwendung eingeführt wird.

    • Runtime-Weben: Aspekte werden irgendwann während der Ausführung der Anwendung eingebunden. Typischerweise erstellt der AOP-Container beim Einbinden von Aspekten dynamisch ein Proxy-Objekt für das Zielobjekt. SpringAOP verwebt auf diese Weise Aspekte.

      Spring verwendet Runtime-Weaving, während AspectJ Compile-Time-Weaving und Class-Loader-Weaving verwendet.

  • Einführung : Einführung ist eine spezielle Erweiterung, mit der einer Klasse dynamisch einige Eigenschaften und Methoden hinzugefügt werden können

Welche Wraparound-Optionen gibt es für AOP?

AOP verfügt im Allgemeinen über 5 Verpackungsmethoden:

  • Vorabbenachrichtigung (@Before)
  • Rücksendebenachrichtigung (@AfterReturning)
  • Ausnahmebenachrichtigung (@AfterThrowing)
  • Benachrichtigung posten (@After)
  • Around-Benachrichtigungen (@Around)

Fügen Sie hier eine Bildbeschreibung ein

Bei mehreren Aspekten können Sie die Reihenfolge über @Order festlegen. Je kleiner die Zahl, desto höher die Priorität.

20. Verwenden Sie normalerweise AOP?

Hier ist ein kleines Beispiel: Im SpringBoot-Projekt ist es relativ schnell, AOP zum Drucken der Eingabe- und Ausgabeparameterprotokolle der Schnittstelle sowie der Ausführungszeit zu verwenden.

  • Abhängigkeiten einführen: AOP-Abhängigkeiten einführen

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>
    
  • Benutzerdefinierte Anmerkung: Passen Sie eine Anmerkung als Schnittpunkt an

    @Retention(RetentionPolicy.RUNTIME)
    @Target({
          
          ElementType.METHOD})
    @Documented
    public @interface WebLog {
          
          
    }
    
  • Konfigurieren Sie den AOP-Aspekt:

    • @Aspect: identifiziert Aspekte

    • @Pointcut: Legen Sie den Schnittpunkt fest. Hier wird die benutzerdefinierte Anmerkung als Schnittpunkt verwendet. Es gibt viele andere Möglichkeiten, den Schnittpunkt zu definieren, und die benutzerdefinierte Anmerkung wird am häufigsten verwendet.

    • @Before: Weben Sie vor dem Punktschnittpunkt ein und geben Sie einige Eingabeparameterinformationen aus

    • @Around: Umgeben Sie den Tangentenpunkt, geben Sie Rückgabeparameter und die Ausführungszeit der Schnittstelle aus

      @Aspect
      @Component
      public class WebLogAspect {
              
              
      
          private final static Logger logger = LoggerFactory.getLogger(WebLogAspect.class);
      
          /**
           * 以自定义 @WebLog 注解为切点
           **/
          @Pointcut("@annotation(cn.fighter3.spring.aop_demo.WebLog)")
          public void webLog() {
              
              }
      
          /**
           * 在切点之前织入
           */
          @Before("webLog()")
          public void doBefore(JoinPoint joinPoint) throws Throwable {
              
              
              // 开始打印请求日志
              ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
              HttpServletRequest request = attributes.getRequest();
              // 打印请求相关参数
              logger.info("========================================== Start ==========================================");
              // 打印请求 url
              logger.info("URL:{}", request.getRequestURL().toString());
              // 打印 Http method
              logger.info("HTTP Method: {}", request.getMethod());
              // 打印调用 controller 的全路径以及执行方法
              logger.info("Class Method: {}.{}", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName());
              // 打印请求的 IP
              logger.info("IP: {}", request.getRemoteAddr());
              // 打印请求入参
              logger.info("Request Args: {}",new ObjectMapper().writeValueAsString(joinPoint.getArgs()));
          }
      
          /**
           * 在切点之后织入
           * @throws Throwable
           */
          @After("webLog()")
          public void doAfter() throws Throwable {
              
              
              // 结束后打个分隔线,方便查看
              logger.info("=========================================== End ===========================================");
          }
      
          /**
           * 环绕
           */
          @Around("webLog()")
          public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
              
              
              //开始时间
              long startTime = System.currentTimeMillis();
              Object result = proceedingJoinPoint.proceed();
              // 打印出参
              logger.info("Response Args: {}", new ObjectMapper().writeValueAsString(result));
              // 执行耗时
              logger.info("Time-Consuming: {} ms", System.currentTimeMillis() - startTime);
              return result;
          }
      
      }
      
  • Verwendung: Fügen Sie der Benutzeroberfläche einfach benutzerdefinierte Anmerkungen hinzu

    @GetMapping("/hello")
    @WebLog(desc = "这是一个欢迎接口")
    public String hello(String name){
          
          
    	return "Hello "+name;
    }
    
  • Ausführungsergebnisse: Sie können sehen, dass das Protokoll die Eingabeparameter, Ausgabeparameter und die Ausführungszeit druckt.

Fügen Sie hier eine Bildbeschreibung ein

21. Sprechen Sie über den dynamischen JDK-Proxy und den CGLIB-Proxy?

Springs AOP wird durch dynamische Proxys implementiert. Es gibt zwei Hauptarten dynamischer Proxys : JDK-dynamische Proxys und Cglib-dynamische Proxys . Die Verwendung und die Prinzipien dieser beiden dynamischen Proxys sind etwas unterschiedlich.

Dynamischer JDK-Proxy

  1. Schnittstelle : Für den dynamischen JDK-Proxy muss die Zielklasse eine Schnittstelle implementieren.

  2. InvocationHandler : InvocationHandler ist eine Schnittstelle. Sie können diese Schnittstelle implementieren, um übergreifende Logik zu definieren, und dann den Code der Zielklasse über den Reflexionsmechanismus (Aufruf) aufrufen. In diesem Prozess kann die Logik in Pre- und Post-Pakete gepackt werden -Verarbeiten Sie die Zielmethode.

  3. Proxy : Proxy verwendet InvocationHandler, um dynamisch eine Instanz zu erstellen, die der von der Zielklasse implementierten Schnittstelle entspricht, und generiert ein Proxy-Paar der Zielklasse.

Schauen wir uns ein häufiges kleines Szenario an, den Kundendiensttransfer zur Lösung von Benutzerproblemen:

Fügen Sie hier eine Bildbeschreibung ein

JDK-Implementierung des dynamischen Proxys:

Fügen Sie hier eine Bildbeschreibung ein

  • Schnittstelle

    public interface ISolver {
          
          
        void solve();
    }
    
  • Zielklasse: Die entsprechende Schnittstelle muss implementiert werden

    public class Solver implements ISolver {
          
          
        @Override
        public void solve() {
          
          
            System.out.println("疯狂掉头发解决问题……");
        }
    }
    
  • Dynamische Proxy-Fabrik: ProxyFactory, die direkt Reflektion verwendet, um ein Proxy-Objekt für das Zielobjekt zu generieren. Hier wird eine anonyme innere Klasse verwendet, um die InvocationHandler-Methode neu zu schreiben, und das Umschreiben der Schnittstelle ist ähnlich.

    public class ProxyFactory {
          
          
    
        // 维护一个目标对象
        private Object target;
    
        public ProxyFactory(Object target) {
          
          
            this.target = target;
        }
    
        // 为目标对象生成代理对象
        public Object getProxyInstance() {
          
          
            return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),
                    new InvocationHandler() {
          
          
                        @Override
                        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
          
          
                            System.out.println("请问有什么可以帮到您?");
    
                            // 调用目标对象方法
                            Object returnValue = method.invoke(target, args);
    
                            System.out.println("问题已经解决啦!");
                            return null;
                        }
                    });
        }
    }
    
  • Client: Client, generiert eine Proxy-Objektinstanz und ruft die Zielobjektmethode über das Proxy-Objekt auf

    public class Client {
          
          
        public static void main(String[] args) {
          
          
            //目标对象:程序员
            ISolver developer = new Solver();
            //代理:客服小姐姐
            ISolver csProxy = (ISolver) new ProxyFactory(developer).getProxyInstance();
            //目标方法:解决问题
            csProxy.solve();
        }
    }
    

Implementierung des dynamischen Cglib-Proxys:

Fügen Sie hier eine Bildbeschreibung ein

  • Zielklasse: Solver. Die Zielklasse hier muss die Schnittstelle nicht implementieren.

    public class Solver {
          
          
        public void solve() {
          
          
            System.out.println("疯狂掉头发解决问题……");
        }
    }
    
  • Dynamische Proxy-Fabrik:

    public class ProxyFactory implements MethodInterceptor {
          
          
    
       //维护一个目标对象
        private Object target;
    
        public ProxyFactory(Object target) {
          
          
            this.target = target;
        }
    
        //为目标对象生成代理对象
        public Object getProxyInstance() {
          
          
            //工具类
            Enhancer en = new Enhancer();
            //设置父类
            en.setSuperclass(target.getClass());
            //设置回调函数
            en.setCallback(this);
            //创建子类对象代理
            return en.create();
        }
    
        @Override
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
          
          
            System.out.println("请问有什么可以帮到您?");
            // 执行目标对象的方法
            Object returnValue = method.invoke(target, args);
            System.out.println("问题已经解决啦!");
            return null;
        }
    
    }
    
  • Kunde: Kunde

    public class Client {
          
          
        public static void main(String[] args) {
          
          
            //目标对象:程序员
            Solver developer = new Solver();
            //代理:客服小姐姐
            Solver csProxy = (Solver) new ProxyFactory(developer).getProxyInstance();
            //目标方法:解决问题
            csProxy.solve();
        }
    }
    

22. Sprechen Sie über den Unterschied zwischen Spring AOP und AspectJAOP?

Frühlings-AOP

Spring AOP ist eine Laufzeiterweiterung mit den folgenden Hauptfunktionen:

  1. Die Implementierung basiert auf einem dynamischen Proxy. Wenn eine Schnittstelle verwendet wird, wird standardmäßig der vom JDK bereitgestellte dynamische Proxy verwendet. Wenn es sich um eine Methode handelt, wird CGLIB verwendet.
  2. Spring AOP muss für die Verwaltung auf den IOC-Container angewiesen sein, kann nur im Spring-Container verwendet werden und wird mit reinem Java-Code implementiert.
  3. In Bezug auf die Leistung muss Spring AOP beim Starten des Containers generiert werden, da Spring AOP auf der Grundlage dynamischer Proxys implementiert wird. Außerdem wird die Tiefe des Stapels bei Methodenaufrufen erhöht, wodurch die Leistung von Spring AOP beeinträchtigt wird gut wie das von AspectJ.
  4. Spring AOP engagiert sich für die Lösung der häufigsten AOP (Methodenweberei) in der Entwicklung auf Unternehmensebene.

AspektJ

AspectJ ist ein benutzerfreundliches und leistungsstarkes AOP-Framework. Es stellt eine Erweiterung zur Kompilierungszeit dar und kann allein verwendet oder in andere Frameworks integriert werden. Es ist eine Komplettlösung für die AOP-Programmierung. Aspecty erfordert einen separaten Compiler AJC.

Aspecty ist ein statisches Weben , das durch Modifizieren des Codes implementiert wird. Das Weben wird vor der eigentlichen Ausführung abgeschlossen, sodass die von ihm generierten Klassen keinen zusätzlichen Laufzeitaufwand verursachen. Im Allgemeinen gibt es mehrere Webmöglichkeiten wie folgt:

  1. Weben zur Kompilierungszeit: Wenn Klasse A Aspecty verwendet, um ein Attribut hinzuzufügen, und Klasse B darauf verweist, erfordert dieses Szenario das Weben zur Kompilierungszeit, andernfalls kann Klasse B nicht kompiliert werden.
  2. Weben nach dem Kompilieren: Das heißt, die .class-Datei wurde generiert oder in ein JAR-Paket gepackt. Wenn wir in diesem Fall die Verarbeitung verbessern müssen, müssen wir Weben nach dem Kompilieren verwenden.
  3. Ladezeitweben: Bezieht sich auf das Weben beim Laden einer Klasse. Um das Weben während dieser Zeit zu erreichen, gibt es mehrere gängige Methoden.

Der Gesamtvergleich sieht wie folgt aus:

Fügen Sie hier eine Bildbeschreibung ein

Angelegenheiten

Das Wesentliche an Spring-Transaktionen ist eigentlich die Unterstützung von Transaktionen durch die Datenbank. Ohne Datenbanktransaktionsunterstützung kann Spring keine Transaktionsfunktionen bereitstellen.

Spring bietet lediglich eine einheitliche Transaktionsverwaltungsschnittstelle, und die spezifische Implementierung wird von jeder Datenbank selbst implementiert. Die Übermittlung und das Rollback von Datenbanktransaktionen werden über den datenbankeigenen Transaktionsmechanismus implementiert.

23. Welche Arten von Spring-Transaktionen gibt es?

Spring unterstützt zwei 编程式事务Verwaltungs- und 声明式Transaktionsverwaltungsmethoden:

Fügen Sie hier eine Bildbeschreibung ein

Programmatische Transaktionen

  • Die programmgesteuerte Transaktionsverwaltung verwendet TransactionTemplate und erfordert die explizite Ausführung von Transaktionen.

Deklarative Transaktionen

  • Das deklarative Transaktionsmanagement basiert auf AOP . Sein Kern besteht darin, die Methode vorher und nachher über die AOP-Funktion abzufangen und die Transaktionsverarbeitungsfunktion in die Abfangmethode einzubinden, dh eine Transaktion zu starten, bevor die Zielmethode startet, und die Transaktion nach der Ausführung der Zielmethode festzuschreiben oder je nach Ausführungsstatus zurückgesetzt.

  • Der Vorteil besteht darin, dass kein Transaktionsverwaltungscode in den Geschäftslogikcode gemischt werden muss. Sie müssen lediglich relevante Transaktionsregeldeklarationen in der Konfigurationsdatei vornehmen oder @Transactional-Annotationen verwenden, um Transaktionsregeln auf die Geschäftslogik anzuwenden und den Geschäftscode zu reduzieren. der Verschmutzung. Der einzige Nachteil besteht darin, dass die feinste Granularität nur auf die Methodenebene angewendet werden kann und nicht wie programmatische Transaktionen auf die Codeblockebene angewendet werden kann.

24. Die Transaktionsisolationsstufe von Spring?

Die Schnittstelle TransactionDefinition von Spring definiert Konstanten, die die Isolationsstufe darstellen. Natürlich entspricht sie hauptsächlich der Transaktionsisolationsstufe der Datenbank:

  1. ISOLATION_DEFAULT: Verwenden Sie die Standardisolationsgrenze der Back-End-Datenbank. MySQL ist standardmäßig auf wiederholbares Lesen eingestellt, Oracle standardmäßig auf festgeschriebenes Lesen.
  2. ISOLATION_READ_UNCOMMITTED: Nicht festgeschrieben lesen
  3. ISOLATION_READ_COMMITTED: Lesen festgeschrieben
  4. ISOLATION_REPEATABLE_READ: wiederholbares Lesen
  5. ISOLATION_SERIALIZABLE: Serialisierung

25. Der Transaktionsweitergabemechanismus von Spring?

Der Spring-Transaktionsausbreitungsmechanismus beschreibt, wie Spring das Verhalten dieser Transaktionen handhabt, wenn mehrere Transaktionen gleichzeitig vorhanden sind – im Allgemeinen bezieht er sich darauf, wenn mehrere Transaktionsmethoden sich gegenseitig aufrufen.

Der Mechanismus zur Transaktionsweitergabe wird mit einfachem ThreadLocal implementiert. Wenn also die aufgerufene Methode in einem neuen Thread aufgerufen wird, schlägt die Transaktionsweitergabe tatsächlich fehl.

Fügen Sie hier eine Bildbeschreibung ein

Das standardmäßige Transaktionsweitergabeverhalten von Spring ist PROPAFATION_REQUIRED, was für die meisten Situationen geeignet ist. Wenn mehrere ServiceX#methodX()in einer Transaktionsumgebung arbeiten (alle durch Spring-Transaktionen erweitert) und im Programm eine Aufrufkette vorhanden ist Service1#method1()->Service2#method2()->Service3#method3(), dann die drei Methoden dieser drei Serviceklassen Alle arbeiten in derselben Transaktion über den Transaktionsweitergabemechanismus von Spring.

26. Verstehen Sie das Prinzip der deklarativen Transaktionsimplementierung?

Das geschieht über AOP/dynamischen Proxy.

  • Erstellen Sie während der Bean-Initialisierungsphase ein Proxy-Objekt : Wenn der Spring-Container jede Singleton-Bean initialisiert, durchläuft er alle BeanPostProcessor-Implementierungsklassen im Container und führt seine postProcessAfterInitialization-Methode aus. Wenn er die postProcessAfterInitialization-Methode der AbstractAutoProxyCreator-Klasse ausführt, durchläuft er alle BeanPostProcessor-Implementierungsklassen im Container. Aspekt: ​​Suchen Sie den Aspekt, der mit der aktuell instanziierten Bean übereinstimmt. Hier erhalten Sie den Transaktionsattributaspekt, suchen die Annotation @Transactional und ihren Attributwert und erstellen dann ein Proxy-Objekt basierend auf dem erhaltenen Aspekt. Standardmäßig wird zum Erstellen des Proxys der dynamische JDK-Proxy verwendet. Wenn die Zielklasse eine Schnittstelle ist, verwenden Sie den dynamischen JDK-Proxy, andernfalls verwenden Sie Cglib.
  • Führen Sie beim Ausführen der Zielmethode Transaktionserweiterungsvorgänge aus : Wenn die Bean-Methode über das Proxy-Objekt aufgerufen wird, wird der entsprechende AOP-Erweiterungsinterceptor ausgelöst. Deklarative Transaktionen sind eine Art Surround-Erweiterung. Die entsprechende Schnittstelle ist die Implementierung der Transaktion Die Erweiterungsschnittstelle MethodInterceptorlautet TransactionInterceptor. Das Klassendiagramm lautet wie folgt:

Fügen Sie hier eine Bildbeschreibung ein

TransactionInterceptorIn der Methode führt der Transaktionsinterceptor die Transaktionsverarbeitung durch, indem er die Methode der invokeübergeordneten Klasse aufruft, einschließlich des Startens einer Transaktion, der Transaktionsübermittlung und des Ausnahme-Rollbacks.TransactionAspectSupportinvokeWithinTransaction

27. Unter welchen Umständen schlagen deklarative Transaktionen fehl?

Fügen Sie hier eine Bildbeschreibung ein

1. @Transactional wird auf nicht öffentliche geänderte Methoden angewendet

Wenn die Annotation „Transactional“ auf eine nicht öffentliche geänderte Methode angewendet wird, ist „Transactional“ ungültig.

Dies liegt daran, dass TransactionInterceptor (Transaction Interceptor) während des Spring AOP-Proxys vor und nach der Ausführung der Zielmethode abfängt. Die Intercept-Methode von DynamicAdvisedInterceptor (interne Klasse von CglibAopProxy) oder die Invoke-Methode von JdkDynamicAopProxy ruft indirekt die ComputeTransactionAttribute-Methode von AbstractFallbackTransactionAttributeSource auf, um sie abzurufen die transaktional kommentierte Transaktion . Konfigurationsinformationen.

protected TransactionAttribute computeTransactionAttribute(Method method,
    Class<?> targetClass) {
    
    
        // Don't allow no-public methods as required.
        if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
    
    
        return null;
}

Diese Methode prüft, ob der Modifikator der Zielmethode öffentlich ist. Wenn er nicht öffentlich ist, werden die Eigenschaftskonfigurationsinformationen von @Transactional nicht abgerufen.

2. Die Weitergabe des @Transactional-Annotationsattributs ist falsch eingestellt

  • TransactionDefinition.PROPAGATION_SUPPORTS: Wenn derzeit eine Transaktion vorhanden ist, treten Sie der Transaktion bei. Wenn derzeit keine Transaktion vorhanden ist, führen Sie die Ausführung nicht transaktional fort.
  • TransactionDefinition.PROPAGATION_NOT_SUPPORTED: Im nicht-transaktionalen Modus ausführen. Wenn derzeit eine Transaktion vorhanden ist, wird die aktuelle Transaktion ausgesetzt.
  • TransactionDefinition.PROPAGATION_NEVER: Wird im nicht-transaktionalen Modus ausgeführt und löst eine Ausnahme aus, wenn derzeit eine Transaktion vorhanden ist.

3. Das @Transactional-Annotationsattribut rollbackFor ist falsch eingestellt

rollbackFor kann den Ausnahmetyp angeben, der ein Transaktions-Rollback auslösen kann. Spring führt die Transaktion nur dann zurück, wenn standardmäßig eine ungeprüfte Ausnahme (eine von RuntimeException geerbte Ausnahme) oder ein Fehler ausgelöst wird. Andere Ausnahmen lösen kein Rollback der Transaktion aus.

Fügen Sie hier eine Bildbeschreibung ein

// 希望自定义的异常可以进行回滚
@Transactional(propagation= Propagation.REQUIRED,rollbackFor= MyException.class

Wenn die in der Zielmethode ausgelöste Ausnahme eine Unterklasse der durch rollbackFor angegebenen Ausnahme ist, wird die Transaktion ebenfalls zurückgesetzt.

4. Methodenaufrufe in derselben Klasse führen dazu, dass @Transactional ungültig wird.

Während der Entwicklung ist es unvermeidlich, Methoden in derselben Klasse aufzurufen. Beispielsweise gibt es eine Klasse Test, die eine Methode A hat. A ruft dann Methode B dieser Klasse auf (unabhängig davon, ob Methode B öffentlich oder privat geändert wird). , Methode A jedoch nicht. Deklarationsanmerkungstransaktion, und Methode B hat. Nach dem externen Aufruf von Methode A wird die Transaktion von Methode B nicht wirksam. Auch hier werden oft Fehler gemacht.

Warum passiert das? Tatsächlich wird dies durch die Verwendung des Spring AOP-Proxys verursacht, da die Transaktionsmethode nur dann vom von Spring generierten Proxy-Objekt verwaltet wird, wenn sie von Code außerhalb der aktuellen Klasse aufgerufen wird .

 //@Transactional
     @GetMapping("/test")
     private Integer A() throws Exception {
    
    
         CityInfoDict cityInfoDict = new CityInfoDict();
         cityInfoDict.setCityName("2");
         /**
          * B 插入字段为 3的数据
          */
         this.insertB();
        /**
         * A 插入字段为 2的数据
         */
        int insert = cityInfoDictMapper.insert(cityInfoDict);
        return insert;
    }

    @Transactional()
    public Integer insertB() throws Exception {
    
    
        CityInfoDict cityInfoDict = new CityInfoDict();
        cityInfoDict.setCityName("3");
        cityInfoDict.setParentCityId(3);

        return cityInfoDictMapper.insert(cityInfoDict);
    }

Diese Situation ist das häufigste Fehlerszenario bei @Transactional-Annotationen.

@Transactional
private Integer A() throws Exception {
    
    
    int insert = 0;
    try {
    
    
        CityInfoDict cityInfoDict = new CityInfoDict();
        cityInfoDict.setCityName("2");
        cityInfoDict.setParentCityId(2);
        /**
         * A 插入字段为 2的数据
         */
        insert = cityInfoDictMapper.insert(cityInfoDict);
        /**
         * B 插入字段为 3的数据
        */
        b.insertB();
    } catch (Exception e) {
    
    
        e.printStackTrace();
    }
}

Wenn innerhalb von Methode B eine Ausnahme ausgelöst wird und Methode A versucht, die Ausnahme von Methode B abzufangen, kann die Transaktion nicht normal zurückgesetzt werden und es wird eine Ausnahme ausgelöst:

org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only

MVC

28. Was sind die Kernkomponenten von Spring MVC?

  1. DispatcherServlet : Der Frontcontroller ist der Kern der gesamten Prozesssteuerung . Er steuert die Ausführung anderer Komponenten, führt eine einheitliche Planung durch und reduziert die Kopplung zwischen Komponenten. Er entspricht dem Oberbefehlshaber.
  2. Handler : Prozessor, vervollständigt eine bestimmte Geschäftslogik, äquivalent zu Servlet oder Action.
  3. HandlerMapping : Nachdem DispatcherServlet die Anforderung empfangen hat, ordnet es über HandlerMapping verschiedene Anforderungen verschiedenen Handlern zu.
  4. HandlerInterceptor : Der Prozessor-Interceptor ist eine Schnittstelle. Wenn Sie eine Abfangverarbeitung durchführen müssen, können Sie diese Schnittstelle implementieren.
  5. HandlerExecutionChain : Prozessorausführungskette, bestehend aus zwei Teilen: Handler und HandlerInterceptor (das System verfügt standardmäßig über einen HandlerInterceptor. Wenn Sie zusätzliche Abfangfunktionen einrichten müssen, können Sie einen Interceptor hinzufügen).
  6. HandlerAdapter : Prozessoradapter. Bevor Handler Geschäftsmethoden ausführt, muss er eine Reihe von Vorgängen ausführen, einschließlich der Überprüfung von Formulardaten, der Konvertierung von Datentypen, der Kapselung von Formulardaten in JavaBeans usw. Diese Vorgänge werden von HandlerApater abgeschlossen. Nur Entwickler benötigen DispatcherServlet muss sich auf die Verarbeitung der Geschäftslogik konzentrieren und führt verschiedene Handler über HandlerAdapter aus.
  7. ModelAndView : Lädt Modelldaten und Ansichtsinformationen und gibt sie als Verarbeitungsergebnis des Handlers an DispatcherServlet zurück.
  8. ViewResolver : View Resolver, über den DispatcheServlet logische Ansichten in physische Ansichten analysiert und schließlich dem Client mit den Rendering-Ergebnissen antwortet.

29.Spring MVC-Workflow?

Fügen Sie hier eine Bildbeschreibung ein

  1. Der Client sendet eine Anfrage an den Server, und diese Anfrage wird zunächst an den Front-End-Controller DispatcherServlet (auch zentraler Controller genannt) weitergeleitet.
  2. DispatcherServlet ruft nach Erhalt der Anforderung den HandlerMapping-Prozessor-Mapper auf. Daraus wissen wir, welcher Controller die Anfrage bearbeiten soll (der Controller wird nicht aufgerufen, sondern ist nur bekannt).
  3. DispatcherServlet ruft den HandlerAdapter-Prozessoradapter auf und teilt dem Prozessoradapter mit, welchen Controller er ausführen soll.
  4. Der HandlerAdapter-Prozessoradapter führt den Controller aus, ruft ModelAndView (Daten und Ansicht) ab und gibt es Schicht für Schicht an das DispatcherServlet zurück.
  5. DispatcherServlet übergibt ModelAndView zum Parsen an den ViewReslover-Ansichtsparser und gibt dann die echte Ansicht zurück.
  6. DispatcherServlet füllt Modelldaten in die Ansicht
  7. DispatcherServlet antwortet dem Client mit den Ergebnissen

Obwohl der Gesamtprozess von Spring MVC komplex ist, ist er in der tatsächlichen Entwicklung sehr einfach. Die meisten Komponenten müssen nicht von Entwicklern erstellt und verwaltet werden. Sie müssen nur über Konfigurationsdateien konfiguriert werden. Nur Handler (Controller) müssen wirklich konfiguriert werden Von Entwicklern verarbeitet . , Ansicht , Modell .

Natürlich basiert der größte Teil unserer aktuellen Entwicklung auf der Trennung von Front-End und Back-End, einer Schnittstelle im Restful-Stil, und das Back-End muss nur Json-Daten zurückgeben.

30.Wie läuft die Schnittstelle im Restful-Stil von SpringMVC ab?

PS: Das ist ein völlig neues Stereotyp. Schließlich sollte niemand mehr die ModelAndView-Methode verwenden, oder? Heutzutage gibt es separate Front-End- und Back-End-Schnittstellen und es ist Zeit für die Aktualisierung achtteiliger Software.

Wir alle kennen die Restful-Schnittstelle und das Antwortformat ist JSON, das eine gemeinsame Annotation verwendet: @ResponseBody

@GetMapping("/user")
@ResponseBody
public User user(){
    
    
    return new User(1,"张三");
}

Nach dem Hinzufügen dieser Anmerkung ist der Gesamtprozess im Allgemeinen derselbe wie bei der Verwendung von ModelAndView, es gibt jedoch einige Unterschiede im Detail:

Fügen Sie hier eine Bildbeschreibung ein

  1. Der Client sendet eine Anfrage an den Server. Diese Anfrage wird zunächst an den Front-End-Controller DispatcherServlet gesendet.

  2. DispatcherServlet ruft nach Erhalt der Anforderung den HandlerMapping-Prozessor-Mapper auf . Daraus wissen wir, welcher Controller die Anfrage bearbeiten soll

  3. DispatcherServlet ruft den HandlerAdapter-Prozessoradapter auf und teilt dem Prozessoradapter mit, welchen Controller er ausführen soll .

  4. Der Controller ist in eine ServletInvocableHandlerMethod gekapselt, und der HandlerAdapter-Prozessoradapter führt die invokeAndHandle-Methode aus , um die Anforderungsverarbeitung für den Controller abzuschließen.

  5. Nachdem HandlerAdapter die Anforderung an den Controller ausgeführt hat, ruft er HandlerMethodReturnValueHandler auf, um den Rückgabewert zu verarbeiten . Der Hauptprozess ist:

    5.1. Rufen Sie RequestResponseBodyMethodProcessor auf , um eine Instanz von ServletServerHttpResponse (Springs Kapselung des nativen ServerHttpResponse) zu erstellen.

    5.2. Verwenden Sie die Schreibmethode von HttpMessageConverter, um den Rückgabewert in den OutputStream-Ausgabestream von ServletServerHttpResponse zu schreiben.

    5.3. Während des Schreibvorgangs wird JsonGenerator (standardmäßig wird das Jackson-Framework verwendet) verwendet, um den Rückgabewert in Json zu serialisieren.

  6. Nach der Ausführung der Anfrage ist das zurückgegebene ModelAndView null und die Antwort wurde in ServletServerHttpResponse geschrieben , sodass Sie sich keine Gedanken über die View-Verarbeitung machen müssen.

SpringBoot

31. Stellen Sie SpringBoot vor und welche Vorteile bietet es?

Spring Boot wird auf Basis von Spring entwickelt. Spring Boot selbst bietet nicht die Kernfunktionen und Erweiterungsfunktionen des Spring-Frameworks, sondern dient lediglich der schnellen und agilen Entwicklung einer neuen Generation von Anwendungen auf Basis des Spring-Frameworks. Es handelt sich nicht um eine Lösung, die Spring ersetzt, sondern um ein Tool, das eng in das Spring-Framework integriert ist, um die Spring-Entwicklererfahrung zu verbessern.

Fügen Sie hier eine Bildbeschreibung ein

Spring Boot 约定大于配置arbeitet mit der Kernidee und hat gegenüber Spring folgende Vorteile:

  1. Spring Boot kann schnell eigenständige Spring-Anwendungen erstellen .
  2. Spring Boot verfügt über integrierte Container wie Tomcat, Jetty und Undertow , was bedeutet, dass es ohne Bereitstellungsaufwand direkt ausgeführt werden kann.
  3. Spring Boot muss nicht mehr wie Spring eine Reihe umständlicher XML-Dateikonfigurationen verwenden.
  4. Spring Boot kann (Kern-)Spring automatisch konfigurieren . SpringBoot ändert die ursprüngliche XML-Konfiguration in eine Java-Konfiguration, ändert die Bean-Injection in Annotation-Injection (@Autowire) und fasst mehrere XML- und Eigenschaftenkonfigurationen in einer appliaction.yml-Konfigurationsdatei zusammen .
  5. Spring Boot bietet einige vorhandene Funktionen wie Messtools, Formulardatenvalidierung und einige Funktionen von Drittanbietern wie externe Konfiguration.
  6. Spring Boot kann gängige Abhängigkeiten (Entwicklungsbibliotheken wie spring-webmvc, jackson-json, validation-api, tomcat usw.) schnell integrieren und das bereitgestellte POM kann die Maven-Konfiguration vereinfachen. Wenn wir Kernabhängigkeiten einführen, führt SpringBoot automatisch andere Abhängigkeiten ein.

32. Verstehen Sie das Prinzip der automatischen Konfiguration von SpringBoot?

Die Annotation von SpringBoot zum Aktivieren der automatischen Konfiguration besteht darin, @EnableAutoConfigurationdass die Annotation für die Startklasse @SpringBootApplicationeine zusammengesetzte Annotation ist, einschließlich @EnableAutoConfiguration:

Fügen Sie hier eine Bildbeschreibung ein

  • EnableAutoConfigurationNur eine einfache Anmerkung: Die Kernfunktion der automatischen Assemblierung wird tatsächlich durch AutoConfigurationImportSelectorKlassen implementiert

    @AutoConfigurationPackage //将main同级的包下的所有组件注册到容器中
    @Import({
          
          AutoConfigurationImportSelector.class}) //加载自动装配类 xxxAutoconfiguration
    public @interface EnableAutoConfiguration {
          
          
        String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
    
        Class<?>[] exclude() default {
          
          };
    
        String[] excludeName() default {
          
          };
    }
    
  • AutoConfigurationImportSelectorDie Schnittstelle ist implementiert ImportSelector. Die Funktion dieser Schnittstelle besteht darin, die zu importierenden Konfigurationsklassen zu sammeln. Durch die Zusammenarbeit @Import()können die entsprechenden Klassen in den Spring-Container importiert werden.

  • Die Methode zum Abrufen der injizierten Klasse ist selectImports (). Was tatsächlich aufgerufen wird, ist, dass getAutoConfigurationEntrydiese Methode der Schlüssel zum Abrufen der automatischen Assembly-Klasse ist. Der Hauptprozess kann in die folgenden Schritte unterteilt werden:

    1. Rufen Sie die Attribute der Anmerkung für nachfolgende Ausschlüsse ab
    2. Erhalten Sie die Pfade aller Konfigurationsklassen, die automatisch zusammengestellt werden müssen : Dieser Schritt ist der kritischste. Erhalten Sie die Pfade aller automatischen Konfigurationsklassen aus META-INF/spring.factories
    3. Entfernen Sie doppelte Konfigurationsklassen und doppelte Klassen, die ausgeschlossen werden müssen, und speichern Sie die Pfade der Konfigurationsklassen, die automatisch geladen werden müssen.
    protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
    
    
        if (!this.isEnabled(annotationMetadata)) {
    
    
            return EMPTY_ENTRY;
        } else {
    
    
            //1.获取到注解的属性
            AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
            //2.获取需要自动装配的所有配置类,读取META-INF/spring.factories,获取自动配置类路径
            List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
            //3.1.移除重复的配置
            configurations = this.removeDuplicates(configurations);
            //3.2.处理需要排除的配置
            Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
            this.checkExcludedClasses(configurations, exclusions);
            configurations.removeAll(exclusions);
            configurations = this.getConfigurationClassFilter().filter(configurations);
            this.fireAutoConfigurationImportEvents(configurations, exclusions);
            return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
        }
    }

33.Wie passt man einen SpringBoot Srarter an?

Wenn man das Prinzip der automatischen Konfiguration kennt, ist es sehr einfach, einen benutzerdefinierten SpringBoot-Starter zu erstellen.

  1. Erstellen Sie ein Projekt mit dem Namen demo-spring-boot-starter und führen Sie SpringBoot-bezogene Abhängigkeiten ein
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
</dependency>
  1. Konfigurationsdatei schreiben

    Definiert hier das Präfix der Attributkonfiguration

    @ConfigurationProperties(prefix = "hello")
    public class HelloProperties {
          
          
    
        private String name;
    
        //省略getter、setter
    }
    
  2. automatische Montage

    Erstellen Sie die automatische Konfigurationsklasse HelloPropertiesConfigure

    @Configuration
    @EnableConfigurationProperties(HelloProperties.class)
    public class HelloPropertiesConfigure {
    }
    
  3. Konfigurieren Sie automatische Klassen

    /resources/META-INF/spring.factoriesFügen Sie der Datei den Klassenpfad für die automatische Konfiguration hinzu

    org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
      cn.fighter3.demo.starter.configure.HelloPropertiesConfigure
    
  4. prüfen

    Zu diesem Zeitpunkt ist ein von Hand geschriebener benutzerdefinierter SpringBoot-Starter fertiggestellt. Obwohl er relativ einfach ist, verfügt er über die wichtigsten automatischen Montagefunktionen.

    • Erstellen Sie ein Projekt und führen Sie benutzerdefinierte Starterabhängigkeiten ein

      <dependency>
          <groupId>cn.fighter3</groupId>
          <artifactId>demo-spring-boot-starter</artifactId>
          <version>0.0.1-SNAPSHOT</version>
      </dependency>
      
    • Konfiguration in der Konfigurationsdatei hinzufügen

      hello.name=张三
      
    • Testklasse

      @RunWith(SpringRunner.class)
      @SpringBootTest
      public class HelloTest {
              
              
          @Autowired
          HelloProperties helloProperties;
      
          @Test
          public void hello(){
              
              
              System.out.println("你好,"+helloProperties.getName());
          }
      }
      
    • Operationsergebnis

    Fügen Sie hier eine Bildbeschreibung ein

34. Springboot-Startprinzip?

Die SpringApplication-Klasse erledigt hauptsächlich die folgenden vier Dinge:

  1. Ermitteln Sie, ob es sich bei dem Anwendungstyp um ein normales Projekt oder ein Webprojekt handelt
  2. Suchen und laden Sie alle verfügbaren Initialisierer und legen Sie sie auf das Attribut initializers fest
  3. Suchen Sie alle Anwendungs-Listener und legen Sie sie auf das Listeners-Attribut fest
  4. Leiten Sie die definierende Klasse der Hauptmethode ab und legen Sie sie fest, um die auszuführende Hauptklasse zu finden

Der allgemeine Prozess des SpringBoot-Starts ist wie folgt:

Fügen Sie hier eine Bildbeschreibung ein

SpringCloud

35.Wie viel wissen Sie über Spring Cloud?

SpringCloud ist das von Spring offiziell eingeführte Microservice-Governance-Framework.

Spring Cloud Alibaba Microservice-Framework:

Fügen Sie hier eine Bildbeschreibung ein

Was sind Microservices?

  1. Eine neue architektonische Form, die 2014 von Martin Fowler vorgeschlagen wurde. Microservice-Architektur ist ein Architekturmuster , das die Aufteilung einer einzelnen Anwendung in eine Reihe kleiner Dienste befürwortet. Die Dienste koordinieren und kooperieren miteinander, um den Benutzern den ultimativen Mehrwert zu bieten. Jeder Dienst läuft in seinem eigenen unabhängigen Prozess und Dienste nutzen einfache Kommunikationsmechanismen (wie HTTP oder Dubbo), um miteinander zusammenzuarbeiten. Jeder Dienst basiert auf einem bestimmten Unternehmen und kann unabhängig bereitgestellt werden. In der Produktionsumgebung außerdem Ein einheitlicher und zentralisierter Service-Management-Mechanismus sollte so weit wie möglich vermieden werden. Für einen bestimmten Service sollten die entsprechende Sprache und Tools (z. B. Maven) ausgewählt werden, um ihn entsprechend dem Geschäftskontext aufzubauen.
  2. Der Kern von Microservices besteht darin, herkömmliche One-Stop-Anwendungen je nach Geschäft einzeln in Dienste aufzuteilen und diese vollständig zu entkoppeln . Jeder Microservice stellt den Service einer einzelnen Geschäftsfunktion bereit, und jeder Service erledigt eine Aufgabe. Aus technischer Sicht Es handelt sich um einen kleinen und unabhängigen Verarbeitungsprozess, der dem Konzept eines Prozesses ähnelt. Er kann unabhängig gestartet oder zerstört werden und verfügt über eine eigene unabhängige Datenbank.

Welche Probleme löst die Microservice-Architektur hauptsächlich?

  1. Es gibt viele Dienste. Wie greifen Clients auf sie zu und wie stellen sie externe Gateways bereit?
  2. Wie kommunizieren sie bei so vielen Diensten untereinander? HTTP oder RPC?
  3. Wie verwaltet man so viele Dienste? Dienstregistrierung und -erkennung.
  4. Was soll ich tun, wenn der Dienst ausfällt? Schutzschaltermechanismus.

Was sind die gängigen Microservice-Frameworks?

  1. Frühlingswolke Netflix
  2. Spring Cloud Alibaba
  3. SpringBoot + Dubbo + ZooKeeper

Was sind die Kernkomponenten von SpringCloud?

Fügen Sie hier eine Bildbeschreibung ein

PS: Es wird später Möglichkeiten geben, Microservices zu erweitern. Tatsächlich basieren Interviews normalerweise auf Projekten.

Informationsquelle: Noodle Counterattack: Fünfunddreißig Fragen des Frühlings, 40.000 Wörter + fünfzig Bilder, ausführliche Erklärung! Zum Sammeln empfohlen!

Supongo que te gusta

Origin blog.csdn.net/weixin_45483322/article/details/132435302
Recomendado
Clasificación