上一篇中分析了AOP的实现原理,
总结为:
- 判断对象是否需要被代理?@Aspect注解的实现是根据切入点表达式
- 代理之后需要做什么,就是那些通知,本质上是实现了MethodInterceptor的拦截器
- 如何让一个自定义的通知器生效?就是注入一个实现Advisor的bean
我们在使用@Aspect时通常都是使用表达式,基本上都是基于package级别的切,如果我们只想切某些较为分散的方法,这个时候配置表达式的话可能就不太方便啦,那么可以通过自定义注解,在需要的方法上加上这个注解就ok了
根据这些信息,我们可以自己仿写一个类@Aspect的功能
1.注入一个通知器,基于表达式的
@Component
public class MethodCustomAdvisor extends AbstractPointcutAdvisor {
@Override
public Pointcut getPointcut() {
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
//定义切入点表达式
pointcut.setExpression("切入点表达式");
//基于method级别的注解
// AnnotationMatchingPointcut.forMethodAnnotation(MethodCustomAnnotation.class);
//基于class级别的注解
// AnnotationMatchingPointcut.forClassAnnotation(ClazzCustomAnnotation.class);
return pointcut;
}
//绑定某个通知
@Override
public Advice getAdvice() {
return new MethodCustomInterceptor();
}
}
2. 定义一个拦截器(通知),表明这个通知要做什么,这样完全就可以啦
@Slf4j
public class MethodCustomInterceptor implements MethodInterceptor, Serializable {
private Map<Method, Boolean> map = new ConcurrentHashMap<>();
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
log.error("ff========");
//譬如记录日志等等......
return invocation.proceed();
}
}
3.基于注解的实现
基于注解的话,完全就是将上面的表达式的判断部分改为注解的相关判断就可以啦,aop本身提供了方法级别和类级别的注解判断,只要自己定义一个注解写上去就OK啦
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface MethodCustomAnnotation {
String name() default "name";
String value();
}