Spring DI und AOP

+ andere TechDocs
+ Spring-Projekte
+ Spring Framework
+ Spring Boot
+ Spring Batch
+


Spring unterstützt die Softwareentwicklung von Enterprise-tauglichen JVM-basierenden Anwendungen durch Vereinfachungen, Effektivität, Flexibilität, Portabilität und Förderung guter Programmierpraktiken.

Wichtige Schlüsselstrategien von Spring sind:

Spring besteht aus mehreren Spring-Projekten.

Die Basis bildet das Spring Framework, welches Dependency Injection (DI), Aspect-Oriented Programming (AOP), Declarative Transaction Management, MVC Web Application, RESTful Web Services und vieles mehr bietet.



Inhalt

  1. Begriffe im Spring-Umfeld
  2. DI-Demo mit den JSR-330-Annotationen @Named und @Inject
  3. DI-Demo mit Spring-Annotationen
  4. DI-Demo mit JUnit-Modultest
  5. DI-Demo mit DataSourcen und Profilen
  6. AOP-Demo mit Aspect, Pointcut und Advices



Begriffe im Spring-Umfeld



DI-Demo mit den JSR-330-Annotationen @Named und @Inject

Das folgende einfache Beispiel demonstriert:

Normalerweise werden in Nicht-Spring-Anwendungen die JSR-330-Annotationen verwendet, und in Spring-Anwendungen ausschließlich Spring-Annotationen. Wie das folgende Beispiel zeigt, kann auch beides gemischt werden.

Sie können das Beispiel wahlweise entweder downloaden oder wie beschrieben Schritt für Schritt aufbauen und ausführen.

Führen Sie folgende Schritte aus:

  1. JDK und Maven müssen installiert sein.

  2. Wechseln Sie in Ihr Workspace-Verzeichnis (z.B. \MeinWorkspace) und führen Sie folgende Kommandos aus:

    cd \MeinWorkspace

    md SpringDemo01-Jsr330

    cd SpringDemo01-Jsr330

    md src\main\java\didemo

    tree /F

  3. Erstellen Sie im SpringDemo01-Jsr330-Projektverzeichnis die Maven-Projektkonfigurationsdatei: pom.xml

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <groupId>didemo</groupId>
      <artifactId>SpringDiDemo</artifactId>
      <version>1.0-SNAPSHOT</version>
      <dependencies>
        <dependency>
          <groupId>javax.inject</groupId>
          <artifactId>javax.inject</artifactId>
          <version>1</version>
        </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-context</artifactId>
          <version>4.3.5.RELEASE</version>
        </dependency>
      </dependencies>
    </project>
    
  4. Erzeugen Sie im src/main/java/didemo-Verzeichnis die Main- und Konfigurationsklasse: MainApp.java

    package didemo;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    @ComponentScan
    public class MainApp
    {
       public static void main( String[] args )
       {
          ApplicationContext ctx = new AnnotationConfigApplicationContext( MainApp.class );
          MeineComponent meineInjizierteComponent = ctx.getBean( MeineComponent.class );
          meineInjizierteComponent.printInfo();
          meineInjizierteComponent.runInjizierteBean();
       }
    }
    

    Sehen Sie sich obige Erläuterungen zu den Basis-Annotationen an, sowie die Javadoc zu: @Configuration, @ComponentScan, ApplicationContext und AnnotationConfigApplicationContext.

  5. Erzeugen Sie im src/main/java/didemo-Verzeichnis eine einfache POJO-Klasse, die per @Named-Annotation als injizierbare managed Bean deklariert wird, und in deren Feldvariable eine andere managed Bean per @Inject injiziert wird: MeineComponent.java

    package didemo;
    
    import javax.inject.Inject;
    import javax.inject.Named;
    import org.springframework.context.annotation.Bean;
    
    @Named
    public class MeineComponent
    {
       @Inject
       private Runnable meineInjizierteBean;
    
       public void printInfo()
       {
          System.out.println( "---- Meine injizierte Component ----" );
       }
    
       public void runInjizierteBean()
       {
          meineInjizierteBean.run();
       }
    
       @Bean
       private Runnable meineBean()
       {
          return new Runnable() {
             public void run() {
                System.out.println( "---- Meine injizierte Bean ----" );
          } };
       }
    }
    

    Sehen Sie sich obige Erläuterungen zu den Basis-Annotationen an, sowie die Javadoc zu: @Named, @Inject, @Bean und Runnable.

  6. Die Projektstruktur sieht jetzt so aus (überprüfen Sie es mit tree /F):

    [\MeinWorkspace\SpringDemo01-Jsr330]
     |- [src]
     |   '- [main]
     |       '- [java]
     |           '- [didemo]
     |               |- MainApp.java
     |               '- MeineComponent.java
     '- pom.xml
    
  7. Führen Sie im Kommandozeilenfenster aus (passen Sie die Pfade an) (das lange java...-Kommando als eine Zeile):

    cd \MeinWorkspace\SpringDemo01-Jsr330

    mvn clean package

    set MVN_REPO=\Tools\Maven3-Repo

    set MVN_REPO_ORG_SPRFW=%MVN_REPO%\org\springframework

    set SPRFW_VERS=4.3.5.RELEASE

    java -cp target\SpringDiDemo-1.0-SNAPSHOT.jar;%MVN_REPO%\javax\inject\javax.inject\1\javax.inject-1.jar;%MVN_REPO_ORG_SPRFW%\spring-aop\%SPRFW_VERS%\*;%MVN_REPO_ORG_SPRFW%\spring-beans\%SPRFW_VERS%\*;%MVN_REPO_ORG_SPRFW%\spring-core\%SPRFW_VERS%\*;%MVN_REPO_ORG_SPRFW%\spring-context\%SPRFW_VERS%\*;%MVN_REPO_ORG_SPRFW%\spring-expression\%SPRFW_VERS%\*;%MVN_REPO%\commons-logging\commons-logging\1.2\* didemo.MainApp

  8. Sie erhalten:

    ---- Meine injizierte Component ----
    ---- Meine injizierte Bean ----
    
  9. Wenn Sie die umständliche lange java...-Kommandozeile vermeiden wollen, sehen Sie sich an: Spring-Boot, Maven Assembly Plugin oder Maven Shade Plugin.
    Oder importieren Sie das Maven-Projekt einfach in Ihre IDE, beispielsweise Eclipse oder IntelliJ Idea, und führen Sie darin die MainApp-Klasse aus.

  10. Sehen Sie sich die verwendeten Libs an:

    mvn dependency:tree



