AspectJ、Spring、Maven

私たちのグループでは、環境をセットアップし、AspectJアスペクトの使用とSpringとの統合を示すように頼まれました。
habrosocietyも面白いかもしれないと私には思えました。

ここでは、AspectJが何であるかについては説明しません。AspectJは便利です。アスペクトとは、コンパイルや実行時の段階でクラスに機能を追加する機能であることに注意してください。 または、既存のものを変更します。

次:プロジェクトの構成と3つの例の側面。


Maven設定から始めましょう:
<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/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.habloexample</groupId> <artifactId>aspects</artifactId> <packaging>jar</packaging> <version>0.0.1-SNAPSHOT</version> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.8.2</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>3.0.5.RELEASE</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>1.6.7</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.0.2</version> <configuration> <source>${maven.compiler.source}</source> <target>${maven.compiler.target}</target> </configuration> </plugin> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>aspectj-maven-plugin</artifactId> <version>1.3</version> <configuration> <source>${maven.compiler.source}</source> <target>${maven.compiler.target}</target> </configuration> <executions> <execution> <goals> <goal>compile</goal> <goal>test-compile</goal> </goals> </execution> </executions> </plugin> </plugins> </build> <properties> <org.springframework.version>3.0.5.RELEASE</org.springframework.version> <maven.compiler.source>1.6</maven.compiler.source> <maven.compiler.target>1.6</maven.compiler.target> </properties> </project><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/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.habloexample</groupId> <artifactId>aspects</artifactId> <packaging>jar</packaging> <version>0.0.1-SNAPSHOT</version> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.8.2</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>3.0.5.RELEASE</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>1.6.7</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.0.2</version> <configuration> <source>${maven.compiler.source}</source> <target>${maven.compiler.target}</target> </configuration> </plugin> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>aspectj-maven-plugin</artifactId> <version>1.3</version> <configuration> <source>${maven.compiler.source}</source> <target>${maven.compiler.target}</target> </configuration> <executions> <execution> <goals> <goal>compile</goal> <goal>test-compile</goal> </goals> </execution> </executions> </plugin> </plugins> </build> <properties> <org.springframework.version>3.0.5.RELEASE</org.springframework.version> <maven.compiler.source>1.6</maven.compiler.source> <maven.compiler.target>1.6</maven.compiler.target> </properties> </project>
<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/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.habloexample</groupId> <artifactId>aspects</artifactId> <packaging>jar</packaging> <version>0.0.1-SNAPSHOT</version> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.8.2</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>3.0.5.RELEASE</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>1.6.7</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.0.2</version> <configuration> <source>${maven.compiler.source}</source> <target>${maven.compiler.target}</target> </configuration> </plugin> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>aspectj-maven-plugin</artifactId> <version>1.3</version> <configuration> <source>${maven.compiler.source}</source> <target>${maven.compiler.target}</target> </configuration> <executions> <execution> <goals> <goal>compile</goal> <goal>test-compile</goal> </goals> </execution> </executions> </plugin> </plugins> </build> <properties> <org.springframework.version>3.0.5.RELEASE</org.springframework.version> <maven.compiler.source>1.6</maven.compiler.source> <maven.compiler.target>1.6</maven.compiler.target> </properties> </project>


次に、Intellij IDEAで:
プラグインAspectJ:有効
プラグインAspectJ Weaver:無効化
設定/コンパイル/ JavaCompiler:Ajc

例1、注釈付きのAspectJ、注釈付きのSpring:

www.javacodegeeks.com/2010/07/aspect-oriented-programming-with-spring.htmlから取られた例)

クラスを作成します。

package org.habr.springaspectj.services; import org.springframework.stereotype.Service; @Service("greetingService") public class GreetingService { public static final String HELLO_FROM_GREETING_SERVICE = "Hello from Greeting Service"; public String sayHello() { return HELLO_FROM_GREETING_SERVICE; } }package org.habr.springaspectj.services; import org.springframework.stereotype.Service; @Service("greetingService") public class GreetingService { public static final String HELLO_FROM_GREETING_SERVICE = "Hello from Greeting Service"; public String sayHello() { return HELLO_FROM_GREETING_SERVICE; } }
package org.habr.springaspectj.services; import org.springframework.stereotype.Service; @Service("greetingService") public class GreetingService { public static final String HELLO_FROM_GREETING_SERVICE = "Hello from Greeting Service"; public String sayHello() { return HELLO_FROM_GREETING_SERVICE; } }


