这里用比较原生的方式实现比较利于学习和理解AOP。
1、环境准备
创建一个maven工程并导入以下依赖
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<!-- Spring AOP + AspectJ by yinxin -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>3.0.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>3.0.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.6.11</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.11</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.1_3</version>
</dependency>
<!-- end -->
</dependencies>
2、spring的xml配置文件将aop的代理对象和被代理对象注入ioc容器。
如图:
name:applicationContext-aop.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<!-- 使 AspectJ 的注解起作用 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
<bean id="personServiceBean" class="com.yinxin.aop.AopTest.impl.personServerImpl"/>
<bean id="myInterceptor" class="com.yinxin.aop.AopTest.AspectIntercepter"/>
</beans>
2、代码实现
自定义注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Log {
String value() default "";
}
被代理类
//接口(按规范来)
public interface personServer {
void save(String name,int age);
}
//实现接口的类
import com.yinxin.aop.AopTest.annotation.Log;
import com.yinxin.aop.AopTest.personServer;
public class personServerImpl implements personServer {
@Log
@Override
public void save(String name, int age) {
int a=0;
// age = age/a;//打开上面两行报错可触发异常通知
System.err.println("come in personServerImpl save method...");
}
}
代理类
package com.yinxin.aop.AopTest;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import java.util.Arrays;
@Aspect//声明这是一个切面
@Component//声明这是一个组件,泛指...可以去掉
public class AspectIntercepter {
// @Pointcut(value="execution(* com.yinxin.aop.AopTest.impl.personServerImpl.*(..))")//exec表达式方式
@Pointcut(value="@annotation(com.yinxin.aop.AopTest.annotation.Log)")//注解方式
private void pointCut(){//定义一个切入点 后面的通知直接引入切入点方法pointCut即可personServerImpl下面的所有方法
}
//环绕通知(连接到切入点开始执行,下一步进入前置通知,在下一步才是执行操作方法)
@Around(value="pointCut()")
public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable{
System.out.println("@Around进入环绕通知...");
Object object = pjp.proceed();//执行该方法
System.out.println(pjp.getThis()+"方法操作结束,退出方法;环绕[@Around]结束!...");
return object;
}
//前置通知(进入环绕后执行,下一步执行方法)
@Before(value="pointCut()")
public void doAccessCheck(JoinPoint joinPoint){
System.out.println("@Before前置通知:"+ Arrays.toString(joinPoint.getArgs()));
/*System.out.println(joinPoint);
System.out.println(joinPoint.getKind());
System.out.println(joinPoint.getThis());
MethodSignature signature = (MethodSignature) joinPoint.getSignature();//获取signature 该注解作用在方法上,强转为 MethodSignature
System.out.println("signature.getMethod() = " + signature.getMethod());
System.out.println("signature.getName() = " + signature.getName());
System.out.println("signature.getParameterNames() = " + signature.getParameterNames());
System.out.println("signature.getReturnType() = " + signature.getReturnType());
System.out.println(joinPoint.getSourceLocation());
System.out.println(joinPoint.getClass());
System.out.println(joinPoint.getStaticPart());
System.out.println(joinPoint.getTarget());*/
}
//异常通知(出错时执行)
// @AfterThrowing(value="pointCut()",throwing="ex")
public void doAfterThrow(JoinPoint joinPoint,Throwable ex){
System.out.println("@AfterThrowing例外通知(异常通知)"+Arrays.toString(joinPoint.getArgs()));
System.out.println("@AfterThrowing异常信息:"+ex);
}
//后置通知(返回之前执行)
@After(value="pointCut()")
public void after(){
System.out.println("@After后置通知...");
}
//最终通知(正常返回通知,最后执行)
// @AfterReturning(value="pointCut()")
public void doAfter(){
System.out.println("@AfterReturning最终通知...End!");
}
}
注解(加这个注解的方法都会被aop实现方法增强)
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Log {
String value() default "";
}
测试类(注意这里用了两种方式实现了方法增强,修改获取切点的表达式方法完成两种方式的切换)
import com.yinxin.aop.AopTest.personServer;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author yinxin
* @version 1.0
* @Description:
* @date 2022/3/1016:34
*/
public class test {
@Test
public void inteceptorTest(){
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext-aop.xml");
personServer bean = (personServer)ctx.getBean("personServiceBean");
bean.save("badMonkey",23);
// personServer p = new personServerImpl();//通过new对象是不会触发aop的
// p.save("11", "22");
}
}