Spring--AOP案例以及使用先容

打印 上一主题 下一主题

主题 656|帖子 656|积分 1968

AOP案例

1 案例-测量业务层接口万次执行效率

问题导入

能不能描述一下围绕通知内里的实现步骤?
1.1 需求和分析

需求:任意业务层接口执行均可表现其执行效率(执行时长)
分析:
​ ①:业务功能:业务层接口执行前后分别记载时间,求差值得到执行效率
​ ②:通知类型选择前后均可以加强的类型——围绕通知
1.2 代码实现

【前置工作】环境准备


  • Spring整合mybatis对spring_db数据库中的Account举行CRUD操作
  • Spring整合Junit测试CRUD是否OK。
  • 在pom.xml中添加aspectjweaver切入点表达式依赖
  • … …
【第一步】编写通知类

  1. @Component
  2. @Aspect
  3. public class ProjectAdvice {
  4.     //匹配业务层的所有方法
  5.     @Pointcut("execution(* com.itheima.service.*Service.*(..))")
  6.     private void servicePt(){}
  7.     //设置环绕通知,在原始操作的运行前后记录执行时间
  8.     @Around("ProjectAdvice.servicePt()") //本类类名可以省略不写
  9.     public void runSpeed(ProceedingJoinPoint pjp) throws Throwable {
  10.         //获取执行的签名对象
  11.         Signature signature = pjp.getSignature();
  12.         //获取接口/类全限定名
  13.         String className = signature.getDeclaringTypeName();
  14.         //获取方法名
  15.         String methodName = signature.getName();
  16.         //记录开始时间
  17.         long start = System.currentTimeMillis();
  18.         //执行万次操作
  19.         for (int i = 0; i < 10000; i++) {
  20.            pjp.proceed();
  21.         }
  22.         //记录结束时间
  23.         long end = System.currentTimeMillis();
  24.         //打印执行结果
  25.         System.out.println("万次执行:"+ className+"."+methodName+"---->" +(end-start) + "ms");
  26.     }
  27. }
复制代码
【第二步】在SpringConfig配置类上开启AOP注解功能

  1. @Configuration
  2. @ComponentScan("com.itheima")
  3. @PropertySource("classpath:jdbc.properties")
  4. @Import({JdbcConfig.class,MybatisConfig.class})
  5. @EnableAspectJAutoProxy //开启AOP注解功能
  6. public class SpringConfig {
  7. }
复制代码
【第三步】运行测试类,检察结果

  1. @RunWith(SpringJUnit4ClassRunner.class)
  2. @ContextConfiguration(classes = SpringConfig.class)
  3. public class AccountServiceTestCase {
  4.     @Autowired
  5.     private AccountService accountService;
  6.     @Test
  7.     public void testFindById(){
  8.         Account account = accountService.findById(2);
  9.     }
  10.     @Test
  11.     public void testFindAll(){
  12.         List<Account> list = accountService.findAll();
  13.     }
  14. }
复制代码
2 AOP切入点数据获取

问题导入

在围绕通知中可以获取到哪些数据?
2.1 获取参数

   说明:在前置通知和围绕通知中都可以获取到毗连点方法的参数们
  

  • JoinPoint对象描述了毗连点方法的运行状态,可以获取到原始方法的调用参数
  1. @Before("pt()")
  2. public void before(JoinPoint jp) {
  3.     Object[] args = jp.getArgs(); //获取连接点方法的参数们
  4.     System.out.println(Arrays.toString(args));
  5. }
复制代码


  • ProccedJointPoint是JoinPoint的子类
  1. @Around("pt()")
  2. public Object around(ProceedingJoinPoint pjp) throws Throwable {
  3.     Object[] args = pjp.getArgs(); //获取连接点方法的参数们
  4.     System.out.println(Arrays.toString(args));
  5.     Object ret = pjp.proceed();
  6.     return ret;
  7. }
复制代码
2.2 获取返回值

   说明:在返回后通知和围绕通知中都可以获取到毗连点方法的返回值
  

  • 返回后通知可以获取切入点方法返回值信息,使用形参可以接收对应的返回值
  1. @AfterReturning(value = "pt()",returning = "ret")
  2. public void afterReturning(String ret) { //变量名要和returning="ret"的属性值一致
  3.     System.out.println("afterReturning advice ..."+ret);
  4. }
复制代码


  • 围绕通知中可以手工誊写对原始方法的调用,得到的结果即为原始方法的返回值
  1. @Around("pt()")
  2. public Object around(ProceedingJoinPoint pjp) throws Throwable {
  3.     // 手动调用连接点方法,返回值就是连接点方法的返回值
  4.     Object ret = pjp.proceed();
  5.     return ret;
  6. }
复制代码
2.3 获取异常

   说明:在抛出异常后通知和围绕通知中都可以获取到毗连点方法中出现的异常
  

  • 抛出异常后通知可以获取切入点方法中出现的异常信息,使用形参可以接收对应的异常对象
  1. @AfterThrowing(value = "pt()",throwing = "t")
  2. public void afterThrowing(Throwable t) {//变量名要和throwing = "t"的属性值一致
  3.     System.out.println("afterThrowing advice ..."+ t);
  4. }
