Aspectj注解实现AOP
1、添加jar类库
2.在spring配置文件中添加如下代码
<context:component-scan base-package="com.jd"></context:component-scan>
<bean class="com.jd.calculator.CalculatorService"></bean>
<aop:aspectj-autoproxy proxy-target-class="false"></aop:aspectj-autoproxy>
第一行是扫描自定义的包,这次所有与测试相关的类都在com.jd中
第二行是创建一个自定义的类的bean放在IOC容器中
第三行解释:如果创建目标对象的目标类中的方法与AspectJ切面中切入点表达式匹配,则自动为该目标对象生成动态代理对象,该代理对象默认使用JDK动态代理,即proxy-target-class="false" ,当为true时为CGLib代理。
3.此次测试代码
①.CalculatorAspect类(设置增强方法)
@Aspect
@Component
public class CalculatorAspect {
@Pointcut("execution(int com.jd.calculator.CalculatorService.*(int,int))")
public void pointcut() {
}
@Before("pointcut()")
public void before(JoinPoint joinpoint) {
Object object = joinpoint.getTarget();//获取目标对象
Object [] args = joinpoint.getArgs();
String name = joinpoint.getSignature().getName();
System.out.println(object.getClass().getName()+":The "+name+" method begins.");
System.out.println(object.getClass().getName()+":Parameters of the "+name+" method: ["+args[0]+","+args[1]+"]");
}
@AfterReturning(value="pointcut()",returning="result")
public void afterReturning(JoinPoint joinPoint,Object result) {
Object object = joinPoint.getTarget();
String name = joinPoint.getSignature().getName();
System.out.println(object.getClass().getName()+":Result of the "+name+" method:"+result);
}
@After("pointcut()")
public void after(JoinPoint joinPoint) {
Object object = joinPoint.getTarget();
String name = joinPoint.getSignature().getName();
System.out.println(object.getClass().getName()+":The "+name+" method ends.");
}
@AfterThrowing(value="pointcut()",throwing="excption")
public void afterThrowing(JoinPoint joinPoint,Exception excption) {
Object object = joinPoint.getTarget();
String name = joinPoint.getSignature().getName();
System.out.println(object.getClass().getName()+":Exception of the method "+name+": "+excption);
}
}
②.CalculatorService类
@Component
public class CalculatorService implements ICalculatorService{
@Override
public int mul(int a, int b) {
int result = a*b;
return result;
}
@Override
public int div(int a, int b) {
int result = a/b;
return result;
}
}
③.ICalculatorService接口
public interface ICalculatorService {
int mul(int a, int b);
int div(int a, int b);
}
④.Test类
public class Test {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("app.xml");
ICalculatorService calculatorService = context.getBean(ICalculatorService.class);
int result = calculatorService.div(1, 1);
System.out.println(result);
context.close();
}
}
4.分析增强的执行过程
执行Test类中的main方法发现执行结果如下
我们故意设置一个错误(在service类中)
@Override
public int div(int a, int b){
int result = a/b;
if(a==0) {
throw new RuntimeException("1111111");
}
return result;
}
执行结果如下
我们将println的输出与增强方法一一对应,我们会发现增强方法的执行过程是加有@Before注解的方法 -->执行增强的目标方法-->@After注解所修饰的方法-->@AfterReturning注解所修饰的方法-->@AfterThrowing注解所修饰的方法
实际上这些方法是这样执行的
@Around
AspectJ一共支持5种类型的增强注解,除了@Before,@After,@AfterReturning和@AfterThrowing以外,还有一种增强注解——@Around,在@Around修饰的方法中可以实现@Before,@After,@AfterReturning和@AfterThrowing增强效果,可以实现动态代理全过程,代码如下:
@Aspect
@Component
public class CalculatorAspect {
@Pointcut("execution(int com.jd.calculator.CalculatorService.*(int,int))")
public void pointcut() {
}
@Around("pointcut()")
public Object around(ProceedingJoinPoint joinPoint) {
Object result=null;
Object object = joinPoint.getTarget();//获取目标对象
Object [] args = joinPoint.getArgs();
String name = joinPoint.getSignature().getName();
try {
try {
//前置增强
System.out.println(object.getClass().getName()+":The "+name+" method begins.");
System.out.println(object.getClass().getName()+":Parameters of the "+name+" method: ["+args[0]+","+args[1]+"]");
result = joinPoint.proceed();
} finally{
System.out.println(object.getClass().getName()+":The "+name+" method ends.");
//后置增强
}
//返回增强
System.out.println(object.getClass().getName()+":Result of the "+name+" method:"+result);
} catch (Throwable e) {
System.out.println(object.getClass().getName()+":Exception of the method "+name+": "+e);
}
return result;
}
}
结果如下
与上面执行结果相同,因此可得出一个结论@Around注解的方法可以代替其他四种增强方法
注意:如果 @AfterThrowing所注解的方法中 异常的类型若与方法中抛出的异常类型不匹配会怎样呢?
相应的方法修改如下
@Override
public int div(int a, int b){
int result = a/b;
if(a==0) {
throw new ArithmeticException("!!!!!!!!!!!!");
}
return result;
}
@AfterThrowing(value="pointcut()",throwing="excption")
public void afterThrowing(JoinPoint joinPoint,NullPointerException excption) {
Object object = joinPoint.getTarget();
String name = joinPoint.getSignature().getName();
System.out.println(object.getClass().getName()+":Exception of the method "+name+": "+excption);
}
运行结果如下
也就是说@AfterThrowing注解的方法并没有起作用。
使用最先提到的四种注解与@Around注解的区别
1.@Before、@After、@AfterRunning和@AfterThrowing修饰的方法可以通过声明JoinPoint 类型参数变量获取目标方法的信息;@Around修饰的方法必须声明ProceedingJoinPoint类型的参数获取目标方法的信息
2.@Before、@After、@AfterRunning和@AfterThrowing修饰的方法没有返回值;而@Around修饰的方法必须有返回值,返回值为目标方法的返回值