Spring : @Aspect 切面的几种方式
1、@Aspect 注解方式
直接使用 @Aspect 注解方式,切面的功能都在这个类每个方法中,如下所示:
@Aspect
@Configuration
@ComponentScan(basePackages = {"com.gwm.spring.aopproxy","com.gwm.spring.interceptor"})
@EnableAspectJAutoProxy // 点击进入查看实现原理
public class JavAspect {
@Pointcut("execution(* com.gwm.spring.aopproxy..*.*(..))")
public void pointcutGwm() {}
@Before(value = "pointcutGwm()")
public void beforeTest(JoinPoint joinPoint) {
System.out.println("beforeTest log info ===================");
}
/**
* 在方法[结束]之后(也就是return语句执行完了之后结束了整个方法调用栈)开始执行这个 after , 比 @AfterReturning 注解后执行!
*/
@After(value = "pointcutGwm()")
public void afterTest(JoinPoint joinPoint) {
System.out.println("afterTest log info===================");
}
@Around(value = "pointcutGwm()")
public void aroundTest(ProceedingJoinPoint joinpoint) {
System.out.println("aroundTest start log info= 在这里看试下能不能获取到方法上的注解==================");
/**
* 可以直接从 MethodInvocation 获取到值,前提是不是多线程情况下
* 因为这里是从 ThreadLocal 中获取的值
* ExposeInvocationInterceptor 这个 Advice 就是做了一件事情,就是把 MethodInvocation 保存到 ThreadLocal 中
*/
MethodInvocation methodInvocation = ExposeInvocationInterceptor.currentInvocation();
System.out.println("methodInvocation.getArguments() = " methodInvocation.getArguments());
/**
* 下面测试下在这里能不能获取到 method 上面的注解之类的修饰
* 答案是获取不到的,因为此时的 method 对象是接口上的 method 对象,不是具体实现类上的 method 对象
* 接口上是没有任何修饰符的,通过 ProxyGenerator 工具类可以获取到 Proxy 代理对象的字节码文件,M4 方法
* 就是加载的接口上的 method 对象,所以可以想办法去获取目标类上的 method,方法有很多
*/
Method method = methodInvocation.getMethod();
DBMasterAnno annotation = method.getAnnotation(DBMasterAnno.class);
System.out.println("此处是接口类上的 method 对象 flag=" method.isAnnotationPresent(DBMasterAnno.class));
/**
* 方法一:拿到目标类之后,通过一下工具类查找具体的 method 对象
*/
Method specificMethod = AopUtils.getMostSpecificMethod(method, joinpoint.getTarget().getClass());
DBMasterAnno annotation1 = specificMethod.getAnnotation(DBMasterAnno.class);
System.out.println("此处才是实现类的 method 对象 flag=" specificMethod.isAnnotationPresent(DBMasterAnno.class));
/**
* 获取到参数名称
*/
String[] parameterNames = new DefaultParameterNameDiscoverer().getParameterNames(method);
System.out.println("parameterNames = " parameterNames);
try {
/**
* 方法二:拿到目标类之后,通过自己遍历找到有注解修饰的 method 对象
*/
Method[] declaredMethods = joinpoint.getTarget().getClass().getDeclaredMethods();
Arrays.asList(declaredMethods).forEach(e->{
if (e.isAnnotationPresent(DBMasterAnno.class)) {
System.out.println("此处才是实现类的 method 对象 flag=" specificMethod.isAnnotationPresent(DBMasterAnno.class));
}
});
} catch (Exception e) {
e.printStackTrace();
}
try {
joinpoint.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
System.out.println("aroundTest end log info===================");
}
/**
* 在方法 return 之就开始执行这个功能!
*/
@AfterReturning(value = "pointcutGwm()",returning = "retVal")
public void afterReturningTest(JoinPoint joinPoint, Object retVal) {
System.out.println("afterReturningTest log info===================" retVal);
Object[] args = joinPoint.getArgs();
System.out.println("args = " args);
}
/**
* 只要发生了异常就会执行此方法
*/
@AfterThrowing(value = "pointcutGwm()", throwing = "e")
public void afterThrowingTest(JoinPoint joinPoint,Throwable e) {
System.out.println("afterThrowingTest error log info===================" e.getMessage());
}
}
在执行时,Spring 会自己根据你配置的 Pointcut 来判断是否需要被代理增强。从而实现了 AOP 切面功能。
2、自定义 Adisor
如果不用 @Aspect 注解的话,也可以通过自定义 Advisor 的方式添加切面,但是自定义 Advisor 有点麻烦就是,它还需要有自己的 Advice、Pointcut,注意要加上 @Component 注解表示交给 Spring 管理,代码如下:
@Component
public class MyAdvisor extends AbstractPointcutAdvisor implements Serializable {
private static final long serialVersionUID = 2669293150219020249L;
@Override
public Advice getAdvice() {
return new MyMethodAdvice();
}
@Override
public Pointcut getPointcut() {
return new MyPointcut();
}
}
需要添加一个自定义的 Advice,因为切面增强逻辑都写在这个 Adivce 中,如下所示:
public class MyMethodAdvice implements MethodInterceptor {
/**
* @desc:
* @author: Gong
* @date: 2022/12/29 17:34
*/
@Nullable
@Override
public Object invoke(@Nonnull MethodInvocation invocation) throws Throwable {
System.out.println("我是 MyMethodAdvice 增强逻辑....");
Object aThis = invocation.getThis();
Method method = invocation.getMethod();
Object[] arguments = invocation.getArguments();
Object invoke = method.invoke(aThis, arguments);
System.out.println("aThis = " aThis);
// Arrays.asList(arguments).forEach(System.out::println);
return invocation.proceed();
// return invoke;
}
}
然后还需要添加一个自定义的 Pointcut,而 Pointcut 是对方法和类过滤进行过滤,判断某个类、和某个类中的方法是否需要被代理,如下所示:
public class MyPointcut implements Pointcut {
@Override
public ClassFilter getClassFilter() {
return new MyClassFilter();
}
@Override
public MethodMatcher getMethodMatcher() {
return new MyMethodMatcher();
}
}
public class MyClassFilter implements ClassFilter {
@Override
public boolean matches(Class<?> clazz) {
return clazz == Apple.class;
}
}
public class MyMethodMatcher implements MethodMatcher {
@Override
public boolean matches(Method method, Class<?> targetClass) {
return method.getName().equals("add");
}
/**
* 控制更细粒度的开关
* @return
*/
@Override
public boolean isRuntime() {
return false;
}
/**
* 可以对参数进行判断做到了更新粒度的切面控制
* @return
*/
@Override
public boolean matches(Method method, Class<?> targetClass, Object... args) {
return false;
}
}
在执行时,Spring 就会收集到你自定义的 Advisor 来做切面逻辑。
3、自定义 Advice
如果你觉得自定义 Advisor 麻烦的话,那可以通过自定义 Advice 的方法方便点,一般自定义的 Advice 实现它的子类接口 MethodInterceptor 即可,如下所示:
/**
* @author: Gong
* @date: 2022/12/30 17:00
* @desc: ...
*/
@Component
public class MyAdvice implements MethodInterceptor {
@Nullable
@Override
public Object invoke(@Nonnull MethodInvocation invocation) throws Throwable {
System.out.println(">>>>>>MyAdvice 增强逻辑...");
return invocation.proceed();
}
}
但是这里还需要定一个 PriorityOrdered 级别的 BeanPostProcessor,因为我们需要把上面的 MyAdvice 添加到切面的逻辑中去。PriorityOrdered 级别是因为自定义的 MyAdviceBeanPostProcessor 一定要比 AnnotationAwareAspectJAutoProxyCreator 先被注册到 Spring 容器 beanPostProcessors 中,这样等你执行 AnnotationAwareAspectJAutoProxyCreator 的 getBean() 时就能够被你自定义的 beanPostProcessors 包装增强。
/**
* @author: Gong
* @date: 2022/12/30 17:01
* @desc: ...
*/
@Component
public class MyAdviceBeanPostProcessor implements BeanPostProcessor, PriorityOrdered {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof AnnotationAwareAspectJAutoProxyCreator) {
AnnotationAwareAspectJAutoProxyCreator aspectJAutoProxyCreator = (AnnotationAwareAspectJAutoProxyCreator) bean;
aspectJAutoProxyCreator.setInterceptorNames("myAdvice");
}
return bean;
}
@Override
public int getOrder() {
return 0;
}
}
同时也要注意次 Advice 也是个全局的拦截器,Pointcut 默认都是 TRUE 不做任何类和方法的拦截过滤。
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanhgjabie
-
photoshop保存的图片太大微信发不了怎么办
PHP中文网 06-15 -
《学习通》视频自动暂停处理方法
HelloWorld317 07-05 -
word里面弄一个表格后上面的标题会跑到下面怎么办
PHP中文网 06-20 -
Android 11 保存文件到外部存储,并分享文件
Luke 10-12 -
photoshop扩展功能面板显示灰色怎么办
PHP中文网 06-14 -
微信公众号没有声音提示怎么办
PHP中文网 03-31 -
excel下划线不显示怎么办
PHP中文网 06-23 -
excel打印预览压线压字怎么办
PHP中文网 06-22 -
TikTok加速器哪个好免费的TK加速器推荐
TK小达人 10-01 -
怎样阻止微信小程序自动打开
PHP中文网 06-13