アスペクトを作成します。

package org.habr.springaspectj.aspects; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; @Aspect public class GreetingAspect { private String message; public void setMessage(String message) { this.message = message; } @Around("execution(* org.habr.springaspectj.services.GreetingService.*(..))") public Object advice(ProceedingJoinPoint pjp) throws Throwable { String serviceGreeting = (String) pjp.proceed(); return message + " and " + serviceGreeting; } }package org.habr.springaspectj.aspects; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; @Aspect public class GreetingAspect { private String message; public void setMessage(String message) { this.message = message; } @Around("execution(* org.habr.springaspectj.services.GreetingService.*(..))") public Object advice(ProceedingJoinPoint pjp) throws Throwable { String serviceGreeting = (String) pjp.proceed(); return message + " and " + serviceGreeting; } }
package org.habr.springaspectj.aspects; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; @Aspect public class GreetingAspect { private String message; public void setMessage(String message) { this.message = message; } @Around("execution(* org.habr.springaspectj.services.GreetingService.*(..))") public Object advice(ProceedingJoinPoint pjp) throws Throwable { String serviceGreeting = (String) pjp.proceed(); return message + " and " + serviceGreeting; } }


Spring用のtest-aspectj.xmlを作成します。

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:task="http://www.springframework.org/schema/task" xsi:schemaLocation=" http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd"> <context:component-scan base-package="org.habr.springaspectj" /> <bean class="org.habr.springaspectj.aspects.GreetingAspect" factory-method="aspectOf"> <property name="message" value="Hello from Greeting Aspect"/> </bean> <beans><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:task="http://www.springframework.org/schema/task" xsi:schemaLocation=" http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd"> <context:component-scan base-package="org.habr.springaspectj" /> <bean class="org.habr.springaspectj.aspects.GreetingAspect" factory-method="aspectOf"> <property name="message" value="Hello from Greeting Aspect"/> </bean> <beans>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:task="http://www.springframework.org/schema/task" xsi:schemaLocation=" http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd"> <context:component-scan base-package="org.habr.springaspectj" /> <bean class="org.habr.springaspectj.aspects.GreetingAspect" factory-method="aspectOf"> <property name="message" value="Hello from Greeting Aspect"/> </bean> <beans>

私たちはテストを書いています:

package org.habr.springaspectj; import org.habr.springaspectj.services.GreetingService; import org.habr.springaspectj.services.IncrementService; import org.junit.Before; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertTrue; public class AspectAnnotationTest { ApplicationContext context ; @Before public void init() { context = new ClassPathXmlApplicationContext("test-aspectj.xml"); } @Test public void testAnnotationService() { GreetingService greetingService = (GreetingService) context.getBean("greetingService"); assertTrue(greetingService.sayHello().contains(GreetingService.HELLO_FROM_GREETING_SERVICE)); assertTrue(greetingService.sayHello().length()>GreetingService.HELLO_FROM_GREETING_SERVICE.length()); } }package org.habr.springaspectj; import org.habr.springaspectj.services.GreetingService; import org.habr.springaspectj.services.IncrementService; import org.junit.Before; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertTrue; public class AspectAnnotationTest { ApplicationContext context ; @Before public void init() { context = new ClassPathXmlApplicationContext("test-aspectj.xml"); } @Test public void testAnnotationService() { GreetingService greetingService = (GreetingService) context.getBean("greetingService"); assertTrue(greetingService.sayHello().contains(GreetingService.HELLO_FROM_GREETING_SERVICE)); assertTrue(greetingService.sayHello().length()>GreetingService.HELLO_FROM_GREETING_SERVICE.length()); } }
package org.habr.springaspectj; import org.habr.springaspectj.services.GreetingService; import org.habr.springaspectj.services.IncrementService; import org.junit.Before; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertTrue; public class AspectAnnotationTest { ApplicationContext context ; @Before public void init() { context = new ClassPathXmlApplicationContext("test-aspectj.xml"); } @Test public void testAnnotationService() { GreetingService greetingService = (GreetingService) context.getBean("greetingService"); assertTrue(greetingService.sayHello().contains(GreetingService.HELLO_FROM_GREETING_SERVICE)); assertTrue(greetingService.sayHello().length()>GreetingService.HELLO_FROM_GREETING_SERVICE.length()); } }


