摘要:我们将看到关于Spring AOP的概念以及如何实现它。

Spring AOP:
面向切面的编程是一种编程范式,类似于面向对象编程.面向对象编程的关键单元是类,类似于AOP的关键单元是切面.切面支持诸如事务管理之类的关注点的模块化,它跨越多个类和类型。它也称为横切关注点。

什么 AOP?

它提供了在业务逻辑之前、之后或周围应用关注点的可插入方法。让我们在日志的帮助下理解。您已经在不同的类中放置了日志记录,但是出于某些原因,如果您现在想删除日志,您必须在所有类中进行更改,但是您可以通过使用方面轻松地解决这个问题。如果你想删除日志,你只需要拔掉那个方面的插头。

AOP 概念:
Aspect:方面是一个实现跨越不同类的关注点的类,比如日志。它只是一个名字.
Joint Point : 它是程序执行的一个点,例如方法的执行。在Spring AOP中,连接点总是表示方法执行。
Advice : 方面在特定连接点上采取的行动例如:在执行getEmployeeName()方法之前,put日志。这里,我们在建议之前使用。
Pointcut : 切入点是决定在匹配的连接点上执行建议的表达式。Spring默认使用AspectJ切入点表达式语言。
Target object : 这些是应用建议的对象。例如:有一个对象,您希望在连接点上应用日志记录。
AOP proxy : Spring将创建JDK动态代理,以便通过建议调用围绕目标对象创建代理类。
Weaving : 从目标对象创建代理对象的过程可以称为编织。
Types of Advices :建议是由方面在特定的连接点上采取的行动。
Before Advice: 它在连接点之前执行
After Returning Advice:它在一个关节点完成后执行,没有任何异常.
After Throwing Advice:如果方法通过抛出异常来执行.
After Advice: 它在一个连接点之后执行,而不考虑结果.

Around Advice:它在连接点之前和之后执行.

Spring AOP AspectJ Annotation Example

在这篇文章中,我们将看到Spring AOP AspectJ注释示例。

下面是AspectJ注释,我们将使用它来实现Spring AOP。

@Aspect :要声明一个类作为方面,用于创建通知的注释是:
@Before : @Before注解被用来创建前置通知.它在实际的方法执行之前执行(连接点)。
@AfterReturning: 这个注释用于创建返回通知.它在一个方法执行完成后执行,没有任何异常。
@AfterThrowing: 这个注释用于在抛出通知之后创建.如果方法通过抛出一个异常来执行。
@After : 这个注释用于在通知之后创建.它在方法执行之后执行,而不考虑结果。

@Around : 这个注释用于创建环绕通知.它在连接点之前和之后执行。

项目结构:

Spring AOP介绍和实战_aop注入

@Before  :

比方说你有一些业务逻辑类(BusinessLogic.java),你想在这个类的getBusinessLogic方法执行之前做日志记录

package com.micai.spring.aop;

/**
* 描述:
* <p>
*
* @author: 赵新国
* @date: 2018/6/11 17:30
*/
public class BusinessLogic {

public void getBusinessLogic() {
System.out.println("*****************");
System.out.println("In Business Logic method");
System.out.println("*****************");
}
}

现在我们将创建aspect类

package com.micai.spring.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

/**
* 描述:
* <p>
*
* @author: 赵新国
* @date: 2018/6/11 17:31
*/
@Aspect
public class LoggingAspect {

@Before("execution(* com.micai.spring.aop.BusinessLogic.getBusinessLogic(..))")
public void loggingBeforeBusinessLogic(JoinPoint joinPoint) {
System.out.println("loggingBeforeBusinessLogic() is running!");
System.out.println("Before execution of method : " + joinPoint.getSignature().getName());
}
}

execution(* com.micai.spring.aop.BusinessLogic.getBusinessLogic(。。))是切入点表达式。


在BusinessLogic类的getBusinessLogic方法之前,它表示方法的执行。

让我们在applicationContext.xml中对上述bean进行配置。

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd ">

<aop:aspectj-autoproxy />

<bean id="businessLogic" class="com.micai.spring.aop.BusinessLogic"></bean>

<!-- Aspect -->
<bean id="logAspect" class="com.micai.spring.aop.LoggingAspect"/>


</beans>

创建名为SpringAOPMain的主类来执行应用程序

package com.micai.spring;

import com.micai.spring.aop.BusinessLogic;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
* 描述:
* <p>
*
* @author: 赵新国
* @date: 2018/6/11 17:34
*/
public class SpringAOPMain {

public static void main(String [] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
BusinessLogic businessLogic = (BusinessLogic) applicationContext.getBean("businessLogic");
businessLogic.getBusinessLogic();

}
}

当您运行在程序之上时,您将得到以下输出:

log4j:WARN No appenders could be found for logger (org.springframework.core.env.StandardEnvironment).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
loggingBeforeBusinessLogic() is running!
Before execution of method : getBusinessLogic
*****************
In Business Logic method
*****************

Process finished with exit code 0

@After:

我在LoggingAspect中替换@before方法。带有@after注释的java方法。该方法将在实际业务逻辑执行后执行,因此要执行LoggingAspect。java看起来是这样的。

package com.micai.spring.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

