概念
面向切面编程:把逻辑代码和处理琐碎事务的代码分离开,以便能够分离复杂度。
切面(AOP)术语
- 连接点(Joinpoint)
- 切点(Pointcut)
- 增强(Advice)
- Before advice
- After returning advice
- After throwing advice
- After(finally) advice
- Around advice
- 目标对象(Target)
- 引入(Introduction)
- 织入(Weaving)
- 代理(Proxy)
- 切面(Aspect)
优点
更清晰的代码逻辑,业务逻辑只关注自己本身,不用去管琐碎的事情,比如:安全,日志,事务等等。
可以减少代码量
切面配置
切面应用:日志
注解定义
package com.aspect.annotation;
import java.lang.annotation.*;
({ElementType.METHOD})
(RetentionPolicy.RUNTIME)
public ControllerLog {
String description() default "";
切面定义
package com.aspect.aspect;
import com.aspect.annotation.ControllerLog;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
public class SystemLogAspect {
("@annotation(com.aspect.annotation.ControllerLog)")
public void controllerAspect(){
("controllerAspect()")
public void doBefore(JoinPoint joinPoint){
System.out.println("------defore------");
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String ip = request.getRemoteAddr();
String targetName = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
Object[] arguments = joinPoint.getArgs();
Class targetClass = null;
try {
targetClass = Class.forName(targetName);
} catch (ClassNotFoundException e) {
e.printStackTrace();
Method[] methods = targetClass.getMethods();
String description = "";
for (Method method : methods) {
if (method.getName().equals(methodName)) {
Class[] clazzs = method.getParameterTypes();
if (clazzs.length == arguments.length) {
description = method.getAnnotation(ControllerLog.class).description();
break;
System.out.println(ip+" | "+description);
("@annotation(com.aspect.annotation.ControllerLog)")
public void deAfter(JoinPoint joinPoint){
System.out.println("------after------");
使用切面注解
("/hello")
public class TestServlet {
(value = "/user",method = RequestMethod.GET,produces = "application/json;charset=utf-8")
(description = "welcome user")
public String getMessage(@RequestParam("name") String value){
System.out.println(value);
String output="Hello "+value;
return output;
测试结果
------defore------
0:0:0:0:0:0:0:1 | welcome user
------after------
切面应用:计算方法调用耗时
注解定义
package com.aspect.annotation;
import java.lang.annotation.*;
({ElementType.METHOD})
(RetentionPolicy.RUNTIME)
public ExecuteTimeAnnotation {
切面定义
package com.aspect.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;
public class ExecuteTimeLogAspect {
("@annotation(com.aspect.annotation.ExecuteTimeAnnotation)")
public void executeTimeAspect(){
(value = "executeTimeAspect()")
public Object executeTime(ProceedingJoinPoint joinPoint) throws Throwable {
Signature signature=joinPoint.getSignature();
MethodSignature methodSignature=(MethodSignature)signature;
StopWatch stopWatch=new StopWatch(String.format("方法名: %s",methodSignature.getName()));
System.out.println("StopWatch start");
stopWatch.start();
Object ret=joinPoint.proceed();
stopWatch.stop();
System.out.println(stopWatch.toString());
return ret;
使用切面注解
("/hello")
public class TestServlet {
(value = "/user",method = RequestMethod.GET,produces = "application/json;charset=utf-8")
public String getMessage(@RequestParam("name") String value){
System.out.println(value);
String output="Hello "+value;
return output;
测试结果
StopWatch start
StopWatch '方法名: getMessage': running time (millis) = 14; [] took 14 = 100%
注意点:
当同时以上两个切面时,输出结果为
StopWatch start
------defore------
0:0:0:0:0:0:0:1 | welcome user
------after------
StopWatch '方法名: getMessage': running time (millis) = 12; [] took 12 = 100%
可以发现以@Around的joinPoint.proceed();为分界,进入该方法时调用@Before,退出该方法时调用@After。