本文使用注解进行spring AOP的实现。
1.AOP的基本概念
(1)Aspect(切面):通常是一个类,里面可以定义切入点和通知
(2)JointPoint(连接点):程序执行过程中明确的点,一般是方法的调用
(3)Advice(通知):AOP在特定的切入点上执行的增强处理,有before,after,afterReturning,afterThrowing,around
(4)Pointcut(切入点):就是带有通知的连接点,在程序中主要体现为书写切入点表达式
2.用到的注解
1.@Aspect 注解位置为类,声明切面。
2.@PointCut 声明切点,支持俩种类型,一种是execution表达式,一种是注解形式的。
execution表达式:
execution(* com.test.aspect.service.*.*(..)) 第一个* 代表的是所有返回值类型,第二个*代表的是包下所有的类,第三个*代表的是类下所有的方法,()里的..代表的是所有参数类型
注解:
@annotation(com.test.aspect.LogOperate)
3.@Around 环绕增强
4.@Before 前置增强
5.@After 后置增强
6.@AfterThrowing 异常增强
3.具体实现
1.日志一般使用的是注解类型的切点表达式,我们先创建一个日志注解,当spring容器扫描到有此注解的方法就会进行增强。
@Inherited
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface LogOperate {
}
2.切点声明:
@Component //声明为组件,可有容器管理
@Aspect
public class LogAdvice {
@Pointcut("@annotation(com.test.aspect.LogOperate)") //切点
public void log(){
}
@Around(value = "log()") //环绕增强,切点为log这个切点
public void around(ProceedingJoinPoint point) throws Throwable { //这里使用参数为ProceedingJoinPoint 类型,只有环绕增强可以使用,并且在方法中必须执行proceed方法,否则被增强的方法不会执行
System.out.println("around exec");
point.proceed();
}
@Before(value = "log()") //除了环绕增强,其他使用的是joinPoint 类型
public void before(JoinPoint point) throws Throwable {
System.out.println("before exec");
}
@After(value = "log()")
public void after(JoinPoint point) throws Throwable {
System.out.println("after exec");
}
@AfterThrowing("log()")
public void afterThrowing(JoinPoint point){
System.out.println("after throw");
}
3.声明一个使用注解的类
public class Service {
@LogOperate
public void operate(){
System.out.println("operate exec");
}
}
4.Java配置类
@Configuration
@ComponentScan(basePackages = "com.test.aspect")
@EnableAspectJAutoProxy //开启对AOP的支持,在springboot里无需此注解
public class Config {
@Bean
public Service service(){
return new Service();
}
}
5.Java测试类:
public class Main {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
Service bean = context.getBean(Service.class);
bean.operate();
}
}
/*结果:
around exec
before exec
operate exec
after exec */
6.出现的问题:
通过反射获取方法参数名会出现错误,不是原来的参数名,而是arg1,arg2....,解决方法是在 pom的编译插件中添加一个参数:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
</configuration>
</plugin>
这样就可以获取到正常对的参数名了