复制代码


  • 抛出异常后通知可以获取切入点方法运行的异常信息,使用形参可以接收运行时抛出的异常对象
  1. @Around("pt()")
  2. public Object around(ProceedingJoinPoint pjp)  {
  3.     Object ret = null;
  4.     //此处需要try...catch处理,catch中捕获到的异常就是连接点方法中抛出的异常
  5.     try {
  6.         ret = pjp.proceed();
  7.     } catch (Throwable t) {
  8.         t.printStackTrace();
  9.     }
  10.     return ret;
  11. }
复制代码
3 案例-百度网盘密码数据兼容处理

问题导入

请说出我们该使用什么类型的通知来完成这个需求?
3.1 需求和分析

需求:对百度网盘分享链接输入密码时尾部多输入的空格做兼容处理
分析:
①:在业务方法执行之前对所有的输入参数举行格式处理——trim()
②:使用处理后的参数调用原始方法——围绕通知中存在对原始方法的调用
3.2 代码实现

【前置工作】环境准备

  1. //-------------service层代码-----------------------
  2. public interface ResourcesService {
  3.     public boolean openURL(String url ,String password);
  4. }
  5. @Service
  6. public class ResourcesServiceImpl implements ResourcesService {
  7.     @Autowired
  8.     private ResourcesDao resourcesDao;
  9.     public boolean openURL(String url, String password) {
  10.         return resourcesDao.readResources(url,password);
  11.     }
  12. }
  13. //-------------dao层代码-----------------------
  14. public interface ResourcesDao {
  15.     boolean readResources(String url, String password);
  16. }
  17. @Repository
  18. public class ResourcesDaoImpl implements ResourcesDao {
  19.     public boolean readResources(String url, String password) {
  20.         System.out.println(password.length());
  21.         //模拟校验
  22.         return password.equals("root");
  23.     }
  24. }
复制代码
【第一步】编写通知类

  1. @Component
  2. @Aspect
  3. public class DataAdvice {
  4.    
  5.     @Pointcut("execution(boolean com.itheima.service.*Service.*(*,*))")
  6.     private void servicePt(){}
  7.     @Around("DataAdvice.servicePt()")
  8.     public Object trimStr(ProceedingJoinPoint pjp) throws Throwable {
  9.         Object[] args = pjp.getArgs();
  10.         for (int i = 0; i < args.length; i++) {
  11.             //判断参数是不是字符串
  12.             if(args[i].getClass().equals(String.class)){
  13.                 args[i] = args[i].toString().trim();
  14.             }
  15.         }
  16.         Object ret = pjp.proceed(args);
  17.         return ret;
  18.     }
  19. }
复制代码
【第二步】在SpringConfig配置类上开启AOP注解功能

  1. @Configuration
  2. @ComponentScan("com.itheima")
  3. @EnableAspectJAutoProxy
  4. public class SpringConfig {
  5. }
复制代码
【第三步】运行测试类,检察结果

  1. public class App {
  2.     public static void main(String[] args) {
  3.         ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
  4.         ResourcesService resourcesService = ctx.getBean(ResourcesService.class);
  5.         boolean flag = resourcesService.openURL("http://pan.baidu.com/haha", "root ");
  6.         System.out.println(flag);
  7.     }
  8. }
复制代码
4 AOP开辟总结

4.1 AOP的核心概念



  • 概念:AOP(Aspect Oriented Programming)面向切面编程,一种编程范式
  • 作用:在不惊动原始筹划的基础上为方法举行功能加强
  • 核心概念

    • 代理(Proxy):SpringAOP的核心本质是采用代理模式实现的
    • 毗连点(JoinPoint): 在SpringAOP中,明白为任意方法的执行
    • 切入点(Pointcut):匹配毗连点的式子,也是具有共性功能的方法描述
    • 通知(Advice):多少个方法的共性功能,在切入点处执行,最终体现为一个方法
    • 切面(Aspect):描述通知与切入点的对应关系
    • 目标对象(Target):被代理的原始对象成为目标对象

4.2 切入点表达式语法



  • 切入点表达式标准格式:动作关键字(访问修饰符 返回值 包名.类/接口名.方法名(参数)异常名)

    • execution(* com.itheima.service.Service.(…))

  • 切入点表达式描述通配符:

    • 作用:用于快速描述,范围描述
    • *:匹配任意符号(常用)
    • … :匹配多个连续的任意符号(常用)
    • +:匹配子类类型

  • 切入点表达式誊写本领
    1.按标准规范开辟
    2.查询操作的返回值发起使用*匹配
    3.减少使用…的形式描述包
    4.对接口举行描述,使用*表示模块名,例如UserService的匹配描述为*Service
    5.方法名誊写保存动词,例如get,使用*表示名词,例如getById匹配描述为getBy*
    6.参数根据实际情况灵活调解
4.3 五种通知类型



  • 前置通知
  • 后置通知

    • 围绕通知(重点)
    • 围绕通知依赖形参ProceedingJoinPoint才能实现对原始方法的调用
    • 围绕通知可以隔离原始方法的调用执行
    • 围绕通知返回值设置为Object类型
    • 围绕通知中可以对原始方法调用过程中出现的异常举行处理

  • 返回后通知
  • 抛出异常后通知

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

九天猎人

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表