AOP 面向切面编程
适用场景:日志记录、执行前后拦截等
步骤
0. 引入相关依赖
1. 编写实际业务方法
2. 编写切面类
2.1 定义连接点
2.2 使用通知
3. 调用业务方法
0. 依赖
<dependencies>
<!-- test -->
<dependency>
<groupid>junit</groupid>
<artifactid>junit</artifactid>
<scope>test</scope>
</dependency>
<dependency>
<groupid>org.springframework</groupid>
<artifactid>spring-test</artifactid>
<scope>test</scope>
</dependency>
<dependency>
<groupid>ch.qos.logback</groupid>
<artifactid>logback-classic</artifactid>
</dependency>
<dependency>
<groupid>org.slf4j</groupid>
<artifactid>jcl-over-slf4j</artifactid>
</dependency>
<dependency>
<groupid>org.springframework</groupid>
<artifactid>spring-core</artifactid>
<exclusions>
<exclusion>
<groupid>commons-logging</groupid>
<artifactid>commons-logging</artifactid>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupid>org.springframework</groupid>
<artifactid>spring-context</artifactid>
</dependency>
<dependency>
<groupid>org.aspectj</groupid>
<artifactid>aspectjrt</artifactid>
</dependency>
<dependency>
<groupid>org.aspectj</groupid>
<artifactid>aspectjweaver</artifactid>
</dependency>
</dependencies>
版本自行去找最新版
配置:
Spring:
<?xml version="1.0" encoding="UTF-8"?>
<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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component -scan base-package="com.youthlin.demo"></context:component>
<!-- aop -->
<aop:aspectj -autoproxy></aop:aspectj>
</beans>
Logback:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<!-- https://logback.qos.ch/manual/layouts.html#coloring -->
<pattern>
%d{yyyy-MM-dd HH:mm:ss.SSS} %highlight(%-5level) [%15.15t]%X{sessionId} %cyan(%-40.40logger{39}) : %m%n
</pattern>
</encoder>
</appender>
<logger name="org" level="warn"></logger>
<root level="${log.level:-debug}">
<appender -ref ref="STDOUT"></appender>
</root>
</configuration>
1. 业务方法
在这个类写实际的业务方法。
package com.youthlin.demo.service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
/**
* 创建者: youthlin.chen 日期: 17-3-26.
*/
@Service
public class HelloService {
private static final Logger LOGGER = LoggerFactory.getLogger(HelloService.class);
@SuppressWarnings("SameParameterValue")
public String sayHello(String name) {
LOGGER.debug("in say hello method");
return "Hello, " + name;
}
public void voidFun() {
LOGGER.debug("void method.");
throw new RuntimeException("");
}
}
2. 切面通知
在这个类定义要拦截的方法及拦截的操作。
package com.youthlin.demo.aop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;
import java.util.Arrays;
/**
* 创建者: youthlin.chen 日期: 17-3-26.
*/
@Aspect//声明切面
@Component//让 Spring 扫描到
public class LogAop {
private static final Logger LOGGER = LoggerFactory.getLogger(LogAop.class);
@SuppressWarnings("unused")
@Pointcut(value = "execution(* com.youthlin.demo.service.*.*(..))")//定义连接点
private void pointcut() {
}
@Around("pointcut()")//环绕通知
public Object processTx(ProceedingJoinPoint pjp) throws Throwable {
LOGGER.debug("环绕通知 之前");
StopWatch stopWatch = new StopWatch();
stopWatch.start();
Object proceed = pjp.proceed();
stopWatch.stop();
LOGGER.debug("环绕通知 之后. {}ms", stopWatch.getTotalTimeMillis());
return proceed;
}
@Before("pointcut()")//前置通知
public void before(JoinPoint jp) {
Object[] args = jp.getArgs();
LOGGER.debug("前置通知 {} args = {}", jp.getSignature(), Arrays.toString(args));
}
@AfterReturning(pointcut = "pointcut()", returning = "result")//后置返回通知
public void afterReturning(Object result) {
LOGGER.debug("后置返回通知 result = {}", result);
}
@AfterThrowing(pointcut = "pointcut()", throwing = "throwable")//后置异常通知
public void afterThrowing(Throwable throwable) {
LOGGER.debug("后置异常通知", throwable);
}
@After("pointcut()")//后置通知
public void after() {
LOGGER.debug("后置通知");
}
}
3. 测试
package com.youthlin.demo.test;
import com.youthlin.demo.service.HelloService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.annotation.Resource;
/**
* 创建者: youthlin.chen 日期: 17-3-26.
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:/app.xml"})
public class AopTest {
private static final Logger LOGGER = LoggerFactory.getLogger(AopTest.class);
@Resource
private HelloService service;
@Test
public void logTest() {
LOGGER.debug("{}", service.sayHello("Lin"));
}
@Test(expected = RuntimeException.class)
public void aVoid() {
service.voidFun();
}
}
测试结果:
2017-03-26 20:40:56.063 DEBUG [ main] com.youthlin.demo.aop.LogAop : 环绕通知 之前 2017-03-26 20:40:56.073 DEBUG [ main] com.youthlin.demo.aop.LogAop : 前置通知 void com.youthlin.demo.service.HelloService.voidFun() args = [] 2017-03-26 20:40:56.134 DEBUG [ main] com.youthlin.demo.service.HelloService : void method. 2017-03-26 20:40:56.135 DEBUG [ main] com.youthlin.demo.aop.LogAop : 后置通知 2017-03-26 20:40:56.138 DEBUG [ main] com.youthlin.demo.aop.LogAop : 后置异常通知 java.lang.RuntimeException: at com.youthlin.demo.service.HelloService.voidFun(HelloService.java:22) at com.youthlin.demo.service.HelloService$$FastClassBySpringCGLIB$$8a47ffe4.invoke(<generated>) at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:721) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:52) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:85) at com.youthlin.demo.aop.LogAop.processTx(LogAop.java:37) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:629) at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:618) at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:70) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.aop.aspectj.AspectJAfterAdvice.invoke(AspectJAfterAdvice.java:47) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) 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:62) 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:656) at com.youthlin.demo.service.HelloService$$EnhancerBySpringCGLIB$$340752f6.voidFun(<generated>) at com.youthlin.demo.test.AopTest.aVoid(AopTest.java:30) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) at org.junit.internal.runners.statements.ExpectException.evaluate(ExpectException.java:19) at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75) at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86) at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:252) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191) at org.junit.runner.JUnitCore.run(JUnitCore.java:137) at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68) at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:51) at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:237) at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70) 2017-03-26 20:40:56.151 DEBUG [ main] com.youthlin.demo.aop.LogAop : 环绕通知 之前 2017-03-26 20:40:56.151 DEBUG [ main] com.youthlin.demo.aop.LogAop : 前置通知 String com.youthlin.demo.service.HelloService.sayHello(String) args = [Lin] 2017-03-26 20:40:56.151 DEBUG [ main] com.youthlin.demo.service.HelloService : in say hello method 2017-03-26 20:40:56.158 DEBUG [ main] com.youthlin.demo.aop.LogAop : 环绕通知 之后. 0ms 2017-03-26 20:40:56.158 DEBUG [ main] com.youthlin.demo.aop.LogAop : 后置通知 2017-03-26 20:40:56.158 DEBUG [ main] com.youthlin.demo.aop.LogAop : 后置返回通知 result = Hello, Lin 2017-03-26 20:40:56.158 DEBUG [ main] com.youthlin.demo.test.AopTest : Hello, Lin

完整代码:https://github.com/YouthLin/examples/tree/master/example-aop
声明
- 本作品采用署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。除非特别注明, 霖博客文章均为原创。
- 转载请保留本文(《Spring AOP 小例子》)链接地址: https://youthlin.com/?p=1431
- 订阅本站:https://youthlin.com/feed/