DI-Demo mit Spring-Annotationen

Das folgende einfache Beispiel demonstriert:

Sie können das Beispiel wahlweise entweder downloaden oder wie beschrieben Schritt für Schritt aufbauen und ausführen.

Führen Sie folgende Schritte aus:

  1. JDK und Maven müssen installiert sein.

  2. Wechseln Sie in Ihr Workspace-Verzeichnis (z.B. \MeinWorkspace) und führen Sie folgende Kommandos aus:

    cd \MeinWorkspace

    md SpringDemo02-Di

    cd SpringDemo02-Di

    md src\main\java\didemo

    tree /F

  3. Erstellen Sie im SpringDemo02-Di-Projektverzeichnis die Maven-Projektkonfigurationsdatei: pom.xml

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <groupId>didemo</groupId>
      <artifactId>SpringDiDemo</artifactId>
      <version>1.0-SNAPSHOT</version>
      <dependencies>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-context</artifactId>
          <version>4.3.5.RELEASE</version>
        </dependency>
      </dependencies>
    </project>
    
  4. Erzeugen Sie im src/main/java/didemo-Verzeichnis die Main- und Konfigurationsklasse: MainApp.java

    package didemo;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    @ComponentScan
    public class MainApp
    {
       public static void main( String[] args )
       {
          ApplicationContext ctx = new AnnotationConfigApplicationContext( MainApp.class );
          MeineComponent meineInjizierteComponent = ctx.getBean( MeineComponent.class );
          meineInjizierteComponent.printInfo();
          meineInjizierteComponent.runInjizierteBean();
       }
    }
    

    Sehen Sie sich obige Erläuterungen zu den Basis-Annotationen an, sowie die Javadoc zu: @Configuration, @ComponentScan, ApplicationContext und AnnotationConfigApplicationContext.

  5. Erzeugen Sie im src/main/java/didemo-Verzeichnis eine einfache POJO-Klasse, die per @Component-Annotation als injizierbare managed Bean deklariert wird, und in deren Feldvariable eine andere managed Bean per @Autowired injiziert wird: MeineComponent.java

    package didemo;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Bean;
    import org.springframework.stereotype.Component;
    
    @Component
    public class MeineComponent
    {
       @Autowired
       private Runnable meineInjizierteBean;
    
       public void printInfo()
       {
          System.out.println( "---- Meine injizierte Component ----" );
       }
    
       public void runInjizierteBean()
       {
          meineInjizierteBean.run();
       }
    
       @Bean
       private Runnable meineBean()
       {
          return new Runnable() {
             public void run() {
                System.out.println( "---- Meine injizierte Bean ----" );
          } };
       }
    }
    

    Sehen Sie sich obige Erläuterungen zu den Basis-Annotationen an, sowie die Javadoc zu: @Component, @Autowired, @Bean und Runnable.

  6. Die Projektstruktur sieht jetzt so aus (überprüfen Sie es mit tree /F):

    [\MeinWorkspace\SpringDemo02-Di]
     |- [src]
     |   '- [main]
     |       '- [java]
     |           '- [didemo]
     |               |- MainApp.java
     |               '- MeineComponent.java
     '- pom.xml
    
  7. Führen Sie im Kommandozeilenfenster aus (passen Sie die Pfade an) (das lange java...-Kommando als eine Zeile):

    cd \MeinWorkspace\SpringDemo02-Di

    mvn clean package

    set MVN_REPO=\Tools\Maven3-Repo

    set MVN_REPO_ORG_SPRFW=%MVN_REPO%\org\springframework

    set SPRFW_VERS=4.3.5.RELEASE

    java -cp target\SpringDiDemo-1.0-SNAPSHOT.jar;%MVN_REPO_ORG_SPRFW%\spring-aop\%SPRFW_VERS%\*;%MVN_REPO_ORG_SPRFW%\spring-beans\%SPRFW_VERS%\*;%MVN_REPO_ORG_SPRFW%\spring-core\%SPRFW_VERS%\*;%MVN_REPO_ORG_SPRFW%\spring-context\%SPRFW_VERS%\*;%MVN_REPO_ORG_SPRFW%\spring-expression\%SPRFW_VERS%\*;%MVN_REPO%\commons-logging\commons-logging\1.2\* didemo.MainApp

  8. Sie erhalten:

    ---- Meine injizierte Component ----
    ---- Meine injizierte Bean ----
    
  9. Wenn Sie die umständliche lange java...-Kommandozeile vermeiden wollen, sehen Sie sich an: Spring-Boot, Maven Assembly Plugin oder Maven Shade Plugin.
    Oder importieren Sie das Maven-Projekt einfach in Ihre IDE, beispielsweise Eclipse oder IntelliJ Idea, und führen Sie darin die MainApp-Klasse aus.

  10. Sehen Sie sich die verwendeten Libs an:

    mvn dependency:tree



