添加依赖
<!-- aspectj 方式的AOP,需要加入下面三个包 -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.9</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.9</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>1.8.9</version>
</dependency>
XML启用
Spring上下文创建一个AnnotationAwareAspectJAutoProxyCreator类
<aop:aspectj-autoproxy/>
切入点声明
@AspectJ风格的命名切入点使用org.aspectj.lang.annotation包下的@Pointcut方法(方法必须是返回void类型)实现。
@Pointcut(value="切入点表达式", argNames = "参数名列表")
使用注解
@Pointcut("@annotation(com.apus.dap.hella.common.aspect.annotation.JmxMetrical) || @target(com.apus.dap.hella.common.aspect.annotation.JmxMetrical)")
public void annotationProcessor() {
}
注解类@JmxMetrical
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface JmxMetrical {
String name() default "";
boolean displayArgs() default false;
/**
* 增删改的数据的类型
*/
Class<?> clazz();
}
通知声明
- 前置通知
使用org.aspectj.lang.annotation 包下的@Before注解声明;
@Before(value = "切入点表达式或命名切入点", argNames = "参数列表参数名")
-
环绕通知
像Spring基于XML的AOP一样,@AspectJ注解的使用不仅只限定与定义前置和后置通知类型。我们还可以创建环绕通知,使用环绕通知需要使用@Around。
@Around (
value="切入点表达式或命名切入点",
argNames="参数列表参数名")
使用org.aspectj.lang.annotation 包下的@AfterReturning注解声明;
@AfterReturning(
value="切入点表达式或命名切入点",
pointcut="切入点表达式或命名切入点",
argNames="参数列表参数名",
returning="返回值对应参数名")
使用org.aspectj.lang.annotation 包下的@After注解声明;
@After (
value="切入点表达式或命名切入点",
argNames="参数列表参数名")
使用org.aspectj.lang.annotation 包下的@AfterThrowing注解声明
@AfterThrowing (
value="切入点表达式或命名切入点",
pointcut="切入点表达式或命名切入点",
argNames="参数列表参数名",
throwing="异常对应参数名")
@Aspect
@Component
public class JmxMetricalAOP {
private static final Logger LOG = LoggerFactory.getLogger(JmxMetricalAOP.class);
private static MetricalCounterManager metricalCounterManager;
private static final String POINTCUT_METHOD =
"(execution(public * " + API_PROTOCOL_CLASS_NAME + ".*(..)))";
@PostConstruct
public void init() {
//初始化一个全局度量器管理类
metricalCounterManager = new MetricalCounterManager(Maps.newHashMap());
LOG.info("JmxMetricalAOP.methodAnnotated init:success");
}
@Pointcut("@annotation(com.apus.dap.hella.common.aspect.annotation.JmxMetrical) || @target(com.apus.dap.hella.common.aspect.annotation.JmxMetrical)")
public void annotationProcessor() {
}
@Pointcut(POINTCUT_METHOD)
public void publicMethod() {
LOG.info("JmxMetricalAOP.methodJoinPointed");
}
@Around("publicMethod() && annotationProcessor()")
public Object timedJoinPoint(ProceedingJoinPoint joinPoint) throws Throwable {
Signature signature = joinPoint.getSignature();
Method method = ((MethodSignature) signature).getMethod();
final String methodName = signature.getName();
/**
* 1.获取唯一接口全路径
*/
String fullApiName = getFullApiName(joinPoint, signature, methodName);
if (method.getDeclaringClass().isInterface()) {
method = joinPoint.getTarget().getClass()
.getDeclaredMethod(methodName, method.getParameterTypes());
}
/**
* 2. 方法上的注解优先级比类上的注解高,可以覆盖类上注解的值,获取相关值
*/
//是否注解
Boolean isJmxMetrical = false;
//注解对象名
String jmxMetricalName = null;
//注解对象参数
Object[] jmxMetricalArgs = null;
//注解对象class
Class<? extends JmxMetrical> aClass = null;
JmxMetrical jmxMetrical = null;
//处理方法上的注解
if (method.isAnnotationPresent(JmxMetrical.class)) {
isJmxMetrical = true;
jmxMetrical = method.getAnnotation(JmxMetrical.class);
jmxMetricalName = jmxMetrical.name();
aClass = jmxMetrical.getClass();
if (jmxMetrical.displayArgs()) {
jmxMetricalArgs = joinPoint.getArgs();
}
} else {
//处理类上面的注解
Object target = joinPoint.getTarget();
if (target.getClass().isAnnotationPresent(JmxMetrical.class)) {
isJmxMetrical = true;
jmxMetrical = target.getClass().getAnnotation(JmxMetrical.class);
jmxMetricalName = jmxMetrical.name();
aClass = jmxMetrical.getClass();
if (jmxMetrical.displayArgs()) {
jmxMetricalArgs = joinPoint.getArgs();
}
}
}
/**
* 3. 切入点度量
*/
//切入点方法执行结果
Object result = null;
Boolean thrown = false;
try {
result = joinPoint.proceed();
} catch (Throwable throwable) {
thrown = true;
//如果需要度量
}
//如果不需要度量
if (!isJmxMetrical) {
return result;
}
metricalCounterManager.metricApi(fullApiName, result, thrown);
return result;
}
private String getFullApiName(ProceedingJoinPoint joinPoint, Signature signature,
String methodName) {
//通过包路径方式获取
String[] packageName = signature.getDeclaringTypeName().split("\\.");
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < packageName.length; ++i) {
if (i < packageName.length - 1) {
stringBuilder.append(packageName[i].substring(0, 1));
} else {
stringBuilder.append(packageName[i]);
}
if (i == packageName.length - 1) {
stringBuilder.append(FULL_POINT_SEP);
continue;
}
stringBuilder.append(".");
}
String fullApiName = stringBuilder + signature.getName();
LOG.info("Executing: " + fullApiName);
//通过接口方式获取
// String className = joinPoint.getTarget().getClass().getInterfaces()[0].getName();
// String fullApiName = className + SEP + methodName;
return fullApiName;
}
/**
* 后置异常通知
*/
@AfterThrowing("publicMethod() && annotationProcessor()")
public void demandRefund() {
LOG.info("com.apus.hella.protocol.dto.*#{} exception!!!");
}
public static List<MetricalCounter> getMonitorList() {
List<MetricalCounter> monitor_profiles = getMonitorMap().values().stream()
.collect(Collectors.toList());
return monitor_profiles;
}