Dies ist der zweite Teil der Reihe "Wichtige Änderungen an Spring Framework 5.0" und die wichtigsten Änderungen der Kernfunktionen (neue Funktionen, Verbesserungen usw.). Ich möchte vorstellen.
In Spring Framework 5.0 wurden die folgenden Änderungen an allgemeinen Funktionen (= Kernfunktionen) vorgenommen, die nicht vom Anwendungstyp abhängen.
Artikelnummer | Änderungen |
---|---|
1 | Mit den von JDK 8 unterstützten Mechanismen können Sie effizient auf Methodenparameter zugreifen.[Zu Details:arrow_right:] **Note:**Da es sich um eine interne Implementierung handelt, ändern sich die externen Spezifikationen nicht. |
2 | Einige Schnittstellen implementieren jetzt die von JDK 8 unterstützten Standardmethoden.[Zu Details:arrow_right:] **Note:**BeimErstelleneinerImplementierungsklasse(Erweiterungsklasse) für diese Schnittstellen müssen nur die erforderlichen Methoden implementiert werden. Daher gibt es Maßnahmen wie "Erstellen einer Adapterklasse, die eine leere Implementierung bereitstellt" und "unnötiges Ausführen einer leeren Implementierung". Es wird unnötig sein. |
3 | Unterstützt in JDK 7StandardCharsets Wird verwendet.[Zu Details:arrow_right:]**Note:**Da es sich um eine interne Implementierung handelt, ändern sich die externen Spezifikationen nicht. |
4 | Wird in JDK 9 veraltet seinClass#newInstance() AnstattConstructor#newInstance() Wird aufgerufen, um eine Instanz zu erstellen.[Zu Details:arrow_right:]**Note:**Da es sich um eine interne Implementierung handelt, ändern sich die externen Spezifikationen nicht. |
5 | spring-jcl Module wurden hinzugefügt und Log4j 2 über die Commons Logging API.x, SLF4J, JUL(java.util.logging )Sie können das Protokoll über ausgeben.[Zu Details:arrow_right:]Note: Spring Framework 4.Die Bibliothek für Log Bridge, die bis zu 3 benötigt wurde, wird nicht mehr benötigt. |
6 | Schnittstelle zum Abstrahieren von Ressourcen(Resource )ZuisFile() メソッドが追加され、リソースがファイルシステム上Zu存在するか判定できるようZuなります。[Zu Details:arrow_right:] |
7 | Schnittstelle zum Abstrahieren von Ressourcen(Resource )ZureadableChannel() Methode hinzugefügt,ReadableByteChannel (New I/O)経由でリソースのデータを読み込むことができるようZuなります。[Zu Details:arrow_right:] |
[SPR-14055]: Ab JDK 8 sind die Klassen "java.lang.reflect.Method" und "java.lang.reflect.Constructor" Es erbt jetzt die von JDK 8 hinzugefügte Klasse "java.lang.reflect.Executable", und Spring Framework 5.0 verwendet jetzt die Methoden der Klasse "Executable", um auf Informationen zu Methoden und Konstruktorparametern zuzugreifen. wurde. Da die diesmal geänderte Klasse im Grunde genommen eine Klasse ist, die bei der internen Verarbeitung des Frameworks verwendet wird, wird sie meiner Meinung nach nicht oft direkt von Anwendungsentwicklern verwendet, sondern beim Erstellen von AP-Infrastrukturteilen wie Framework-Erweiterungen. Es kann eine Möglichkeit geben.
Zum Beispiel ...
package com.example;
import org.springframework.beans.factory.annotation.Value;
public class Foo {
public Foo(String text, int number) {
// ...
}
public String bar(@Value("${text:dummy}") String text) {
return text;
}
}
Schauen wir uns den Code an, der auf die Argumente des Konstruktors und der Methode dieser Klasse zugreift.
Verwenden Sie in Spring Framework 4.3 die Methode forMethodOrConstructor
der Klasse MethodParameter
, um die Parameterinformationen abzurufen. (Veraltete API in Spring Framework 5.0)
〜4.3
package com.example;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.core.MethodParameter;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
class CoreTest {
@Test
void constructorParameter() throws Exception {
Constructor<?> constructor = Foo.class.getConstructor(String.class, int.class);
MethodParameter parameter0 = MethodParameter.forMethodOrConstructor(constructor, 0);
MethodParameter parameter1 = MethodParameter.forMethodOrConstructor(constructor, 1);
Assertions.assertEquals(String.class, parameter0.getParameterType());
Assertions.assertEquals(int.class, parameter1.getParameterType());
}
@Test
void methodParameter() throws Exception {
Method method = Foo.class.getMethod("bar", String.class);
MethodParameter parameter0 = MethodParameter.forMethodOrConstructor(method, 0);
Assertions.assertEquals(String.class, parameter0.getParameterType());
Assertions.assertEquals("${test:dummy}", parameter0.getParameterAnnotation(Value.class).value());
}
}
Verwenden Sie in Spring Framework 5.0 die Methode "forExecutable" oder "forParameter" der Klasse "MethodParameter", um Parameterinformationen abzurufen.
5.0〜
package com.example;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.core.MethodParameter;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
class CoreTest {
@Test
void constructorParameter() throws Exception {
Constructor<?> constructor = Foo.class.getConstructor(String.class, int.class);
MethodParameter parameter0 = MethodParameter.forExecutable(constructor, 0);
MethodParameter parameter1 = MethodParameter.forExecutable(constructor, 1);
Assertions.assertEquals(String.class, parameter0.getParameterType());
Assertions.assertEquals(int.class, parameter1.getParameterType());
}
@Test
void methodParameter() throws Exception {
Method method = Foo.class.getMethod("bar", String.class);
MethodParameter parameter0 = MethodParameter.forParameter(method.getParameters()[0]);
Assertions.assertEquals(String.class, parameter0.getParameterType());
Assertions.assertEquals("${text:dummy}", parameter0.getParameterAnnotation(Value.class).value());
}
}
Note:
Übrigens ... Wenn Sie den tatsächlichen Parameternamen erhalten möchten, müssen Sie "DefaultParameterNameDiscoverer" auf "MethodParameter" setzen. (Wenn Sie diesen Mechanismus verwenden möchten, müssen Sie "
-parameters
"oder" -g` "als Kompilierungsoption angeben.)MethodParameter parameter0 = MethodParameter.forParameter(method.getParameters()[0]); parameter0.initParameterNameDiscovery(new DefaultParameterNameDiscoverer()); // ... Assertions.assertEquals("text", parameter0.getParameterName());
#In der Schnittstelle implementierte Standardmethode:thumbsup:
[SPR-14432]:EinigedervomSpringFrameworkbereitgestelltenSchnittstellenimplementierenjetztdievonJDK8unterstütztenStandardmethoden.MitdieserÄnderungmüssenbeimErstelleneinerImplementierungsklasse(Erweiterungsklasse) für diese Schnittstellen nur die erforderlichen Methoden implementiert werden. "Erstellen Sie eine Adapterklasse, die eine leere Implementierung bereitstellt" oder "Führen Sie eine leere Implementierung unnötig aus". Es besteht keine Notwendigkeit, Maßnahmen wie.
Zum Beispiel Frühling-Wird vom Beans-Modul bereitgestelltBeanPostProcessor
Auf der SchnittstellepostProcessBeforeInitialization
(Eine Methode, die vor der ersten Verarbeitung der Bean zurückgerufen wird)WannpostProcessAfterInitialization
(Eine Methode, die nach der ersten Verarbeitung von Bnea zurückgerufen wird)Wannいう2つのメソッドがありますが、そちらか一方だけ実装したいWannいうケースもあります。
Spring Framework 4.In 3 musste ich zwei Methoden unbedingt implementieren:
〜4.3
@Configuration
public class AppConfig {
@Bean
BeanPostProcessor myBeanPostProcessor() {
return new BeanPostProcessor() {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
// Beispiel) Implementieren Sie Code, der den Bean-Status ändert, bevor der Initialisierungsprozess ausgeführt wird.
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean; // Benötige eine Vorlagenimplementierung, die die Bean so zurückgibt, wie sie ist ...
}
};
}
}
Spring Framework 5.Bei 0 müssen Sie nur die erforderlichen Methoden wie unten gezeigt implementieren.
5.0〜
@Configuration
public class AppConfig {
@Bean
BeanPostProcessor myBeanPostProcessor() {
return new BeanPostProcessor() {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
// Beispiel) Implementieren Sie Code, der den Bean-Status ändert, bevor der Initialisierungsprozess ausgeführt wird.
return bean;
}
};
}
}
#Standard-Zeichensätze werden für die Verarbeitung innerhalb des Frameworks verwendet:thumbsup:
[SPR-14492]:InderinternenVerarbeitungdesFrameworks"UTF-Standardwie8"Charset
BeiderAngabe"Charset#forName(String)
Unterstützt von JDK 7 stattStandardCharsets
Wird verwendet. Dies hat keine Auswirkungen auf Framework-Benutzer.StandardCharsets
"UNS-ASCII」「ISO-8859-1」「UTF-8」「UTF-16BE」「UTF-16LE」「UTF-Es gibt Konstanten für "16", also lasst uns alle diese Konstanten aktiv verwenden!
Constructor#newInstance()
Wird generiert mit:thumbsup:[SPR-14486]:InderinternenVerarbeitungdesFrameworksNichtempfohlenfürJDK9WirdseinClass#newInstance()
AnstattConstructor#newInstance()
Wirdaufgerufen,umeineInstanzzuerstellen.Anscheinend...Class#newInstance()
Wirdverwendet,umgeprüfteAusnahmenzubehandeln,wenneinegeprüfteAusnahmemiteinerDeklarationinderthrows-KlauseldesKonstruktorsauftritt.(FügenSiediecatch-oderthrow-Klauselhinzu)Wird nicht erzwungen, so scheint es, dass die aufgetretene Ausnahme unbeabsichtigt nach oben geworfen wird. Dies ist auch eine Geschichte, die die Framework-Benutzer überhaupt nicht betrifft, aber es scheint Fälle zu geben, in denen Sie Ihre eigene Instanziierung mithilfe von Reflektion implementieren. Lassen Sie uns also sehen, wo das Problem liegt. ..
Es ist nicht wirklich möglich, aber es wird vom Standardkonstruktor erzwungenIOException
Bereiten Sie eine Klasse vor, die generiert.
public class Foo {
public Foo () throws IOException {
throw new IOException("error.");
}
// ...
}
Wenn Sie eine Instanz der obigen Klasse erstellen,new Foor()
Wenn, der CompilerIOException
Sie werden gebeten, damit umzugehen.
new
@Test
void newInstance() {
try {
new Foo();
Assertions.fail("does not occurred a IOException.");
} catch (IOException e) {// ★★★ Der Compiler erzwingt die Behandlung von IOException! !!
// NOP
}
}
NächsterClass#newInstance
Wenn Sie eine Instanz mit erstellenInstantiationException
WannIllegalAccessException
のハンドリングを行うように求めてきます。 この状態でテストケースを実行するWann・・・
Class.newInstance
@Test
void classNewInstance() {
try {
Foo.class.newInstance();
Assertions.fail("does not occurred a IOException.");
} catch (InstantiationException | IllegalAccessException e) {
// NOP
}
}
java.io.IOException: error.
at com.example.CoreTest$Foo.<init>(CoreTest.java:97)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at java.lang.Class.newInstance(Class.java:442)
at com.example.CoreTest.classNewInstance(CoreTest.java:75)
Und der Test schlägt fehl. Mit anderen Worten ...InstantiationException
WannIllegalAccessException
Trat im Konstruktor auch nach der Handhabung aufIOException
Wird nicht behandelt und eine Ausnahme wird unbeabsichtigt an den Anrufer gesendet.
DannClass#newInstance
nichtConstructor#newInstance()
Mal sehen, was passiert, wenn Sie verwenden. Wenn Sie den folgenden Test ausführen,InvocationTargetException
Tritt ein,InvocationTargetException
Ausnahme, die im Konstruktor aufgetreten ist(IOException
)Ist eingewickelt.
Constructor.newInstance
@Test
void constructorNewInstance() {
try {
Foo.class.getDeclaredConstructor().newInstance();
Assertions.fail("does not occurred a IOException.");
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException e) {
Assertions.fail("does not occurred a IOException.");
} catch (InvocationTargetException e) {// ★★★ Der Compiler zwingt Sie, die Ausnahme zu behandeln, die die im Konstruktor aufgetretene Ausnahme (IOException) umschließt: sweat_smile! !!
Assertions.assertEquals(IOException.class, e.getTargetException().getClass());
}
}
[SPR-14512]:spring-Einjcl-ModulwurdehinzugefügtundLog4j2überdieCommonsLoggingAPI,ohne"OriginalCommonsLogging"oder"BridgeLibrary,diedieCommonsLoggingAPIimplementiert"zuverwenden..x,SLF4J,JUL(java.util.logging)Sie können das Protokoll über ausgeben. Das Spring Framework verwendet die Commons Logging API für die Protokollausgabe, und die Bibliothek für die tatsächliche Protokollausgabe entspricht dem vom Entwickler gewählten Stil. Vor langer Zeit "Commons Logging"+Protokollbibliothek(Log4j usw.)War üblich, aber vor kurzem "SLF4J"+Protokollligator, der die SLF4J-API implementiert(Zum Beispiel Logback)Wird (wahrscheinlich) mehr Mainstream:sweat_smile:)。 Zum Beispiel ... "SLF4J+In dem Fall, in dem "Logback" das Anwendungsprotokoll ausgibt, ist die vom Spring Framework ausgegebene Protokollbibliothek eine Bridge-Bibliothek, die die "Commons Logging API" implementiert.(jcl-over-slf4j etc.) + SLF4J +Es sollte als "Logback" konfiguriert sein.
Mal sehen, wie die abhängigen Bibliotheken für die obige Konfiguration aufgelöst werden.
Spring Framework 4.In 3 Frühling-Da der Kern von "Commons Logging of the head family" abhängt, sollten Sie bei Verwendung der Bridge-Bibliothek den Frühling einstellen-Ich musste "Original Commons Logging" aus den abhängigen Bibliotheken des Kerns ausschließen.
xml:pom.xml(〜4.3)
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.3.8.RELEASE</version>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId> commons-logging </ifactId> <! - ★★★ Schließen Sie die ursprüngliche Commons Logging-> aus
</exclusion>
</exclusions>
</dependency>
</dependencies>
</dependencyManagement>
<!-- ... -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId> jcl-over-slf4j </ifactId> <! - ★★★ "Bridge-Bibliothek, die die Commons Logging API implementiert" ist erforderlich->
<version>1.7.25</version>
</dependency>
Spring Framework 5.Springen Sie ab 0 den Teil der "Bridge-Bibliothek, die die Commons Logging API implementiert".-Weil jcl verantwortlich ist, jcl-over-Verwenden der Commons Logging API "Log 4j 2", ohne eine Bridge-Bibliothek wie slf4j hinzuzufügen.x」「SLF4J」「JUL(java.util.logging
)Sie können das Protokoll über ausgeben. Frühlingsrahmen 5.Ab 0 Frühling-Kern ist Frühling statt "Commons Logging der Kopffamilie"-Frühling, weil es von jcl abhängt-Sie müssen lediglich die von jcl unterstützte Protokollbibliothek zu den abhängigen Bibliotheken hinzufügen.
xml:pom.xml(5.0〜)
<!-- ... -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId> logback-classic </ifactId> <! - ★★★ Sie müssen nur Logback hinzufügen, das die SLF4J-API-> implementiert
<version>1.2.3</version>
</dependency>
Note:
Wenn die zum Erstellen der Anwendung verwendeten Bibliotheken von "Original Commons Logging" oder "Bridge Library, die die Commons Logging API implementiert" abhängen, müssen Sie diese Bibliotheken ausschließen.
Wenn ich versuche, den Code auszuführen, der den DI-Container von Spring generiert ...
@Test
void applicationContext() {
try (ConfigurableApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class)) {
// ...
}
}
Das folgende Protokoll wurde ordnungsgemäß ausgegeben:v:
01:55:50.072 [main] DEBUG org.springframework.core.env.StandardEnvironment - Adding [systemProperties] PropertySource with lowest search precedence
01:55:50.079 [main] DEBUG org.springframework.core.env.StandardEnvironment - Adding [systemEnvironment] PropertySource with lowest search precedence
01:55:50.080 [main] DEBUG org.springframework.core.env.StandardEnvironment - Initialized StandardEnvironment with PropertySources [systemProperties,systemEnvironment]
01:55:50.129 [main] DEBUG org.springframework.context.annotation.ClassPathBeanDefinitionScanner - JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning
01:55:50.179 [main] INFO org.springframework.context.annotation.AnnotationConfigApplicationContext - Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@46daef40: startup date [Fri May 12 01:55:50 JST 2017]; root of context hierarchy
... (weggelassen)
01:55:50.786 [main] INFO org.springframework.context.annotation.AnnotationConfigApplicationContext - Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@46daef40: startup date [Fri May 12 01:55:50 JST 2017]; root of context hierarchy
01:55:50.786 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'lifecycleProcessor'
01:55:50.787 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Destroying singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@482cd91f: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.event.internalEventListenerProcessor,org.springframework.context.event.internalEventListenerFactory,coreTest.AppConfig,myBeanPostProcessor]; root of factory hierarchy
Resource
Kann festgestellt werden, ob es sich im Dateisystem befindet:thumbsup:[SPR-14484]:SchnittstellezumAbstrahierenvonRessourcen(Resource
)ZuisFile()
メソッドが追加され、リソースがファイルシステム上Zu存在するか判定できるようZuなります。
@Test
void resourceIsFile() throws IOException {
Resource fileResource = new FileSystemResource("pom.xml");
Resource webResource = new UrlResource("http://google.com");
Assertions.assertTrue(fileResource.isFile());
Assertions.assertFalse(webResource.isFile());
}
Resource
DatenReadableByteChannel
Kann über erhalten werden:thumbsup:[SPR-14698]:SchnittstellezumAbstrahierenvonRessourcen(Resource
)ZureadableChannel()
Methodehinzugefügt,ReadableByteChannel
(NewI/O)経由でリソースのデータを読み込むことができるようZuなります。ちなみZu・・・RC1WritableResource
ZuwritableChannel
Methode hinzugefügt,WritableByteChannel
経由でデータを書き込めるようZuなっていたので、あわせて実装サンプルを紹介しておきます。
@Test
void resourceUsingByteBuffer() throws IOException {
ByteBuffer buffer = ByteBuffer.allocate(2048);
Resource srcResource = new FileSystemResource("pom.xml");
WritableResource destResource = new FileSystemResource("pom.xml.bk");
try (ReadableByteChannel readableChannel = srcResource.readableChannel();
WritableByteChannel writableChannel = destResource.writableChannel()) {
while (true) {
buffer.clear();
if (readableChannel.read(buffer) <= 0) {
break;
}
buffer.flip();
writableChannel.write(buffer);
}
}
Assertions.assertEquals(srcResource.contentLength(), destResource.contentLength());
}
#Zusammenfassung
Dieses Mal haben wir die wichtigsten Änderungen in den Kernfunktionen eingeführt. Es gab auch eine Einführung von Klassenänderungen, die nicht direkt bei der Entwicklung von Anwendungen verwendet werden, die das Framework verwenden. Es wurden jedoch Verbesserungen vorgenommen, um die "Benutzerfreundlichkeit" und "Effizienz" des Frameworks zu verbessern. Es ist ein Eindruck. nächstes Mal,"Wichtige Änderungen in Bezug auf DI-ContainerWerden vorgestellt.
Recommended Posts