DI-Demo mit JUnit-Modultest

Das folgende einfache Beispiel

Sie können das Beispiel wahlweise entweder downloaden oder wie beschrieben Schritt für Schritt aufbauen und ausführen.

Führen Sie folgende Schritte aus:

  1. Wechseln Sie in das SpringDemo02-Di-Projektverzeichnis und erstellen Sie einen zweiten Sourcecodeverzeichnisbaum:

    cd \MeinWorkspace\SpringDemo02-Di

    md src\test\java\didemo

    tree /F

  2. Erweitern Sie im SpringDemo02-Di-Projektverzeichnis die pom.xml vor </dependencies> um:

        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-test</artifactId>
          <version>4.3.5.RELEASE</version>
          <scope>test</scope>
        </dependency>
        <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>4.12</version>
          <scope>test</scope>
        </dependency>
    
  3. Erzeugen Sie im src/test/java/didemo-Verzeichnis den JUnit-Modultest: MeineComponentTest.java

    package didemo;
    
    import org.junit.Assert;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    
    @RunWith( SpringJUnit4ClassRunner.class )
    @ContextConfiguration( classes = MainApp.class )
    public class MeineComponentTest
    {
       @Autowired private Runnable       meineBean;
       @Autowired private MeineComponent meineComponent;
    
       @Test
       public void testMeineComponent()
       {
          Assert.assertNotNull( meineBean );
          Assert.assertNotNull( meineComponent );
          meineComponent.printInfo();
          meineComponent.runInjizierteBean();
       }
    }
    

    Sehen Sie sich obige Erläuterungen zu den Basis-Annotationen an, sowie die Javadoc zu: @RunWith, SpringJUnit4ClassRunner, @ContextConfiguration, @Autowired, @Test.

  4. Die Projektstruktur sieht jetzt so aus (überprüfen Sie es mit tree /F):

    [\MeinWorkspace\SpringDemo02-Di]
     |- [src]
     |   |- [main]
     |   |   '- [java]
     |   |       '- [didemo]
     |   |           |- MainApp.java
     |   |           '- MeineComponent.java
     |   '- [test]
     |       '- [java]
     |           '- [didemo]
     |               '- MeineComponentTest.java
     '- pom.xml
    
  5. Führen Sie im Kommandozeilenfenster aus:

    cd \MeinWorkspace\SpringDemo02-Di

    mvn clean test

  6. Im JUnit-Modultest wird überprüft, dass die beiden Beans wirklich in die @Autowired-Felder injiziert werden. Anschließend werden Methoden der Beans aufgerufen und Sie erhalten wieder:

    ---- Meine injizierte Component ----
    ---- Meine injizierte Bean ----
    


