什么是Aop
aop被称为面向切面编程,使用动态代理的方式在执行前后或出现异常后做相关逻辑. aop 是oop的一种延续通过预编译方式和运行时期动态代理实现程序功能的一种技术,利用aop可以对业务逻辑的各个部分进行分离,从而使得业务逻辑部分之间的耦合度降低,提高程序的可重用性,同时提高代码的开发效率。在程序运行期间,不修改源码的对已有的方法进行增强。
SpringAOP五种通知类型
- @Before:在目标方法执行之前,前置通知
- @After:在目标方法的执行之后,后置通知
- @AfterThrowing:在目标方法执行出现异常的时候,异常通知
- @AfterReturning:在目标方法最终执行完毕之后,最终通知
- @Around :环绕通知,能在目标方法的前后,异常最终处都能进行通知操作。
SpringAop的关键词
通知方法:aop五中通知方法所在的类
切面类:通知方法所在的类为切面类
连接点:每一个目标执行方法(需要通知的方法)和每一个通知方法的关系
切入点:我们真正的需要执行日志的地方
切入点表达式或者连接线:通过表达式来确定通知方法通知哪个目标执行方法。
aop案例
- 先导入Maven依赖 或者 jar包
<dependencies>
<!--aop 需要的包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.1.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.13</version>
</dependency>
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
<!--spring 核心包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.0.RELEASE</version>
</dependency>
<!-- 日志包-->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.1</version>
</dependency>
</dependencies>
- 编写目标对象
接口
@Component
public interface Operation
{
// 加法
double add(double i,double j);
// 减法
double subtract(double i,double j);
// 乘法
double mul(double i,double j);
// 除法
double div(double i,double j);
}
实现类
@Component
public class OperationImpl implements Operation
{
@Override
public double add(double i, double j)
{
return i+j;
}
@Override
public double subtract(double i, double j)
{
return i-j;
}
@Override
public double mul(double i, double j)
{
return i*j;
}
@Override
public double div(double i, double j)
{
return i/j;
}
}
- 编写通知
@Aspect //声明该类是一个切面类
@Component
public class OperationProxy
{
// execution切入点表达式 (访问修饰符 返回值类型 目标执行的方法)
@Before("execution(public double com.stone.aopdome.operation.impl.OperationImpl.add(double,double))")
public void logbefore(){
System.out.println("我是前置通知");
}
@After("execution(public double com.stone.aopdome.operation.impl.OperationImpl.add(double,double))")
public void logAfter(){
System.out.println("我是后置通知");
}
@AfterThrowing("execution(public double com.stone.aopdome.operation.impl.OperationImpl.add(double,double))")
public void logException(){
System.out.println("我是异常通知");
}
@AfterReturning("execution(public double com.stone.aopdome.operation.impl.OperationImpl.add(double,double))")
public void logFinal(){
System.out.println("我是最终通知");
}
}
- 编写 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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 扫描com.stone.dome包下的所有注解 -->
<context:component-scan base-package="com.stone.aopdome"/>
<!-- 开启基于注解的aop 功能-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
- 测试
public class SpringAopTest
{
private ApplicationContext ioc = new ClassPathXmlApplicationContext("applicationContext.xml");
@Test
public void testaop1(){
Operation bean = ioc.getBean(Operation.class);
double add = bean.add(12.0, 20.0);
System.out.println(add);
}
}
结果
如何得到目标方法的参数
在通知方法的参数列表中添加JoinPoint,最终通知能得到返回值,异常通知能得到异常
实例代码
@Aspect //声明该类是一个切面类
@Component
public class OperationProxy
{
// execution切入点表达式 (访问修饰符 返回值类型 目标执行的方法)
@Before(value = "execution(public double com.stone.aopdome.operation.impl.OperationImpl.*(double,double))")
public void logbefore(JoinPoint joinPoint){
System.out.println("我是前置通知,目标方法名"+joinPoint.getSignature().getName()+
"\t目标方法的参数个数"+joinPoint.getArgs().length+
"\t参数列表 "+ Arrays.asList(joinPoint.getArgs())
);
}
@After("execution(public double com.stone.aopdome.operation.impl.OperationImpl.*(double,double))")
public void logAfter(JoinPoint joinPoint){
System.out.println("我是后置通知,目标方法名"+joinPoint.getSignature().getName()+
"\t目标方法的参数个数"+joinPoint.getArgs().length+
"\t参数列表 "+ Arrays.asList(joinPoint.getArgs())
);
}
@AfterThrowing(value = "execution(public double com.stone.aopdome.operation.impl.OperationImpl.*(double,double))",throwing = "e")
public void logException(JoinPoint joinPoint,Exception e){
System.out.println("我是异常通知,目标方法名"+joinPoint.getSignature().getName()+
"\t目标方法的参数个数"+joinPoint.getArgs().length+
"\t参数列表 "+ Arrays.asList(joinPoint.getArgs())+
"\t目标异常 "+e
);
}
@AfterReturning(value = "execution(public double com.stone.aopdome.operation.impl.OperationImpl.*(double,double))",returning = "result")
public void logFinal(JoinPoint joinPoint,Object result){
System.out.println("我是最置通知,目标方法名"+joinPoint.getSignature().getName()+
"\t目标方法的参数个数"+joinPoint.getArgs().length+
"\t参数列表 "+ Arrays.asList(joinPoint.getArgs())+
"\t目标方法的返回值"+result
);
}
}
测试代码
@Test
public void testaop1(){
Operation bean = ioc.getBean(Operation.class);
double add = bean.add(12.0, 20.0);
// System.out.println(1/0 );
System.out.println(add);
}
运行结果