写在前面

很久以前在有道云笔记上写的笔记,打算放弃它了,将笔记迁移到这里来。文章可能还有很多不足,请大家谅解,欢迎大佬提意见。

本文使用到的东西

  1. java
  2. ecplipse
  3. spring

aop概述

aop的原理基于java动态代理模式,在java文件夹中有动态代理示例

aop添加包

aop实现除了spring包以外还需要添加的包
链接:https://pan.baidu.com/s/1acjKuNkqxdwdoz1hghy_wg
提取码:tbko

aop简单示例

链接:https://pan.baidu.com/s/1ycVitoJJ0tHjexycTOnSGw
提取码:o48k

环绕通知中参数的一些运用示例

链接:https://pan.baidu.com/s/1rr-wNlNFaCnc4AMPgBeVUA
提取码:50jy

aop定义配置文件示例

<?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" 
xmlns:tx="http://www.springframework.org/schema/tx" 
xsi:schemaLocation=" 
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd 
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd 
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd 
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd 
">
   <!-- 创建1个业务类对象 -->
   <bean id="service" class="com.etc.service.UserServiceImpl">  
   </bean>
   <!-- 创建1个业务类对象 -->
   <bean id="service2" class="com.etc.service.UserServiceImpl2">
   </bean>
   <!-- 创建1个自定义通知类对象 --> 
   <bean id="advice" class="com.etc.advice.MyAdvice">  
   </bean>
   <!-- 配置aop的织入-->
   <aop:config>
      <aop:pointcut expression="execution(* com.etc.service.UserService.*og*(..))" id="pc"/>
      <aop:pointcut expression="execution(* com.etc.service.UserService.*eg*(..))" id="pc2"/>
      <aop:aspect ref="advice">     
         <aop:before method="before" pointcut-ref="pc" />         <!-- 配置id为pc切点的前置织入-->
         <aop:after method="after" pointcut-ref="pc2" />  <!-- 配置id为pc2切点的后置织入-->
         <!--    
         <aop:before method="before" pointcut-ref="pc" />       
         <aop:after method="after" pointcut-ref="pc" />         
         <aop:around method="around" pointcut-ref="pc"/>
          <aop:after-throwing method="afterthrow" pointcut-ref="pc"/>
           -->
      </aop:aspect>
   </aop:config>
</beans>

aop标签介绍

<aop:config >标签

  1. 该标签用于配置aop的织入,里面写aop的具体实现
  2. 该标签在根标签中配置

<aop:pointcut >标签
使用示例:

<aop:pointcut expression="execution(* com.etc.service.UserService.*og*(..))" id="pc"/>
  1. 该标签用于添加aop切点,是<aop:config >的子标签,用于给指定的路径中的方法添加切点
  2. expression属性:用于设置切点的位置,填写格式如上,在包名前有一个“”号,和包名用空格隔开,包名中可以在任意位置添加“”,用来表示模糊查询
  3. id属性:给该切点设置一个id,在使用<aop:before >等标签时指定该id设置切点位置

<aop:aspect >标签
使用示例:

<aop:aspect ref="advice">     
      </aop:aspect>
  1. 该标签为<aop:config >的子标签,有<aop:before >等子标签
  2. 该标签用于指定通知的bean对象,该标签拥有<aop:before >等子标签,具体实现该通知对象切点的插入
  3. ref属性:要插入的自定义通知bean对象的id

<aop:before >、<aop:after >、<aop:around >、<aop:after-throwing >标签
使用示例:

<aop:after method="after" pointcut-ref="pc2" />
  1. <aop:before/ >:前置通知,在执行切点方法前执行指定方法
  2. <aop:after/ >:后置通知,在执行切点方法后执行指定方法
  3. <aop:around/ >:环绕通知,在指定执行方法中写执行语句执行切点方法
  4. <aop:after-throwing/ >:抛异常后通知,在程序运行抛出异常之后执行此方法
  5. 其他三个方法没有参数,环绕通知方法有一个ProceedingJoinPoint p参数
  6. 一个方法如果同时指定前置、后置和环绕通知,先执行前置通知、再执行环绕通知、最后执行后置通知
  7. method属性:填写其aop:aspect父标签指定的通知类中一个方法的名称,指定切点执行插入该方法
  8. pointcut-ref属性:指定一个</aop:aspect>切点id,表示在该切点执行method指定的方法
  9. 只有环绕通知能阻止原来代码的执行,实现新增权限管理。其他通知没有该功能

环绕通知执行切片方法

  • p.proceed();就可以实现执行切片方法,并且可以多次使用p.proceed()执行
  • p.getTarget()可以取得调用该方法的对象
  • if (p.getTarget() instanceof UserServiceImpl) 判断p.getTarget()取得的是不是UserServiceImpl类的对象

p.proceed()示例:

   public void around(ProceedingJoinPoint p)
   {
      System.out.println("这是环绕前通知!");
      try {
         p.proceed();
      } catch (Throwable e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
      }//执行原有的业务代码
      System.out.println("这是环绕后通知!");
   }

p.getTarget()示例:
public void around(ProceedingJoinPoint p)
   {
      //只有角色是admin才能删除帖子
       if (p.getTarget() instanceof UserServiceImpl)
       {
          UserServiceImpl imp = (UserServiceImpl) p.getTarget();
          if(!"admin".equals(imp.getRole()))
          {
             System.out.println("只有管理员才能删除帖子!");
             return;
          }             
       }
       try {
            p.proceed();//执行原有的代码
         } catch (Throwable e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
         }//执行原有的业务代码
 
      /*周日禁止注册
      Calendar c = Calendar.getInstance(); //获取当前的日历
      int day = c.get(Calendar.DAY_OF_WEEK);
     
      if(day==Calendar.SUNDAY)
      {
         System.out.println("周四禁止注册!");
         return;
      }
      */
   }