DI-Demo mit DataSourcen und Profilen

Das folgende Beispiel demonstriert:

Sie können das Beispiel wahlweise entweder downloaden oder wie beschrieben Schritt für Schritt aufbauen und ausführen.

Führen Sie folgende Schritte aus:

  1. JDK und Maven müssen installiert sein.

  2. Wechseln Sie in Ihr Workspace-Verzeichnis (z.B. \MeinWorkspace) und führen Sie folgende Kommandos aus:

    cd \MeinWorkspace

    md SpringDemo03-Ds

    cd SpringDemo03-Ds

    md src\main\resources

    md src\main\java\didemo

    md src\test\java\didemo

    tree /F

  3. Erstellen Sie im SpringDemo03-Ds-Projektverzeichnis die Maven-Projektkonfigurationsdatei: pom.xml

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <groupId>didemo</groupId>
      <artifactId>SpringDiDemo</artifactId>
      <version>1.0-SNAPSHOT</version>
      <build>
        <plugins>
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.6.0</version>
            <configuration>
              <source>1.7</source>
              <target>1.7</target>
            </configuration>
          </plugin>
        </plugins>
      </build>
      <dependencies>
        <dependency>
          <groupId>com.h2database</groupId>
          <artifactId>h2</artifactId>
          <version>1.4.193</version>
        </dependency>
        <dependency>
          <groupId>org.apache.commons</groupId>
          <artifactId>commons-dbcp2</artifactId>
          <version>2.1.1</version>
        </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-context</artifactId>
          <version>4.3.5.RELEASE</version>
        </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-jdbc</artifactId>
          <version>4.3.5.RELEASE</version>
        </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-test</artifactId>
          <version>4.3.5.RELEASE</version>
          <scope>test</scope>
        </dependency>
        <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>4.12</version>
          <scope>test</scope>
        </dependency>
      </dependencies>
    </project>
    
  4. Erzeugen Sie im src/main/java/didemo-Verzeichnis die Main- und Konfigurationsklasse: MainApp.java

    package didemo;
    
    import org.springframework.context.annotation.*;
    
    @Configuration
    @ComponentScan
    public class MainApp
    {
       public static void main( String[] args )
       {
          new AnnotationConfigApplicationContext( MainApp.class );
       }
    }
    

    Sehen Sie sich obige Erläuterungen zu den Basis-Annotationen an, sowie die Javadoc zu: @Configuration, @ComponentScan und AnnotationConfigApplicationContext.

  5. Erzeugen Sie im src/main/java/didemo-Verzeichnis eine Klasse mit mehreren DataSource-Beans: MeineDataSource.java

    package didemo;
    
    import javax.sql.DataSource;
    import org.apache.commons.dbcp2.BasicDataSource;
    import org.springframework.context.annotation.*;
    import org.springframework.jdbc.datasource.embedded.*;
    import org.springframework.jndi.JndiObjectFactoryBean;
    
    @Configuration
    public class MeineDataSource
    {
       // DataSource fuer "Entwicklung" und JUnit-Modultests:
       @Bean( destroyMethod="shutdown" )
       @Profile( "dev" )
       public DataSource dataSource1()
       {
          return new EmbeddedDatabaseBuilder()
                .setType( EmbeddedDatabaseType.H2 )
                .addScript( "classpath:schema.sql" )
                .addScript( "classpath:test-data.sql" )
                .build();
       }
    
       // DataSource fuer "Integrationstest" (URL-Pfad anpassen!):
       @Bean
       @Profile( "test" )
       public DataSource dataSource2()
       {
          BasicDataSource ds = new BasicDataSource();
          ds.setDriverClassName( "org.h2.Driver" );
          ds.setUrl( "jdbc:h2:./target/h2-db;DB_CLOSE_ON_EXIT=FALSE" );
          ds.setUsername( "sa" );
          ds.setPassword( "" );
          return ds;
       }
    
       // DataSource fuer "Produktion" (JNDI-Name appassen!):
       @Bean
       @Profile( "prod" )
       public DataSource dataSource3()
       {
          JndiObjectFactoryBean factBean = new JndiObjectFactoryBean();
          factBean.setJndiName( "jdbc/meineDataSource" );
          factBean.setResourceRef( true );
          factBean.setProxyInterface( javax.sql.DataSource.class );
          return (DataSource) factBean.getObject();
       }
    }
    

    Sehen Sie sich obige Erläuterungen zu den Basis-Annotationen an, sowie die Javadoc zu: @Configuration, @Bean, DataSource, EmbeddedDatabaseBuilder und EmbeddedDatabaseType.

    Falls Sie andere Datenbanken bevorzugen, sehen Sie sich beispielsweise die Infos an unter: andere Datenbanken und JpaTestUtil.

    Falls Sie die Datenbankparameter (URL, Username, Password etc.) nicht im Java-Code haben wollen, sondern per Properties-Datei übergeben wollen, sehen Sie sich beispielsweise an: Property Placeholder sowie Spring-Boot-Kommandozeilenanwendung mit JPA.

  6. Erzeugen Sie im src/main/resources-Verzeichnis zwei SQL-Skripte.

    schema.sql

    CREATE TABLE MeineEntity
    (
      id    INTEGER NOT NULL,
      datum DATE    NOT NULL,
      text  VARCHAR( 100 ),
      UNIQUE ( id ),
      PRIMARY KEY ( id )
    );
    

    test-data.sql

    INSERT INTO MeineEntity VALUES ( 1, '2017-01-01', 'Mein Test-Text' );
    
  7. Erzeugen Sie im src/test/java/didemo-Verzeichnis den JUnit-Modultest: MeineDataSourceTest.java

    package didemo;
    
    import java.sql.*;
    import javax.sql.DataSource;
    import org.junit.*;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.test.context.*;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    
    @RunWith( SpringJUnit4ClassRunner.class )
    @ContextConfiguration( classes = MainApp.class )
    // @ActiveProfiles( "dev" )
    public class MeineDataSourceTest
    {
       @Autowired
       private DataSource ds;
    
       @Test
       public void test() throws SQLException
       {
          Assert.assertNotNull( "DataSource ist null", ds );
          DatabaseMetaData md = ds.getConnection().getMetaData();
          System.out.println(
                "\nDB:  " + md.getDatabaseProductName() + " " + md.getDatabaseProductVersion() + ", " + md.getDriverName() +
                ",\nURL: " + md.getURL() + ", User: " + md.getUserName() + "\n" );
          try( ResultSet rs = ds.getConnection().createStatement().executeQuery( "Select * from MeineEntity" ) ) {
             ResultSetMetaData rsmd = rs.getMetaData();
             int n = rsmd.getColumnCount();
             while( rs.next() ) {
                for( int i = 1; i <= n; i++ ) {
                   System.out.println( rsmd.getColumnName( i ) + ": " + rs.getString( i ) );
                }
             }
          } catch( org.h2.jdbc.JdbcSQLException ex ) {
             System.out.println( ex.getMessage() );
          }
       }
    }
    

    Sehen Sie sich obige Erläuterungen zu den Basis-Annotationen an, sowie die Javadoc zu: @RunWith, SpringJUnit4ClassRunner, @ContextConfiguration, @ActiveProfiles, @Autowired, @Test und DataSource.

  8. Die Projektstruktur sieht jetzt so aus (überprüfen Sie es mit tree /F):

    [\MeinWorkspace\SpringDemo03-Ds]
     |- [src]
     |   |- [main]
     |   |   |- [java]
     |   |   |   '- [didemo]
     |   |   |       |- MainApp.java
     |   |   |       '- MeineDataSource.java
     |   |   '- [resources]
     |   |       |- schema.sql
     |   |       '- test-data.sql
     |   '- [test]
     |       '- [java]
     |           '- [didemo]
     |               '- MeineDataSourceTest.java
     '- pom.xml
    
  9. Führen Sie im Kommandozeilenfenster aus:

    cd \MeinWorkspace\SpringDemo03-Ds

    mvn clean test -Dspring.profiles.default=dev

  10. Sie erhalten:

    DB:  H2 1.4.193 (2016-10-31), H2 JDBC Driver,
    URL: jdbc:h2:mem:testdb, User: SA
    
    ID: 1
    DATUM: 2017-01-01
    TEXT: Mein Test-Text
    

    Da als Spring-Profil "dev" vorgegeben wurde, wurde aus der Klasse MeineDataSource die Bean mit der Methode dataSource1() verwendet, welche zwei SQL-Skripte ausführt.

    Die embedded H2-Datenbank wurde erfolgreich gestartet, die Tabelle MeineEntity wurde angelegt, der INSERT-Datensatz wurde geschrieben, und im JUnit-Modultest wurde der Datensatz erfolgreich gelesen.

  11. Wenn Sie die Angabe des Spring-Profils weglassen:

    mvn clean test

    erhalten Sie:

    org.springframework.beans.factory.NoSuchBeanDefinitionException:
    No qualifying bean of type 'javax.sql.DataSource' available:
    expected at least 1 bean which qualifies as autowire candidate.
    

    Die drei DataSource-Beans in MeineDataSource werden nur aktiv, wenn ein passendes Spring-Profil aktiviert ist.

  12. Wenn Sie in der MeineDataSource-Klasse die drei @Profile(...)-Annotationen entfernen oder alternativ alle drei Spring-Profile aktivieren:

    mvn clean test -Dspring.profiles.default=dev,test,prod

    erhalten Sie:

    org.springframework.beans.factory.NoUniqueBeanDefinitionException:
    No qualifying bean of type 'javax.sql.DataSource' available:
    expected single matching bean but found 3: dataSource1,dataSource2,dataSource3
    
  13. Die beiden Profile test und prod funktionieren nur, wenn es entsprechende Datenbanken bzw. JNDI-Konfigurationen gibt. Aber Sie können anhand der unterschiedlichen Fehlermeldung erkennen, dass die Umschaltung per Spring-Profil funktioniert:

    mvn clean test -Dspring.profiles.default=test

    mvn clean test -Dspring.profiles.default=prod

  14. Normalerweise soll der JUnit-Modultest immer im dev-Profil ausgeführt werden, unabhängig davon, welches andere Profil aktiviert ist. Um dies zu erreichen, entfernen Sie die Auskommentierung vor @ActiveProfiles( "dev" ) in der Testklasse MeineDataSourceTest.java. Dann funktioniert auch:

    mvn clean test

  15. Die Aktivierung von Spring-Profilen erfolgt über spring.profiles.active und spring.profiles.default, die über verschiedene Mechanismen gesetzt werden können, beispielsweise:

  16. Kompliziertere Bedingungen können mit der @Conditional-Annotation formuliert werden.

  17. Sehen Sie sich die vielen weiteren Möglichkeiten an, welche Spring-Profile bieten: Environment abstraction.

  18. Wenn Sie nicht zur Laufzeit, sondern beim Compilieren aus mehreren Beans die richtige auswählen wollen, sehen Sie sich die @Qualifier-Annotation an.



