什么是AOP:aspect oridented programming,面向切面编程,是一种在运行时,动态代理实现对传统编程的补充。
AOP用途:简化代码。面向对象开发时,有很多重复的代码,现在就是通过分层,对代码简化。
通过例子讲述如何使用AOP:
1、添加jar包:
2、添加spring xml文件,在文件中配置,为目标对象生成动态代理对象。如图所示:
3、创建ICalculatorService接口,和实现类CaluculatorService,代码分贝如下:
ICalculatorService代码:
package com.jd.calculator.service;
public interface ICalculatorService {
int mul(int a, int b);
int div(int a, int b);
}
CaluculatorService代码:
package com.jd.calculator.service;
import org.springframework.stereotype.Service;
@Service
public class CalculatorService implements ICalculatorService {
@Override
public int mul(int a, int b) {
return a*b;
}
@Override
public int div(int a, int b) {
return a/b;
}
}
4、创建计算器切面类,CalculatorAspect类
主要运用以下四种注解:@Before @After@AfterReturning@AfterThrowing
代码如下:在代码中详细说明了各个注解的增强作用,以及注解的区别,以及为了简化切入点表达式而新定义的pointcut注解
package com.jd.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Aspect//声明该类是切面类
@Component//声明该类对象存在在Ioc容器中
public class CalculatorAspect {
//用于简化注解:通过观察发现CalculatorAspect类中@Before,@After,@AfterReturning、@AfterThrowing和@Around注解中切入点表达式相同,为了简化代码,可以单独自定义一个@Pointcut注解修饰的空方法,通过该方法可以简化@Before,@After,@AfterReturning、@AfterThrowing和@Around注解中的切入点表达式,
@Pointcut("execution(public int com.jd.calculator.service.CalculatorService.*(int,int))")
public void Pointcut(){
}
//前置增强,目标方法执行前执行
@Before("Pointcut()")
public void befor(JoinPoint jp) {
Object [] arges =jp.getArgs();
// for (Object object : arges) {
// System.out.println(object);
// }
Signature signature =jp.getSignature();
String name = signature.getName();
System.out.println("The "+name+" method begins.");
System.out.println("The "+name+" method rags:["+arges[0]+","+arges[1]+"]");
}
//后置增强,目标方法执行完毕执行
@After("Pointcut()")
public void after(JoinPoint jp) {
Signature signature =jp.getSignature();
String name = signature.getName();
System.out.println("The "+name+" method ends.");
}
//返回增强,目标方法执行return以后执行
//后置增强和返回增强的区别:返回增强比后置增强后执行。如果目标方法出现异常则返回增强不执行
@AfterReturning(value="Pointcut())",returning="result")
public void afterReturning(JoinPoint jp,Object result) {
Signature signature =jp.getSignature();
String name = signature.getName();
System.out.println("Result of the "+name+" method:"+result);
}
//异常增强,目标方法出现异常时执行
@AfterThrowing(value="Pointcut()",throwing="e")
public void afterThrowing(JoinPoint jp,Exception e) {
Signature signature =jp.getSignature();
String name = signature.getName();
System.out.println("Exception of the method "+name+": "+e);
}
}
5、创建test类,用于测试:
test代码如下:
package com.jd.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.jd.calculator.service.ICalculatorService;
public class test {
public static void main(String[] args) {
ClassPathXmlApplicationContext applacation = new ClassPathXmlApplicationContext("app.xml");
ICalculatorService calculatorService = applacation.getBean(ICalculatorService.class);
//System.out.println(calculatorService.div(8, 2));
calculatorService.div(8, 2);
applacation.close();
}
}
执行结果如下:
说明以下几点:
①:返回增强比后置增强后执行。如果目标方法出现异常则返回增强不执行
②:各个增强的执行顺序如注释说写。
将div的分母改为0.测试异常增强是否可以如愿执行。
结果如下:说明如愿执行了。
------------------------------------------------------------------------------------------------------------------------------------
还可以将四种增强通过一个注解来写,就是@Around。
代码如下:
jd.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class CalculatorAspect {
@Pointcut("execution(public int com.jd.calculator.service.CalculatorService.*(int,int))")
public void Pointcut(){
}
//环绕增强:目标方法执行前后都可以织入增强处理
//环绕增强和其他增强的区别:@Before、@After、@AfterRunning和@AfterThrowing修饰的方法没有返回值;而@Around修饰的方法必须有返回值,返回值为目标方法的返回值
@Around("Pointcut()")
public Object around(ProceedingJoinPoint jp) {
Object result = null;
String name = jp.getSignature().getName();
Object [] arges =jp.getArgs();
try {
try {
//前置增强
System.out.println("The "+name+" method begins.");
System.out.println("The "+name+" method rags:["+arges[0]+","+arges[1]+"]");
//执行目标对象内的方法
result = jp.proceed();
}finally {
//后置增强
System.out.println("The "+name+" method ends.");
}
//返回增强
System.out.println("Result of the "+name+" method:"+result);
} catch (Throwable e) {
//异常增强
System.out.println("Exception of the method "+name+": "+e);
}
return result;
}
}
执行结果是一样的,这里就不再赘述。