サービスとアスペクトは、src / main / javaの対応するパッケージに移動します
src / test / javaでテストする

テストは、元のメッセージに何かが追加されたことを確認します。
greetingService.sayHello()を印刷すると、xmlアスペクトで渡される行が追加されていることがわかります。

例2.注釈なしでの、メソッドの動作の変更。



サービスを追加します。

package org.habr.springaspectj.services; public class IncrementService { public int inc(int i){ return i+1; } }package org.habr.springaspectj.services; public class IncrementService { public int inc(int i){ return i+1; } }
package org.habr.springaspectj.services; public class IncrementService { public int inc(int i){ return i+1; } }


アスペクトを追加します。

package org.habr.springaspectj.aspects; public aspect DecrementAspect { pointcut incMethod(): execution(public int inc(int)); int around(int number): incMethod() && args(number) { return proceed(number) - 1; } }package org.habr.springaspectj.aspects; public aspect DecrementAspect { pointcut incMethod(): execution(public int inc(int)); int around(int number): incMethod() && args(number) { return proceed(number) - 1; } }
package org.habr.springaspectj.aspects; public aspect DecrementAspect { pointcut incMethod(): execution(public int inc(int)); int around(int number): incMethod() && args(number) { return proceed(number) - 1; } }


サービスをxmlに追加します(約束-今回は注釈なし):

<bean name="inc-bean" class="org.habr.springaspectj.services.IncrementService"/><bean name="inc-bean" class="org.habr.springaspectj.services.IncrementService"/>
<bean name="inc-bean" class="org.habr.springaspectj.services.IncrementService"/>


メソッドを単体テストに追加します。

@Test public void testBeanAndAJService() { IncrementService service = context.getBean(IncrementService.class); int i = 10; assertEquals(i,service.inc(i)); }@Test public void testBeanAndAJService() { IncrementService service = context.getBean(IncrementService.class); int i = 10; assertEquals(i,service.inc(i)); }
@Test public void testBeanAndAJService() { IncrementService service = context.getBean(IncrementService.class); int i = 10; assertEquals(i,service.inc(i)); }


やった! 増分しますが、数は増えません!

注:IDEAのアスペクトサポートは完全ではありません。 上記の側面は赤でマークされますが、ブイとMavenとIDEAがコンパイルされます。

例3:存在しないメソッドの追加



前の例のサービスで、アスペクトを追加します:

package org.habr.springaspectj.aspects; public aspect AddingAspect { public String org.habr.springaspectj.services.IncrementService.myCall(String name) { return "Cognac " + name; } }package org.habr.springaspectj.aspects; public aspect AddingAspect { public String org.habr.springaspectj.services.IncrementService.myCall(String name) { return "Cognac " + name; } }
package org.habr.springaspectj.aspects; public aspect AddingAspect { public String org.habr.springaspectj.services.IncrementService.myCall(String name) { return "Cognac " + name; } }


メソッドをテストに追加します。

@Test public void testAddAMethod() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { IncrementService service = context.getBean(IncrementService.class); assertEquals(service.myCall("Hennesy"),"Cognac Hennesy"); }@Test public void testAddAMethod() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { IncrementService service = context.getBean(IncrementService.class); assertEquals(service.myCall("Hennesy"),"Cognac Hennesy"); }
@Test public void testAddAMethod() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { IncrementService service = context.getBean(IncrementService.class); assertEquals(service.myCall("Hennesy"),"Cognac Hennesy"); }


サービスクラスにmyCallメソッドがないにもかかわらず、IDEAは文句を言わず、すべてがコンパイルされます

結論:


控えめに言っても、コードの理解度や読みやすさは向上しません。特別な必要なしに使用することはお勧めしません。
しかし、本当に必要な場合は、これらの例が役立ちます。

コメントは結論を変えることを勧めた...
アスペクトは、ジャーナリング、監査、トランザクションなどのいくつかの領域に適用する必要があります。
そして、非常に慎重に他の領域でそれらを使用する必要があります。 アスペクトを使用すると、コード内の1つのことを確認し、他の何かが機能することを簡単に確認できます。

Source: https://habr.com/ru/post/J112466/


All Articles