Merge pull request #11638 from freelansam/JAVA-8280
JAVA-8280: Split or move spring-aop module
This commit is contained in:
@@ -6,11 +6,9 @@ This module contains articles about Spring aspect oriented programming (AOP)
|
||||
|
||||
- [Implementing a Custom Spring AOP Annotation](https://www.baeldung.com/spring-aop-annotation)
|
||||
- [Intro to AspectJ](https://www.baeldung.com/aspectj)
|
||||
- [Spring Performance Logging](https://www.baeldung.com/spring-performance-logging)
|
||||
- [Introduction to Spring AOP](https://www.baeldung.com/spring-aop)
|
||||
- [Introduction to Pointcut Expressions in Spring](https://www.baeldung.com/spring-aop-pointcut-tutorial)
|
||||
- [Introduction to Advice Types in Spring](https://www.baeldung.com/spring-aop-advice-tutorial)
|
||||
- [When Does Java Throw UndeclaredThrowableException?](https://www.baeldung.com/java-undeclaredthrowableexception)
|
||||
- [Get Advised Method Info in Spring AOP](https://www.baeldung.com/spring-aop-get-advised-method-info)
|
||||
- [Advise Methods on Annotated Classes With AspectJ](https://www.baeldung.com/aspectj-advise-methods)
|
||||
- [Joinpoint vs. ProceedingJoinPoint in AspectJ](https://www.baeldung.com/aspectj-joinpoint-proceedingjoinpoint)
|
||||
- More articles: [[next -->]](/spring-aop-2)
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
package com.baeldung.method.info;
|
||||
|
||||
public class Account {
|
||||
|
||||
private String accountNumber;
|
||||
private double balance;
|
||||
|
||||
public String getAccountNumber() {
|
||||
return accountNumber;
|
||||
}
|
||||
|
||||
public void setAccountNumber(String accountNumber) {
|
||||
this.accountNumber = accountNumber;
|
||||
}
|
||||
|
||||
public double getBalance() {
|
||||
return balance;
|
||||
}
|
||||
|
||||
public void setBalance(double balance) {
|
||||
this.balance = balance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Account{" + "accountNumber='" + accountNumber + '\'' + ", balance=" + balance + '}';
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package com.baeldung.method.info;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface AccountOperation {
|
||||
String operation();
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
package com.baeldung.method.info;
|
||||
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.annotation.Before;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Arrays;
|
||||
|
||||
@Aspect
|
||||
@Component
|
||||
public class BankAccountAspect {
|
||||
|
||||
@Before(value = "@annotation(com.baeldung.method.info.AccountOperation)")
|
||||
public void getAccountOperationInfo(JoinPoint joinPoint) {
|
||||
|
||||
// Method Information
|
||||
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
|
||||
|
||||
System.out.println("full method description: " + signature.getMethod());
|
||||
|
||||
System.out.println("method name: " + signature.getMethod().getName());
|
||||
|
||||
System.out.println("declaring type: " + signature.getDeclaringType());
|
||||
|
||||
// Method args
|
||||
System.out.println("Method args names:");
|
||||
Arrays.stream(signature.getParameterNames())
|
||||
.forEach(s -> System.out.println("arg name: " + s));
|
||||
|
||||
System.out.println("Method args types:");
|
||||
Arrays.stream(signature.getParameterTypes())
|
||||
.forEach(s -> System.out.println("arg type: " + s));
|
||||
|
||||
System.out.println("Method args values:");
|
||||
Arrays.stream(joinPoint.getArgs())
|
||||
.forEach(o -> System.out.println("arg value: " + o.toString()));
|
||||
|
||||
// Additional Information
|
||||
System.out.println("returning type: " + signature.getReturnType());
|
||||
System.out.println("method modifier: " + Modifier.toString(signature.getModifiers()));
|
||||
Arrays.stream(signature.getExceptionTypes())
|
||||
.forEach(aClass -> System.out.println("exception type: " + aClass));
|
||||
|
||||
// Method annotation
|
||||
Method method = signature.getMethod();
|
||||
AccountOperation accountOperation = method.getAnnotation(AccountOperation.class);
|
||||
System.out.println("Account operation annotation: " + accountOperation);
|
||||
System.out.println("Account operation value: " + accountOperation.operation());
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
package com.baeldung.method.info;
|
||||
|
||||
import org.apache.commons.lang3.RandomUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class BankAccountService {
|
||||
|
||||
@AccountOperation(operation = "deposit")
|
||||
public void deposit(Account account, Double amount) {
|
||||
account.setBalance(account.getBalance() + amount);
|
||||
}
|
||||
|
||||
@AccountOperation(operation = "withdraw")
|
||||
public void withdraw(Account account, Double amount) throws WithdrawLimitException {
|
||||
|
||||
if (amount > 500.0) {
|
||||
throw new WithdrawLimitException("Withdraw limit exceeded.");
|
||||
}
|
||||
|
||||
account.setBalance(account.getBalance() - amount);
|
||||
|
||||
}
|
||||
|
||||
public double getBalance() {
|
||||
return RandomUtils.nextDouble();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
package com.baeldung.method.info;
|
||||
|
||||
public class WithdrawLimitException extends RuntimeException {
|
||||
public WithdrawLimitException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
package com.baeldung.performancemonitor;
|
||||
|
||||
import org.aspectj.lang.annotation.Pointcut;
|
||||
import org.springframework.aop.Advisor;
|
||||
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
|
||||
import org.springframework.aop.interceptor.PerformanceMonitorInterceptor;
|
||||
import org.springframework.aop.support.DefaultPointcutAdvisor;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.EnableAspectJAutoProxy;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.Month;
|
||||
|
||||
@Configuration
|
||||
@EnableAspectJAutoProxy
|
||||
public class AopConfiguration {
|
||||
|
||||
@Pointcut("execution(public String com.baeldung.performancemonitor.PersonService.getFullName(..))")
|
||||
public void monitor() { }
|
||||
|
||||
@Pointcut("execution(public int com.baeldung.performancemonitor.PersonService.getAge(..))")
|
||||
public void myMonitor() { }
|
||||
|
||||
@Bean
|
||||
public PerformanceMonitorInterceptor performanceMonitorInterceptor() {
|
||||
return new PerformanceMonitorInterceptor(true);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Advisor performanceMonitorAdvisor() {
|
||||
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
|
||||
pointcut.setExpression("com.baeldung.performancemonitor.AopConfiguration.monitor()");
|
||||
return new DefaultPointcutAdvisor(pointcut, performanceMonitorInterceptor());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Person person(){
|
||||
return new Person("John","Smith", LocalDate.of(1980, Month.JANUARY, 12));
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PersonService personService(){
|
||||
return new PersonService();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MyPerformanceMonitorInterceptor myPerformanceMonitorInterceptor() {
|
||||
return new MyPerformanceMonitorInterceptor(true);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Advisor myPerformanceMonitorAdvisor() {
|
||||
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
|
||||
pointcut.setExpression("com.baeldung.performancemonitor.AopConfiguration.myMonitor()");
|
||||
return new DefaultPointcutAdvisor(pointcut, myPerformanceMonitorInterceptor());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
package com.baeldung.performancemonitor;
|
||||
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.springframework.aop.interceptor.AbstractMonitoringInterceptor;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public class MyPerformanceMonitorInterceptor extends AbstractMonitoringInterceptor {
|
||||
|
||||
public MyPerformanceMonitorInterceptor() {
|
||||
}
|
||||
|
||||
public MyPerformanceMonitorInterceptor(boolean useDynamicLogger) {
|
||||
setUseDynamicLogger(useDynamicLogger);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object invokeUnderTrace(MethodInvocation invocation, Log log) throws Throwable {
|
||||
|
||||
String name = createInvocationTraceName(invocation);
|
||||
long start = System.currentTimeMillis();
|
||||
log.info("Method "+name+" execution started at:"+new Date());
|
||||
try {
|
||||
return invocation.proceed();
|
||||
}
|
||||
finally {
|
||||
long end = System.currentTimeMillis();
|
||||
long time = end - start;
|
||||
log.info("Method "+name+" execution lasted:"+time+" ms");
|
||||
log.info("Method "+name+" execution ended at:"+new Date());
|
||||
|
||||
if (time > 10){
|
||||
log.warn("Method execution longer than 10 ms!");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
package com.baeldung.performancemonitor;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
|
||||
public class PerfomanceApp {
|
||||
public static void main(String[] args) {
|
||||
|
||||
ApplicationContext context = new AnnotationConfigApplicationContext(AopConfiguration.class);
|
||||
Person person = (Person) context.getBean("person");
|
||||
PersonService personService = (PersonService) context.getBean("personService");
|
||||
|
||||
System.out.println("Name is:"+personService.getFullName(person));
|
||||
System.out.println("Age is:"+personService.getAge(person));
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
package com.baeldung.performancemonitor;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
public class Person {
|
||||
private String lastName;
|
||||
private String firstName;
|
||||
private LocalDate dateOfBirth;
|
||||
|
||||
public Person() {
|
||||
}
|
||||
|
||||
public Person(String firstName, String lastName, LocalDate dateOfBirth) {
|
||||
this.firstName = firstName;
|
||||
this.lastName = lastName;
|
||||
this.dateOfBirth = dateOfBirth;
|
||||
}
|
||||
|
||||
public LocalDate getDateOfBirth() {
|
||||
return dateOfBirth;
|
||||
}
|
||||
|
||||
public void setDateOfBirth(LocalDate dateOfBirth) {
|
||||
this.dateOfBirth = dateOfBirth;
|
||||
}
|
||||
|
||||
public String getLastName() {
|
||||
return lastName;
|
||||
}
|
||||
|
||||
public void setLastName(String lastName) {
|
||||
this.lastName = lastName;
|
||||
}
|
||||
|
||||
public String getFirstName() {
|
||||
return firstName;
|
||||
}
|
||||
|
||||
public void setFirstName(String firstName) {
|
||||
this.firstName = firstName;
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
package com.baeldung.performancemonitor;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.Period;
|
||||
|
||||
public class PersonService {
|
||||
|
||||
public String getFullName(Person person){
|
||||
return person.getLastName()+" "+person.getFirstName();
|
||||
}
|
||||
|
||||
public int getAge(Person person){
|
||||
Period p = Period.between(person.getDateOfBirth(), LocalDate.now());
|
||||
return p.getYears();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -13,10 +13,6 @@
|
||||
<!-- in order to debug some marshalling issues, this needs to be TRACE -->
|
||||
<logger name="org.springframework.web.servlet.mvc" level="WARN" />
|
||||
|
||||
<logger name="com.baeldung.performancemonitor.MyPerformanceMonitorInterceptor" level="INFO" />
|
||||
|
||||
<logger name="org.springframework.aop.interceptor.PerformanceMonitorInterceptor" level="TRACE" />
|
||||
|
||||
<logger name="com.baeldung.aspectj.classmethodadvice" level="TRACE" />
|
||||
|
||||
<root level="TRACE">
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
package com.baeldung.method.info;
|
||||
|
||||
import org.assertj.core.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
@SpringBootTest
|
||||
class BankAccountServiceIntegrationTest {
|
||||
|
||||
private Account account;
|
||||
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
account = new Account();
|
||||
account.setAccountNumber("12345");
|
||||
account.setBalance(2000.0);
|
||||
}
|
||||
|
||||
@Autowired
|
||||
BankAccountService bankAccountService;
|
||||
|
||||
@Test
|
||||
void withdraw() {
|
||||
bankAccountService.withdraw(account, 500.0);
|
||||
assertTrue(account.getBalance() == 1500.0);
|
||||
}
|
||||
|
||||
@Test
|
||||
void withdrawWhenLimitReached() {
|
||||
Assertions.assertThatExceptionOfType(WithdrawLimitException.class)
|
||||
.isThrownBy(() -> bankAccountService.withdraw(account, 600.0));
|
||||
assertTrue(account.getBalance() == 2000.0);
|
||||
}
|
||||
|
||||
@Test
|
||||
void deposit() {
|
||||
bankAccountService.deposit(account, 500.0);
|
||||
assertTrue(account.getBalance() == 2500.0);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getBalance() {
|
||||
bankAccountService.getBalance();
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
package com.baeldung.undeclared;
|
||||
|
||||
public class SomeCheckedException extends Exception {
|
||||
public SomeCheckedException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package com.baeldung.undeclared;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface ThrowUndeclared {
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package com.baeldung.undeclared;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class UndeclaredApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(UndeclaredApplication.class, args);
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
package com.baeldung.undeclared;
|
||||
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Aspect
|
||||
@Component
|
||||
public class UndeclaredAspect {
|
||||
|
||||
@Around("@annotation(undeclared)")
|
||||
public Object advise(ProceedingJoinPoint pjp, ThrowUndeclared undeclared) throws Throwable {
|
||||
throw new SomeCheckedException("AOP Checked Exception");
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
package com.baeldung.undeclared;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class UndeclaredService {
|
||||
|
||||
@ThrowUndeclared
|
||||
public void doSomething() {}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
package com.baeldung.undeclared;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import java.lang.reflect.UndeclaredThrowableException;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(classes = UndeclaredApplication.class)
|
||||
public class UndeclaredThrowableExceptionIntegrationTest {
|
||||
|
||||
@Autowired private UndeclaredService service;
|
||||
|
||||
@Test
|
||||
public void givenAnAspect_whenCallingAdvisedMethod_thenShouldWrapTheException() {
|
||||
assertThatThrownBy(service::doSomething)
|
||||
.isInstanceOf(UndeclaredThrowableException.class)
|
||||
.hasCauseInstanceOf(SomeCheckedException.class);
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
package com.baeldung.undeclared;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.lang.reflect.UndeclaredThrowableException;
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
public class UndeclaredThrowableExceptionUnitTest {
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void givenAProxy_whenProxyUndeclaredThrowsCheckedException_thenShouldBeWrapped() {
|
||||
ClassLoader classLoader = getClass().getClassLoader();
|
||||
InvocationHandler invocationHandler = new ExceptionalInvocationHandler();
|
||||
List<String> proxy = (List<String>) Proxy.newProxyInstance(classLoader, new Class[] { List.class }, invocationHandler);
|
||||
|
||||
assertThatThrownBy(proxy::size)
|
||||
.isInstanceOf(UndeclaredThrowableException.class)
|
||||
.hasCauseInstanceOf(SomeCheckedException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void givenAProxy_whenProxyThrowsUncheckedException_thenShouldBeThrownAsIs() {
|
||||
ClassLoader classLoader = getClass().getClassLoader();
|
||||
InvocationHandler invocationHandler = new ExceptionalInvocationHandler();
|
||||
List<String> proxy = (List<String>) Proxy.newProxyInstance(classLoader, new Class[] { List.class }, invocationHandler);
|
||||
|
||||
assertThatThrownBy(proxy::isEmpty).isInstanceOf(RuntimeException.class);
|
||||
}
|
||||
|
||||
private static class ExceptionalInvocationHandler implements InvocationHandler {
|
||||
|
||||
@Override
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||
if ("size".equals(method.getName())) {
|
||||
throw new SomeCheckedException("Always fails");
|
||||
}
|
||||
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user