AOP-Demo mit Aspect, Pointcut und Advices

Das folgende einfache Beispiel demonstriert:

Sie können das Beispiel wahlweise entweder downloaden oder wie beschrieben Schritt für Schritt aufbauen und ausführen.

Führen Sie folgende Schritte aus:

  1. JDK und Maven müssen installiert sein.

  2. Wechseln Sie in Ihr Workspace-Verzeichnis (z.B. \MeinWorkspace) und führen Sie folgende Kommandos aus:

    cd \MeinWorkspace

    md SpringDemo05-AOP

    cd SpringDemo05-AOP

    md src\main\java\aopdemo

    md src\test\java\aopdemo

    tree /F

  3. Erstellen Sie im SpringDemo05-AOP-Projektverzeichnis die Maven-Projektkonfigurationsdatei: pom.xml

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <groupId>aopdemo</groupId>
      <artifactId>SpringAopDemo</artifactId>
      <version>1.0-SNAPSHOT</version>
      <properties>
        <spring.version>4.3.5.RELEASE</spring.version>
        <aspectj.version>1.8.10</aspectj.version>
      </properties>
      <dependencies>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-context</artifactId>
          <version>${spring.version}</version>
        </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-aop</artifactId>
          <version>${spring.version}</version>
        </dependency>
        <dependency>
          <groupId>org.aspectj</groupId>
          <artifactId>aspectjweaver</artifactId>
          <version>${aspectj.version}</version>
        </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-test</artifactId>
          <version>${spring.version}</version>
          <scope>test</scope>
        </dependency>
        <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>4.12</version>
          <scope>test</scope>
        </dependency>
      </dependencies>
      <!-- Der folgende build-Block wird nur benoetigt, falls eine ausfuehrbare Fat-Jar
           inklusive aller benoetigten Dependencies erstellt werden soll: -->
      <build>
        <plugins>
          <plugin>
            <artifactId>maven-assembly-plugin</artifactId>
            <version>3.0.0</version>
            <configuration>
              <descriptorRefs>
                <descriptorRef>jar-with-dependencies</descriptorRef>
              </descriptorRefs>
              <archive>
                <manifest>
                  <mainClass>aopdemo.MainApp</mainClass>
                </manifest>
              </archive>
            </configuration>
            <executions>
              <execution>
                <id>make-assembly</id>
                <phase>package</phase>
                <goals>
                  <goal>single</goal>
                </goals>
              </execution>
            </executions>
          </plugin>
        </plugins>
      </build>
    </project>
    

    Durch das maven-assembly-plugin wird eine ausführbare Fat-Jar inklusive aller benötigten Dependencies erstellt. Siehe hierzu: Ausführbare Jar-Datei inklusive Abhängigkeiten mit dem Assembly Plugin.

  4. Erzeugen Sie im src/main/java/aopdemo-Verzeichnis die Main- und Konfigurationsklasse: MainApp.java

    package aopdemo;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.annotation.*;
    
    @Configuration
    @ComponentScan
    @EnableAspectJAutoProxy
    public class MainApp
    {
       public static void main( String[] args )
       {
          ApplicationContext ctx = new AnnotationConfigApplicationContext( MainApp.class );
          if( args.length > 0 ) {
             int n = Integer.parseInt( args[0] );
             Fibonacci fibonacci = ctx.getBean( Fibonacci.class );
             System.out.println( "fibonacci( " + n + " ) = " + fibonacci.calc( n ) );
          }
       }
    }
    

    Sehen Sie sich obige Erläuterungen zu den Basis-Annotationen an, sowie die Javadoc zu: @Configuration, @ComponentScan, @EnableAspectJAutoProxy, ApplicationContext und AnnotationConfigApplicationContext.

  5. Erzeugen Sie im src/main/java/aopdemo-Verzeichnis die Spring-Bean: Fibonacci.java

    package aopdemo;
    
    import org.springframework.stereotype.Component;
    
    @Component
    public class Fibonacci
    {
       public long calc( int n )
       {
          return ( n < 2 ) ? n : (calc( n - 1 ) + calc( n - 2 ));
       }
    }
    

    Sehen Sie sich die Javadoc an zu: @Component.

  6. Erzeugen Sie im src/test/java/aopdemo-Verzeichnis den JUnit-Modultest: FibonacciTest.java

    package aopdemo;
    
    import org.junit.*;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    
    @RunWith( SpringJUnit4ClassRunner.class )
    @ContextConfiguration( classes = MainApp.class )
    public class FibonacciTest
    {
       @Autowired private Fibonacci fibonacci;
    
       @Test
       public void testFibonacci()
       {
          Assert.assertNotNull( fibonacci );
          Assert.assertEquals(  13, fibonacci.calc( 7 ) );
       }
    }
    

    Sehen Sie sich die Javadoc an zu: @RunWith, SpringJUnit4ClassRunner, @ContextConfiguration, @Autowired, @Test.

  7. Die Projektstruktur sieht jetzt so aus (überprüfen Sie es mit tree /F):

    [\MeinWorkspace\SpringDemo05-AOP]
     |- [src]
     |   |- [main]
     |   |   '- [java]
     |   |       '- [aopdemo]
     |   |           |- Fibonacci.java
     |   |           '- MainApp.java
     |   '- [test]
     |       '- [java]
     |           '- [aopdemo]
     |               '- FibonacciTest.java
     '- pom.xml
    
  8. Durch das maven-assembly-plugin wurde eine ausführbare Fat-Jar inklusive aller benötigten Dependencies erstellt. Führen Sie im Kommandozeilenfenster aus:

    cd \MeinWorkspace\SpringDemo05-AOP

    mvn clean package

    java -jar target\SpringAopDemo-1.0-SNAPSHOT-jar-with-dependencies.jar 8

    Sie erhalten:

    fibonacci( 8 ) = 21
    
  9. Bis jetzt haben wir ein lauffähiges normales Spring-DI-Projekt mit JUnit-Modultest erstellt (die einzige Besonderheit ist die @EnableAspectJAutoProxy-Annotation, die bislang noch keine Auswirkung hat). In den nächsten Schritten wird es um AOP erweitert.

  10. Erzeugen Sie im src/main/java/aopdemo-Verzeichnis die Aspect-Klasse mit einem Pointcut und drei Advices: MeinAspect.java

    package aopdemo;
    
    import java.util.Arrays;
    import org.aspectj.lang.*;
    import org.aspectj.lang.annotation.*;
    import org.springframework.stereotype.Component;
    
    @Component
    @Aspect
    public class MeinAspect
    {
       @Pointcut( "execution( * Fibonacci.*(..) )" )
       public void meinPointcut() {}
    
       @Before( "meinPointcut()" )
       public void logBefore( JoinPoint jp ) {
          System.out.println( "@Before:       " + jp );
       }
    
       @Around( "meinPointcut()" )
       public Object logAround( ProceedingJoinPoint jp ) throws Throwable {
          System.out.println( "\n@Around-Start, Argumente: " + Arrays.asList( jp.getArgs() ) );
          Object obj = jp.proceed();
          System.out.println( "@Around-Ende,  Ergebnis:  " + obj );
          return obj;
       }
    
       @After( "meinPointcut()" )
       public void logAfter( JoinPoint jp ) {
          System.out.println( "@After:        " + jp + "\n" );
       }
    }
    

    Sehen Sie sich die Javadoc an zu: @Component, @Aspect, @Before, @Around, @After, @Pointcut, JoinPoint, ProceedingJoinPoint.

    Bei den drei Advices hätte man statt der Verweise auf den Pointcut mit "meinPointcut()" auch jeweils direkt den Pointcut-Ausdruck "execution( * Fibonacci.*(..) )" verwenden können, also beispielsweise so:

    @Before( "execution( * Fibonacci.*(..) )" )

    Der Pointcut-Ausdruck "execution( * Fibonacci.*(..) )" ist in der "AspectJ Pointcut Expression Language" formuliert und besteht aus den fünf Teilen:
      execution: AspectJ-Designator für Method Join Point.
      *: Rückgabewert-Typ, * bedeutet beliebiger Typ.
      Fibonacci: Die zu überwachende Klasse, wahlweise inklusive Package.
      .*: Methodenname, .* bedeutet beliebiger Methodenname.
      (..): Methodenargumente, (..) bedeutet beliebige Argumente.
    Sehen Sie sich hierzu die Doku an: Declaring a pointcut und The AspectJ Programming Guide.
    Beachten Sie, dass zwar AspectJ-Annotationen und die AspectJ Pointcut Expression Language verwendet werden, aber trotzdem von Spring AOP nur eine Teilmenge der AspectJ-Funktionalität unterstützt wird.

  11. Die Projektstruktur sieht jetzt so aus (überprüfen Sie es mit tree /F):

    [\MeinWorkspace\SpringDemo05-AOP]
     |- [src]
     |   |- [main]
     |   |   '- [java]
     |   |       '- [aopdemo]
     |   |           |- Fibonacci.java
     |   |           |- MainApp.java
     |   |           '- MeinAspect.java
     |   '- [test]
     |       '- [java]
     |           '- [aopdemo]
     |               '- FibonacciTest.java
     '- pom.xml
    
  12. Führen Sie wieder im Kommandozeilenfenster aus:

    cd \MeinWorkspace\SpringDemo05-AOP

    mvn clean package

    java -jar target\SpringAopDemo-1.0-SNAPSHOT-jar-with-dependencies.jar 8

    Sie erhalten:

    Running aopdemo.FibonacciTest
    ...
    @Around-Start, Argumente: [7]
    @Before:       execution(long aopdemo.Fibonacci.calc(int))
    @Around-Ende,  Ergebnis:  13
    @After:        execution(long aopdemo.Fibonacci.calc(int))
    
    ...
    
    java -jar target\SpringAopDemo-1.0-SNAPSHOT-jar-with-dependencies.jar 8
    ...
    @Around-Start, Argumente: [8]
    @Before:       execution(long aopdemo.Fibonacci.calc(int))
    @Around-Ende,  Ergebnis:  21
    @After:        execution(long aopdemo.Fibonacci.calc(int))
    
    fibonacci( 8 ) = 21
    




Weitere Themen: andere TechDocs | Spring Boot | Spring Batch
© 2016 Torsten Horn, Aachen