Spring AOP技术(基于AspectJ)的Annotation开发

Spring AOP技术(基于AspectJ)的Annotation开发

@(Spring)[aop, spring, xml, Spring, annotation, aspectJ]

Spring AOP的Annotation的开发

Spring的基于AspectJ的AOP的Annotation开发

第一步引入jar包

这里写图片描述

第二步创建配置文件
  • 引入AOP的约束
<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" 
    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.xsd"> 

</beans>
第三步创建需增强包和类
  • 创建接口
package com.pc.aop.dao;

/**
 * 客户持久层接口
 * 
 * @author Switch
 * @data 2016年11月23日
 * @version V1.0
 */
public interface CustomerDao {
    /**
     * 保存用户
     */
    public void save();
}
  • 创建实现类
package com.pc.aop.dao.impl;

import com.pc.aop.dao.CustomerDao;

/**
 * 用户持久层实现类
 * 
 * @author Switch
 * @data 2016年11月23日
 * @version V1.0
 */
public class CustomerDaoImpl implements CustomerDao {
    @Override
    public void save() {
        System.out.println("保存用户了。。。");
    }
}
第四步将类交给Spring管理
<bean id="customerDao" class="com.pc.aop.dao.impl.CustomerDaoImpl" />
第五步编写测试
package com.pc.test;

import javax.annotation.Resource;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.pc.aop.dao.CustomerDao;

/**
 * 面向切面编程测试类
 * 
 * @author Switch
 * @data 2016年11月23日
 * @version V1.0
 */
// 配置Spring单元测试环境
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class SpringAOPTest {
    // 注入依赖
    @Resource(name = "customerDao")
    private CustomerDao customerDao;

    // 测试Spring单元测试集成
    @Test
    public void testSpring() {
        customerDao.save();
    }
}

输出

保存用户了。。。

PS:这时候没用使用AOP进行任何增强

第六步编写切面类和通知
package com.pc.aop.advice;
import org.aspectj.lang.ProceedingJoinPoint;
/**
 * 切面类
 * 
 * @author Switch
 * @data 2016年11月23日
 * @version V1.0
 */
public class MyAspect {
    // 通知:校验权限
    public void check() {
        System.out.println("校验权限。。。。。。");
    }
}
第七步 配置切面类
<!-- 配置切面类 -->
<bean id="myAspect" class="com.pc.aop.advice.MyAspect"/>
第八步开启AOP的自动代理
<!-- 开启AOP注解自动代理 -->
<aop:aspectj-autoproxy/>
第九步通过注解实现AOP
// 配置了自动AOP代理的,需要在类上配置该注解,不然无法被识别为切面
@Aspect
public class MyAspect {
    // 前置通知
    @Before("execution(* com.pc.aop.dao.impl.CustomerDaoImpl.save(..))")
    // 通知:校验权限
    public void check() {
        System.out.println("校验权限。。。。。。");
    }
}
第九步执行测试
package com.pc.test;

import javax.annotation.Resource;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.pc.aop.dao.CustomerDao;

/**
 * 面向切面编程测试类
 * 
 * @author Switch
 * @data 2016年11月23日
 * @version V1.0
 */
// 配置Spring单元测试环境
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class SpringAOPTest {
    // 注入依赖
    @Resource(name = "customerDao")
    private CustomerDao customerDao;

    // 测试Spring单元测试集成
    @Test
    public void testSpring() {
        customerDao.save();
    }
}

输出

校验权限。。。。。。
保存用户了。。。

通知类型

这里写图片描述

PS:因为在XML中已经给出了各个通知的完整测试代码,所以这里只给出通知代码和测试代码及其结果,如果想查看其他代码,请查找《Spring AOP技术(基于AspectJ)的XML开发》

前置通知

前置通知:在目标方法执行之前完成的增强。获得切入点信息。
注解:@Before
PS:接入点信息,其他类型的增强也可以通过这种方法使用。

配置切面和通知
// 配置了自动AOP代理的,需要在类上配置该注解,不然无法被识别为切面
@Aspect
public class MyAspect {
    // 前置通知
    @Before("execution(* com.pc.aop.dao.impl.CustomerDaoImpl.save(..))")
    // 通知:校验权限
    public void check(JoinPoint joinPoint) {
        System.out.println("校验权限。。。。。。");
        // 输出接入点信息
        System.out.println(joinPoint.toString());
    }
}
单元测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class SpringAOPTest {
    // 注入依赖
    @Resource(name = "customerDao")
    private CustomerDao customerDao;
    // 测试前置通知
    @Test
    public void testBefore() {
        customerDao.save();
    }
}

输出

校验权限。。。。。。
execution(void com.pc.aop.dao.CustomerDao.save())
保存用户了。。。
后置通知

后置通知:在目标方法执行之后完成的增强。获得方法的返回值。
注解:@AfterReturning

