1,正确示例
示例中通过注解增强被注解方法功能:数据保存到本地 db 时,同时将该数据封装成统一的消息格式发送到 kafka
1.1 定义注解
package com.demo;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)//方法注解(非构造方法)
@Retention(RetentionPolicy.RUNTIME)//运行时有效
@Inherited//使注解可以被子类继承,但如果子类@Override覆写了被注解方法则无效
public @interface DbInsertAnnotation {
// 无参数
}
1.2 定义切面,并实现增强逻辑
package com.demo;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
@Aspect
@Component
public class DbAspect
{
@Pointcut("execution(@com.demo.DbInsertAnnotation * *(..))")//切面
public void pointcut()
{
}
@Around("pointcut()")
public void around(ProceedingJoinPoint pjp) throws Throwable {
//方法本身功能,写入db
pjp.proceed();
//增强的功能,发送消息到kafka
sendMsg2Kafka(getMessageFromPjp(pjp));
}
private Object getMessageFromPjp(ProceedingJoinPoint pjp) {
//TODO
}
}
1.3 使用注解
package com.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class Demo
{
@Autowired
TestDAO testDAO;
@DbInsert
public void insertDb(Object obj) {
testDAO.insert(obj);
}
}
1.4 调用被注解增强的方法
package com.demo;
import org.springframework.beans.factory.annotation.Autowired;
public class UseDemo
{
@Autowired
Demo demo;
public void call(Object obj) {
demo.insertDb(obj);
}
}
2,一句话说明实现原理
通过注解标记类中的方法,在Spring框架启动时如果发现注入的SpringBean中有该注解,就通过Spring AOP 使用 JDK 动态代理(代理接口时,推荐这种,效率更高)或者 CGLIB(代理class时) 为目标对象创建代理对象,在该对象中方法被调用时实际被调用的是代理对象中对应的方法,而这个代理方法中增加了我们的增强的逻辑,这样通过注解实现方法增强的功能就实现了。
3.错误配置、无效用法及原因说明
3.1 配置有误导致未生效
checkList:
1,是否遗漏了@Aspect@Component两个注解,或者配置的扫描路径未包含
2,@Pointcu定义切面的参数 AOP-execution 表达式是否正确
3,@Around@Before@After的参数 pointcut expression(一般就是简单的函数名加括号)是否正确如
4,果项目中用了以XML配置的SpringMVC就需要在 SpringMVC 的配置文件中开启代理模式:<aop:aspectj-autoproxy expose-proxy="true"></aop:aspectj-autoproxy>
3.2 使用方式错误导致没有调用代理对象的方法
根据2小节原理说明可知,要注解生效关键在于要要调用代理对象的方法,以下情况不能调用到代理对象的方法,所以注解无效
checkList:
1 ,注解在非SpringBean对象方法上时无效(类没有加@Service@Component等注解也没有在XML中配置,使用时不是通过@Autowired@Resource声明而是通过new方法生成的对象)
2,注解在 final 修饰的方法上时无效(CGLIB通过继承实现代理,方法不能被覆写就不能被代理)
2,注解方法在类内部被调用时无效
本文主要参考
https://www.jianshu.com/p/e130b5b73c1b by 泡芙掠夺者
https://bbs.youkuaiyun.com/topics/391049202?page=1
Spring MVC中AOP无效、不起作用,解决方案之一_spring mvc 代理失效-优快云博客 (SpringMVC项目配置)