注:网上搜集的内容,忘记留下出处,见谅
自定义注解
@Target(ElementType.METHOD) //定义是用在方法上
@Retention(RetentionPolicy.RUNTIME) // 定义是在运行时生效
public @interface ZlTest {
String param() default ""; //定义参数,默认为空
}
获取值
- 主要是方法参数多加一个注解类型的参数
/**
* 定义一个切面,用于统计指定注解的方法调用时间
*
* @author zl
* @ProjectName: MapDemo
* @create 2018-12-13 10:08
* @Version: 1.0
* <p>Copyright: Copyright (zl) 2018</p>
**/
@Component
@Aspect
@Slf4j
public class ZlAspect {
@Around("serviceStatistics(zlTest)")
public Object doAround(ProceedingJoinPoint joinPoint, ZlTest zlTest) throws Throwable {
System.out.println("beginning----");
/**
* 获取方法参数值
*/
String key = getKey(zlTest.param(), joinPoint);
log.info("参数是:{}",key);
/**
* 运行doSth(),执行方法的具体业务,并获取返回值,用一个Object类型来接收
*/
Object object = joinPoint.proceed();
/**
* 该方法的后置增强,可以修改返回值
*/
object = 10;
return object;
}
再来一个例子
@Documented//说明该注解将被包含在javadoc中
//@Retention: 定义注解的保留策略,
@Retention(RUNTIME)// 注解会在class字节码文件中存在,在运行时可以通过反射获取到
//@Target:定义注解的作用目标
@Target({METHOD,PARAMETER})// 方法和方法参数
@Inherited//说明子类可以继承父类中的该注解
public @interface LogAnnotation {
/**
* 如果注解只有一个属性,那么肯定是赋值给该属性。
* 如果注解有多个属性,而且前提是这多个属性都有默认值,那么你不写注解名赋值,会赋值给名字为“value”这属性。
* 如果注解有多个属性,其中有没有设置默认值的属性,那么当你不写属性名进行赋值的时候,是会报错的。
*/
//@AliasFor("")起别名
int value() default 000;
}
@Around(value = "LogAnnotation() && webLog() && @annotation(logAnnotation)")//环绕切点,在进入切点前,跟切点后执行
public Object doAround(ProceedingJoinPoint pjp, LogAnnotation logAnnotation)throws Throwable {
Object result = null;
// System.out.println("环绕。。。。。。1"+logAnnotation.value());
//接收到请求,记录请求内容
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
// 记录下请求内容
logger.info("URI : " + request.getRequestURI());
logger.info("URL : " + request.getRequestURL());
logger.info("HTTP_METHOD : " + request.getMethod());
logger.info("IP : " + request.getRemoteAddr());
logger.info("CLASS_METHOD : " + pjp.getSignature().getDeclaringTypeName() + "_" + pjp.getSignature().getName());
logger.info("ARGS : " + Arrays.toString(pjp.getArgs()));
System.out.println("ARGS对象:" + pjp.getArgs()[0]);
}
详细介绍
import java.lang.annotation.*;
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TestAnnotation {
String value(); // 允许注解有参数
}
import com.great.annotation.TestAnnotation;
import com.great.annotation.TestAnnotation;
//import javassist.bytecode.SignatureAttribute;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
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.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
@Aspect // FOR AOP
@Order(-99) // 控制多个Aspect的执行顺序,越小越先执行, 当然也可以不写这注解, 对于写和不写@order的两个切面, 有@order的优先于无@order的执行; 都有@order时, 越小越执先执行
@Component
public class TestAspect {
// @Before可以有两者写法, @annotation(形参test)
@Before("@annotation(test)")
// 拦截被TestAnnotation注解的方法;如果你需要拦截指定package指定规则名称的方法,可以使用表达式execution(...),具体百度一下资料一大堆
// 因为参数传入了TestAnnotation ,所以会自动拦截@TestAnnotation 注解的
public void beforeTest(JoinPoint point, TestAnnotation test) throws Throwable {
System.out.println("beforeTest:" + test.name()); // 直接获取注解参数
}
@After("@annotation(test)")
public void afterTest(JoinPoint point, TestAnnotation test) {
System.out.println("afterTest:" + test.name()); // 直接获取注解参数
}
// 可以控制方法运行, 修改入参和返回值
@Around("@annotation(test)") // test表示aroundTest方法中的test入参
public Object aroundTest(ProceedingJoinPoint pjp, TestAnnotation test) throws Throwable {
System.out.println("afterTest:" + mq.value());
// 获取入参并修改
Object[] args = pjp.getArgs();
args[0] = "";
// 传入修改后的参数, 并继续执行
Object res = pjp.proceed(args);
// 修改返回值
return res.toString() + res.toString();
}
/*
// 指定切面
@Pointcut("@annotation(com.great.annotation.TestAnnotation)")
public void annotationPointCut() {
}
// @Before可以有两者写法, @annotation(函数名annotationPointCut)
@Before("annotationPointCut()")
public void before(JoinPoint joinPoint) {
MethodSignature sign = (MethodSignature) joinPoint.getSignature();
Method method = sign.getMethod();
TestAnnotation annotation = method.getAnnotation(TestAnnotation.class); // 获取指定注解实例
System.out.println("打印:" + annotation.value() + " 前置日志1"); // 获取注解实例的参数
}
@After("annotationPointCut()")
public void afterTTT(JoinPoint point) {
MethodSignature sign = (MethodSignature) point.getSignature();
Method method = sign.getMethod();
TestAnnotation annotation = method.getAnnotation(TestAnnotation.class); // 获取指定注解实例
System.out.println("打印自带参数:" + annotation.value() + " 后置日志1"); // 获取注解实例的参数
}
*/
}
@Around("@annotation(com.xxx.xxx.xxx.SystemLog)")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable{
SystemLog systemLog = ((MethodSignature)joinPoint.getSignature()).getMethod().getAnnotation(SystemLog.class);
......
}