配置切面和通知
// 配置了自动AOP代理的,需要在类上配置该注解,不然无法被识别为切面
@Aspect
public class MyAspect {
    // 后置通知
    @AfterReturning(value = "execution(* com.pc.aop.dao.impl.CustomerDaoImpl.delete(..))", returning = "retVal")
    // 通知:打印日志
    public void printLog(String retVal) {
        System.out.println("打印日志。。。。。");
        System.out.println("返回值为:" + retVal);
    }
}
单元测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class SpringAOPTest {
    // 注入依赖
    @Resource(name = "customerDao")
    private CustomerDao customerDao;
    // 测试后置通知
    @Test
    public void testAfterRunning() {
        String delete = customerDao.delete();
        System.out.println(delete);
    }
}

输出

删除用户了。。。
打印日志。。。。。
返回值为:delete
delete
环绕通知

环绕通知:在目标方法执行前和执行后完成的增强。阻止目标方法的执行,获得方法参数。
注解:@Around

配置切面和通知
// 配置了自动AOP代理的,需要在类上配置该注解,不然无法被识别为切面
@Aspect
public class MyAspect {
    // 环绕通知
    @Around("execution(* com.pc.aop.dao.impl.CustomerDaoImpl.update(..))")
    // 通知:计算方法耗时
    public void calTime(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("方法执行前。。。。。。");
        // 打印参数
        System.out.println("参数为:" + joinPoint.getArgs()[0]);
        // 执行目标方法
        joinPoint.proceed();
        System.out.println("方法执行后。。。。。。");
    }
}
单元测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class SpringAOPTest {
    // 注入依赖
    @Resource(name = "customerDao")
    private CustomerDao customerDao;
    // 测试环绕通知
    @Test
    public void testAround() {
        customerDao.update(6166);
    }
}

输出

方法执行前。。。。。。
参数为:6166
更新用户了。。。
方法执行后。。。。。。
异常抛出通知

异常抛出通知:在目标方法执行出现异常的时候完成的增强。获得异常的信息。
注解:@AfterThrowing

配置切面和通知
// 配置了自动AOP代理的,需要在类上配置该注解,不然无法被识别为切面
@Aspect
public class MyAspect {
    // 异常通知
    @AfterThrowing(value = "execution(* com.pc.aop.dao.impl.CustomerDaoImpl.find(..))", throwing = "ex")
    // 通知:异常处理
    public void throwHandler(Throwable ex) {
        System.out.println("异常处理。。。。。。" + ex.getMessage());
    }
}
单元测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class SpringAOPTest {
    // 注入依赖
    @Resource(name = "customerDao")
    private CustomerDao customerDao;
    // 测试异常通知
    @Test
    public void testAfterThrowing() {
        customerDao.find();
    }
}

输出

查询用户了。。。
异常处理。。。。。。/ by zero
最终通知

最终通知:无论目标方法是否出现异常总是执行的增强。
注解:@After

PS:该案例和异常测试案例对同一个target进行增强。

配置切面和通知
// 配置了自动AOP代理的,需要在类上配置该注解,不然无法被识别为切面
@Aspect
public class MyAspect {
    // 最终通知
    @After("execution(* com.pc.aop.dao.impl.CustomerDaoImpl.find(..))")
    // 通知:关闭资源
    public void close() {
        System.out.println("关闭资源。。。。。。");
    }
}
单元测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class SpringAOPTest {
    // 注入依赖
    @Resource(name = "customerDao")
    private CustomerDao customerDao;
    // 测试最终通知
    @Test
    public void testFinally() {
        customerDao.find();
    }
}

输出

查询用户了。。。
关闭资源。。。。。。
异常处理。。。。。。/ by zero

切入点的注解

在上面的案例中,都是在通知上面直接定义切入点。这样有一个比较麻烦的问题,也就是如果我们需要修改多个通知相同的切入点,那么需要改大量的切入点代码。

上面的问题,可以通过使用切入点注解@Pointcut解决。

案例:

package com.pc.aop.advice;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
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;

/**
 * 切面类
 * 
 * @author Switch
 * @data 2016年11月23日
 * @version V1.0
 */
// 配置了自动AOP代理的,需要在类上配置该注解,不然无法被识别为切面
@Aspect
public class MyAspect {
    // 异常通知
    @AfterThrowing(value = "com.pc.aop.advice.MyAspect.pointcut1()", throwing = "ex")
    // 通知:异常处理
    public void throwHandler(Throwable ex) {
        System.out.println("异常处理。。。。。。" + ex.getMessage());
    }

    // 最终通知
    @After("com.pc.aop.advice.MyAspect.pointcut1()")
    // 通知:关闭资源
    public void close() {
        System.out.println("关闭资源。。。。。。");
    }

    // 配置切入点
    @Pointcut("execution(* com.pc.aop.dao.impl.CustomerDaoImpl.find(..))")
    public void pointcut1() {}
}

PS:切入点的注解需要定义在方法上,切入点方法一般是无意义的。如果需要使用切入点方法,只需要在通知声明中写入包名.类型.方法名(),如果通知和切入点在一个类中,那么也可以直接写入方法名()

Spring AOP小项目

GitHub:Spring AOP小项目
GitHub:MyStore-netease

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值