/**
* 描述:
* <p>
*
* @author: 赵新国
* @date: 2018/6/11 17:31
*/
@Aspect
public class LoggingAspect {

@After("execution(* com.micai.spring.aop.BusinessLogic.getBusinessLogic(..))")
public void loggingBeforeBusinessLogic(JoinPoint joinPoint) {
System.out.println("loggingAfterBusinessLogic() is running!");
System.out.println("After execution of method : " + joinPoint.getSignature().getName());
}
}

当您运行SpringAOPMain。再一次,你将会得到低于输出:

log4j:WARN No appenders could be found for logger (org.springframework.core.env.StandardEnvironment).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
*****************
In Business Logic method
*****************
loggingAfterBusinessLogic() is running!
After execution of method : getBusinessLogic

Process finished with exit code 0

正如您在上面的输出中看到的,在getBusinessLogic方法之后执行的loggingAfterBusinessLogic方法

@AfterReturning:
我将@after替换为@AfterReturning在以上的LoggingAspect.java。这种方法将在实际业务逻辑的执行之后执行,但前提是它成功返回。

package com.micai.spring.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

/**
* 描述:
* <p>
*
* @author: 赵新国
* @date: 2018/6/11 17:31
*/
@Aspect
public class LoggingAspect {

@AfterReturning("execution(* com.micai.spring.aop.BusinessLogic.getBusinessLogic(..))")
public void loggingBeforeBusinessLogic(JoinPoint joinPoint) {
System.out.println("loggingAfterReturningBusinessLogic() is running!");
System.out.println("AfterReturning execution of method : " + joinPoint.getSignature().getName());
}
}

当您运行SpringAOPMain。再一次,你将会得到低于输出:

log4j:WARN No appenders could be found for logger (org.springframework.core.env.StandardEnvironment).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
*****************
In Business Logic method
*****************
loggingAfterReturningBusinessLogic() is running!
AfterReturning execution of method : getBusinessLogic

Process finished with exit code 0

@AfterThrowing:

我们再添加一个方法@AfterThrowing 注解. 如果在getBusinessLogic方法中发生任何异常,它将执行。


LoggingAspect.java

package com.micai.spring.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;

/**
* 描述:
* <p>
*
* @author: 赵新国
* @date: 2018/6/11 17:31
*/
@Aspect
public class LoggingAspect {

@AfterReturning("execution(* com.micai.spring.aop.BusinessLogic.getBusinessLogic(..))")
public void loggingBeforeBusinessLogic(JoinPoint joinPoint) {
System.out.println("loggingAfterReturningBusinessLogic() is running!");
System.out.println("AfterReturning execution of method : " + joinPoint.getSignature().getName());
}

@AfterThrowing("execution(* com.micai.spring.aop.BusinessLogic.getBusinessLogic(..))")
public void loggingAfterBusinessLogicException(JoinPoint joinPoint) {
System.out.println("Exception occurred in getBusinessLogic method");
}
}

现在,从getBusinessLogic抛出RuntimeException来测试@after抛出异常。BusinessLogic.java

package com.micai.spring.aop;

/**
* 描述:
* <p>
*
* @author: 赵新国
* @date: 2018/6/11 17:30
*/
public class BusinessLogic {

public void getBusinessLogic() {
System.out.println("*****************");
System.out.println("In Business Logic method");
System.out.println("*****************");
throw new RuntimeException();
}
}

当您运行SpringAOPMain。java,您将得到以下输出:

log4j:WARN No appenders could be found for logger (org.springframework.core.env.StandardEnvironment).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
Exception in thread "main" java.lang.RuntimeException
at com.micai.spring.aop.BusinessLogic.getBusinessLogic(BusinessLogic.java:16)
at com.micai.spring.aop.BusinessLogic$$FastClassBySpringCGLIB$$776ce13d.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:717)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor.invoke(AfterReturningAdviceInterceptor.java:52)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:58)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:653)
*****************
In Business Logic method
*****************
Exception occurred in getBusinessLogic method
at com.micai.spring.aop.BusinessLogic$$EnhancerBySpringCGLIB$$9a54a68e.getBusinessLogic(<generated>)
at com.micai.spring.SpringAOPMain.main(SpringAOPMain.java:19)

Process finished with exit code 1

正如您所看到的,loggingAfterBusinessLogicException被执行,因为在业务逻辑中有例外。

@Around:

@Around的方法将在业务逻辑执行之前和之后被调用,你需要调用进程的引用和调用继续方法来执行实际的业务逻辑

package com.micai.spring.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;

/**
* 描述:
* <p>
*
* @author: 赵新国
* @date: 2018/6/11 17:31
*/
@Aspect
public class LoggingAspect {

@Around("execution(* com.micai.spring.aop.BusinessLogic.getBusinessLogic(..))")
public void loggingAroundBusinessLogic(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("Before calling actual business logic"); // 在运行实际的业务逻辑之前
joinPoint.proceed(); // 业务逻辑方法被执行
System.out.println("After calling actual business logic"); // 在运行实际业务逻辑之后
}


}

当您运行SpringAOPMain。java,您将得到以下输出:

log4j:WARN No appenders could be found for logger (org.springframework.core.env.StandardEnvironment).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
Before calling actual business logic
*****************
In Business Logic method
*****************
After calling actual business logic

Process finished with exit code 0