From 175f1195738a8a747085507c8f3d98bb53763c80 Mon Sep 17 00:00:00 2001 From: Dmitry Zinkevich Date: Thu, 3 Dec 2015 13:46:25 +0300 Subject: [PATCH] Create AOP examples - Use different types of advice - Use various types of pointcut expressions --- .../java/org/baeldung/aop/LoggingAspect.java | 34 ++++++++++ .../org/baeldung/aop/PerformanceAspect.java | 2 +- .../org/baeldung/aop/PublishingAspect.java | 36 ++++++++++ .../main/java/org/baeldung/dao/FooDao.java | 6 ++ .../org/baeldung/events/FooCreationEvent.java | 10 +++ .../events/FooCreationEventListener.java | 17 +++++ .../src/main/java/org/baeldung/model/Foo.java | 19 ++++++ .../main/resources/org/baeldung/aop/beans.xml | 19 ++++++ .../java/org/baeldung/aop/AopLoggingTest.java | 67 +++++++++++++++++++ .../org/baeldung/aop/AopPublishingTest.java | 67 +++++++++++++++++++ .../aop/AopXmlConfigPerformanceTest.java | 67 +++++++++++++++++++ .../java/org/baeldung/config/TestConfig.java | 2 +- 12 files changed, 344 insertions(+), 2 deletions(-) create mode 100644 spring-mvc-java/src/main/java/org/baeldung/aop/LoggingAspect.java create mode 100644 spring-mvc-java/src/main/java/org/baeldung/aop/PublishingAspect.java create mode 100644 spring-mvc-java/src/main/java/org/baeldung/events/FooCreationEvent.java create mode 100644 spring-mvc-java/src/main/java/org/baeldung/events/FooCreationEventListener.java create mode 100644 spring-mvc-java/src/main/java/org/baeldung/model/Foo.java create mode 100644 spring-mvc-java/src/main/resources/org/baeldung/aop/beans.xml create mode 100644 spring-mvc-java/src/test/java/org/baeldung/aop/AopLoggingTest.java create mode 100644 spring-mvc-java/src/test/java/org/baeldung/aop/AopPublishingTest.java create mode 100644 spring-mvc-java/src/test/java/org/baeldung/aop/AopXmlConfigPerformanceTest.java diff --git a/spring-mvc-java/src/main/java/org/baeldung/aop/LoggingAspect.java b/spring-mvc-java/src/main/java/org/baeldung/aop/LoggingAspect.java new file mode 100644 index 0000000000..9317677fe2 --- /dev/null +++ b/spring-mvc-java/src/main/java/org/baeldung/aop/LoggingAspect.java @@ -0,0 +1,34 @@ +package org.baeldung.aop; + +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.aspectj.lang.annotation.Pointcut; +import org.springframework.stereotype.Component; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.logging.Logger; + +@Component +@Aspect +public class LoggingAspect { + + private static Logger logger = Logger.getLogger(LoggingAspect.class.getName()); + + private ThreadLocal sdf = new ThreadLocal() { + @Override + protected SimpleDateFormat initialValue() { + return new SimpleDateFormat("[yyyy-mm-dd hh:mm:ss:SSS]"); + } + }; + + @Pointcut("@target(org.springframework.stereotype.Repository)") + public void repositoryMethods() {} + + @Before("repositoryMethods()") + public void logMethodCall(JoinPoint jp) throws Throwable { + String methodName = jp.getSignature().getName(); + logger.info(sdf.get().format(new Date()) + methodName); + } +} diff --git a/spring-mvc-java/src/main/java/org/baeldung/aop/PerformanceAspect.java b/spring-mvc-java/src/main/java/org/baeldung/aop/PerformanceAspect.java index 12d6bc4e69..57f5bc5edd 100644 --- a/spring-mvc-java/src/main/java/org/baeldung/aop/PerformanceAspect.java +++ b/spring-mvc-java/src/main/java/org/baeldung/aop/PerformanceAspect.java @@ -16,7 +16,7 @@ public class PerformanceAspect { private static Logger logger = Logger.getLogger(PerformanceAspect.class.getName()); @Pointcut("within(@org.springframework.stereotype.Repository *)") - public void repositoryClassMethods() {}; + public void repositoryClassMethods() {} @Around("repositoryClassMethods()") public Object measureMethodExecutionTime(ProceedingJoinPoint pjp) throws Throwable { diff --git a/spring-mvc-java/src/main/java/org/baeldung/aop/PublishingAspect.java b/spring-mvc-java/src/main/java/org/baeldung/aop/PublishingAspect.java new file mode 100644 index 0000000000..20a10f4f6a --- /dev/null +++ b/spring-mvc-java/src/main/java/org/baeldung/aop/PublishingAspect.java @@ -0,0 +1,36 @@ +package org.baeldung.aop; + +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.AfterReturning; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.baeldung.events.FooCreationEvent; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.stereotype.Component; + +@Component +@Aspect +public class PublishingAspect { + + private ApplicationEventPublisher eventPublisher; + + @Autowired + public void setEventPublisher(ApplicationEventPublisher eventPublisher) { + this.eventPublisher = eventPublisher; + } + + @Pointcut("@target(org.springframework.stereotype.Repository)") + public void repositoryMethods() {} + + @Pointcut("execution(* *..create*(Long,..))") + public void firstLongParamMethods() {} + + @Pointcut("repositoryMethods() && firstLongParamMethods()") + public void entityCreationMethods() {} + + @AfterReturning(value = "entityCreationMethods()", returning = "entity") + public void logMethodCall(JoinPoint jp, Object entity) throws Throwable { + eventPublisher.publishEvent(new FooCreationEvent(entity)); + } +} diff --git a/spring-mvc-java/src/main/java/org/baeldung/dao/FooDao.java b/spring-mvc-java/src/main/java/org/baeldung/dao/FooDao.java index fbd7f4c717..e0da61c547 100644 --- a/spring-mvc-java/src/main/java/org/baeldung/dao/FooDao.java +++ b/spring-mvc-java/src/main/java/org/baeldung/dao/FooDao.java @@ -1,10 +1,16 @@ package org.baeldung.dao; +import org.baeldung.model.Foo; import org.springframework.stereotype.Repository; @Repository public class FooDao { + public String findById(Long id) { return "Bazz"; } + + public Foo create(Long id, String name) { + return new Foo(id, name); + } } diff --git a/spring-mvc-java/src/main/java/org/baeldung/events/FooCreationEvent.java b/spring-mvc-java/src/main/java/org/baeldung/events/FooCreationEvent.java new file mode 100644 index 0000000000..af11f3a4be --- /dev/null +++ b/spring-mvc-java/src/main/java/org/baeldung/events/FooCreationEvent.java @@ -0,0 +1,10 @@ +package org.baeldung.events; + +import org.springframework.context.ApplicationEvent; + +public class FooCreationEvent extends ApplicationEvent { + + public FooCreationEvent(Object source) { + super(source); + } +} diff --git a/spring-mvc-java/src/main/java/org/baeldung/events/FooCreationEventListener.java b/spring-mvc-java/src/main/java/org/baeldung/events/FooCreationEventListener.java new file mode 100644 index 0000000000..35dcfd2bc3 --- /dev/null +++ b/spring-mvc-java/src/main/java/org/baeldung/events/FooCreationEventListener.java @@ -0,0 +1,17 @@ +package org.baeldung.events; + +import org.springframework.context.ApplicationListener; +import org.springframework.stereotype.Component; + +import java.util.logging.Logger; + +@Component +public class FooCreationEventListener implements ApplicationListener { + + private static Logger logger = Logger.getLogger(FooCreationEventListener.class.getName()); + + @Override + public void onApplicationEvent(FooCreationEvent event) { + logger.info("Created foo instance: " + event.getSource().toString()); + } +} diff --git a/spring-mvc-java/src/main/java/org/baeldung/model/Foo.java b/spring-mvc-java/src/main/java/org/baeldung/model/Foo.java new file mode 100644 index 0000000000..17510f4836 --- /dev/null +++ b/spring-mvc-java/src/main/java/org/baeldung/model/Foo.java @@ -0,0 +1,19 @@ +package org.baeldung.model; + +public class Foo { + private Long id; + private String name; + + public Foo(Long id, String name) { + this.id = id; + this.name = name; + } + + @Override + public String toString() { + return "Foo{" + + "id=" + id + + ", name='" + name + '\'' + + '}'; + } +} diff --git a/spring-mvc-java/src/main/resources/org/baeldung/aop/beans.xml b/spring-mvc-java/src/main/resources/org/baeldung/aop/beans.xml new file mode 100644 index 0000000000..17c63e39e4 --- /dev/null +++ b/spring-mvc-java/src/main/resources/org/baeldung/aop/beans.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/spring-mvc-java/src/test/java/org/baeldung/aop/AopLoggingTest.java b/spring-mvc-java/src/test/java/org/baeldung/aop/AopLoggingTest.java new file mode 100644 index 0000000000..7aff17c424 --- /dev/null +++ b/spring-mvc-java/src/test/java/org/baeldung/aop/AopLoggingTest.java @@ -0,0 +1,67 @@ +package org.baeldung.aop; + +import org.baeldung.config.TestConfig; +import org.baeldung.dao.FooDao; +import org.junit.Before; +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; +import org.springframework.test.context.support.AnnotationConfigContextLoader; + +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Handler; +import java.util.logging.LogRecord; +import java.util.logging.Logger; +import java.util.regex.Pattern; + +import static org.hamcrest.Matchers.hasSize; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = {TestConfig.class}, loader = AnnotationConfigContextLoader.class) +public class AopLoggingTest { + + @Before + public void setUp() { + logEventHandler = new Handler() { + @Override + public void publish(LogRecord record) { + messages.add(record.getMessage()); + } + + @Override + public void flush() { + } + + @Override + public void close() throws SecurityException { + } + }; + + messages = new ArrayList<>(); + } + + @Autowired + private FooDao dao; + + private Handler logEventHandler; + + private List messages; + + @Test + public void givenLoggingAspect_whenCallDaoMethod_thenBeforeAdviceIsCalled() { + Logger logger = Logger.getLogger(LoggingAspect.class.getName()); + logger.addHandler(logEventHandler); + + dao.findById(1L); + assertThat(messages, hasSize(1)); + + String logMessage = messages.get(0); + Pattern pattern = Pattern.compile("^\\[\\d{4}\\-\\d{2}\\-\\d{2} \\d{2}:\\d{2}:\\d{2}:\\d{3}\\]findById$"); + assertTrue(pattern.matcher(logMessage).matches()); + } +} diff --git a/spring-mvc-java/src/test/java/org/baeldung/aop/AopPublishingTest.java b/spring-mvc-java/src/test/java/org/baeldung/aop/AopPublishingTest.java new file mode 100644 index 0000000000..561eec06ec --- /dev/null +++ b/spring-mvc-java/src/test/java/org/baeldung/aop/AopPublishingTest.java @@ -0,0 +1,67 @@ +package org.baeldung.aop; + +import org.baeldung.config.TestConfig; +import org.baeldung.dao.FooDao; +import org.baeldung.events.FooCreationEventListener; +import org.baeldung.model.Foo; +import org.junit.Before; +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; +import org.springframework.test.context.support.AnnotationConfigContextLoader; + +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Handler; +import java.util.logging.LogRecord; +import java.util.logging.Logger; +import java.util.regex.Pattern; + +import static org.junit.Assert.assertTrue; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = {TestConfig.class}, loader = AnnotationConfigContextLoader.class) +public class AopPublishingTest { + + @Before + public void setUp() { + logEventHandler = new Handler() { + @Override + public void publish(LogRecord record) { + messages.add(record.getMessage()); + } + + @Override + public void flush() { + } + + @Override + public void close() throws SecurityException { + } + }; + + messages = new ArrayList<>(); + } + + @Autowired + private FooDao dao; + + private Handler logEventHandler; + + private List messages; + + @Test + public void givenPublishingAspect_whenCallCreate_thenCreationEventIsPublished() { + Logger logger = Logger.getLogger(FooCreationEventListener.class.getName()); + logger.addHandler(logEventHandler); + + dao.create(1L, "Bar"); + + String logMessage = messages.get(0); + Pattern pattern = Pattern.compile("Created foo instance: " + + Pattern.quote(new Foo(1L, "Bar").toString())); + assertTrue(pattern.matcher(logMessage).matches()); + } +} diff --git a/spring-mvc-java/src/test/java/org/baeldung/aop/AopXmlConfigPerformanceTest.java b/spring-mvc-java/src/test/java/org/baeldung/aop/AopXmlConfigPerformanceTest.java new file mode 100644 index 0000000000..7ef25d743c --- /dev/null +++ b/spring-mvc-java/src/test/java/org/baeldung/aop/AopXmlConfigPerformanceTest.java @@ -0,0 +1,67 @@ +package org.baeldung.aop; + +import org.baeldung.dao.FooDao; +import org.junit.Before; +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; + +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Handler; +import java.util.logging.LogRecord; +import java.util.logging.Logger; +import java.util.regex.Pattern; + +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.Matchers.hasSize; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration("/org/baeldung/aop/beans.xml") +public class AopXmlConfigPerformanceTest { + + @Before + public void setUp() { + logEventHandler = new Handler() { + @Override + public void publish(LogRecord record) { + messages.add(record.getMessage()); + } + + @Override + public void flush() { + } + + @Override + public void close() throws SecurityException { + } + }; + + messages = new ArrayList<>(); + } + + @Autowired + private FooDao dao; + + private Handler logEventHandler; + + private List messages; + + @Test + public void givenPerformanceAspect_whenCallDaoMethod_thenPerformanceMeasurementAdviceIsCalled() { + Logger logger = Logger.getLogger(PerformanceAspect.class.getName()); + logger.addHandler(logEventHandler); + + final String entity = dao.findById(1L); + assertThat(entity, notNullValue()); + assertThat(messages, hasSize(1)); + + String logMessage = messages.get(0); + Pattern pattern = Pattern.compile("Execution of findById took \\d+ ms"); + assertTrue(pattern.matcher(logMessage).matches()); + } +} diff --git a/spring-mvc-java/src/test/java/org/baeldung/config/TestConfig.java b/spring-mvc-java/src/test/java/org/baeldung/config/TestConfig.java index 60786a108c..0d103f1029 100644 --- a/spring-mvc-java/src/test/java/org/baeldung/config/TestConfig.java +++ b/spring-mvc-java/src/test/java/org/baeldung/config/TestConfig.java @@ -5,7 +5,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy; @Configuration -@ComponentScan(basePackages = {"org.baeldung.dao", "org.baeldung.aop"}) +@ComponentScan(basePackages = {"org.baeldung.dao", "org.baeldung.aop", "org.baeldung.events"}) @EnableAspectJAutoProxy public class TestConfig { }