您的位置:首页 > 编程语言 > Java开发

浅析spring AOP面向切面编程

2019-08-17 18:29 1476 查看

                                                                 关于spring AOP 编程的理解

spring 的AOP编程有两种实现方式,第一种是sping的动态代理,该AOP是一种实现其接口的方式,进行切面编程,另外一种方式是cglib代理,该代理方式原理是继承自己的类。

spring的配置文件如下:

 <aop:config proxy-target-class="false">  <!-- proxy-target-class="false" 表示动态代理(系统默认),proxy-target-class="true" cglib代理       -->
 </aop:config> 

AOP配置方式,一种是xml配置文件方式,另一种是注解方式。下面详细介绍两种方式的用法:

 <aop:config proxy-target-class="false">
        <aop:aspect id="log" ref="userManualProxy" >
               <aop:pointcut id="login"
                      expression="execution(* com.sheemes.service.impl.LoginServiceImpl.*(..))" />
                <aop:after method="loginInfo" pointcut-ref="login" />
        </aop:aspect>
    </aop:config> 

AOP中的相关概念

Aspect(切面): Aspect 声明类似于 Java 中的类声明,在 Aspect 中会包含着一些 Pointcut 以及相应的 Advice。
Joint point(连接点):表示在程序中明确定义的点,典型的包括方法调用,对类成员的访问以及异常处理程序块的执行等等,它自身还可以嵌套其它 joint point。
Pointcut(切点):表示一组 joint point,这些 joint point 或是通过逻辑关系组合起来,或是通过通配、正则表达式等方式集中起来,它定义了相应的 Advice 将要发生的地方。
Advice(增强):Advice 定义了在 Pointcut 里面定义的程序点具体要做的操作,它通过 before、after 和 around 来区别是在每个 joint point 之前、之后还是代替执行的代码。
Target(目标对象):织入 Advice 的目标对象.。
Weaving(织入):将 Aspect 和其他对象连接起来, 并创建 Adviced object 的过程

然后举一个容易理解的例子: 
看完了上面的理论部分知识, 我相信还是会有不少朋友感觉到 AOP 的概念还是很模糊, 对 AOP 中的各种概念理解的还不是很透彻. 其实这很正常, 因为 AOP 中的概念是在是太多了, 我当时也是花了老大劲才梳理清楚的. 
下面我以一个简单的例子来比喻一下 AOP 中 Aspect, Joint point, Pointcut 与 Advice之间的关系. 
让我们来假设一下, 从前有一个叫爪哇的小县城, 在一个月黑风高的晚上, 这个县城中发生了命案. 作案的凶手十分狡猾, 现场没有留下什么有价值的线索. 不过万幸的是, 刚从隔壁回来的老王恰好在这时候无意中发现了凶手行凶的过程, 但是由于天色已晚, 加上凶手蒙着面, 老王并没有看清凶手的面目, 只知道凶手是个男性, 身高约七尺五寸. 爪哇县的县令根据老王的描述, 对守门的士兵下命令说: 凡是发现有身高七尺五寸的男性, 都要抓过来审问. 士兵当然不敢违背县令的命令, 只好把进出城的所有符合条件的人都抓了起来.

来让我们看一下上面的一个小故事和 AOP 到底有什么对应关系. 
首先我们知道, 在 Spring AOP 中 Joint point 指代的是所有方法的执行点, 而 point cut 是一个描述信息, 它修饰的是 Joint point, 通过 point cut, 我们就可以确定哪些 Joint point 可以被织入 Advice. 对应到我们在上面举的例子, 我们可以做一个简单的类比, Joint point 就相当于 爪哇的小县城里的百姓,pointcut 就相当于 老王所做的指控, 即凶手是个男性, 身高约七尺五寸, 而 Advice 则是施加在符合老王所描述的嫌疑人的动作: 抓过来审问. 
为什么可以这样类比呢?

Joint point : 爪哇的小县城里的百姓: 因为根据定义, Joint point 是所有可能被织入 Advice 的候选的点, 在 Spring AOP中, 则可以认为所有方法执行点都是 Joint point. 而在我们上面的例子中, 命案发生在小县城中, 按理说在此县城中的所有人都有可能是嫌疑人.

Pointcut :男性, 身高约七尺五寸: 我们知道, 所有的方法(joint point) 都可以织入 Advice, 但是我们并不希望在所有方法上都织入 Advice, 而 Pointcut 的作用就是提供一组规则来匹配joinpoint, 给满足规则的 joinpoint 添加 Advice. 同理, 对于县令来说, 他再昏庸, 也知道不能把县城中的所有百姓都抓起来审问, 而是根据凶手是个男性, 身高约七尺五寸, 把符合条件的人抓起来. 在这里 凶手是个男性, 身高约七尺五寸 就是一个修饰谓语, 它限定了凶手的范围, 满足此修饰规则的百姓都是嫌疑人, 都需要抓起来审问.

Advice :抓过来审问, Advice 是一个动作, 即一段 Java 代码, 这段 Java 代码是作用于 point cut 所限定的那些 Joint point 上的. 同理, 对比到我们的例子中, 抓过来审问 这个动作就是对作用于那些满足 男性, 身高约七尺五寸 的爪哇的小县城里的百姓.

Aspect::Aspect 是 point cut 与 Advice 的组合, 因此在这里我们就可以类比: “根据老王的线索, 凡是发现有身高七尺五寸的男性, 都要抓过来审问” 这一整个动作可以被认为是一个 Aspect.

最后是一个描述这些概念之间关系的图: 

Advice 的类型

before advice, 在 join point 前被执行的 advice. 虽然 before advice 是在 join point 前被执行, 但是它并不能够阻止 join point 的执行, 除非发生了异常(即我们在 before advice 代码中, 不能人为地决定是否继续执行 join point 中的代码)

after return advice, 在一个 join point 正常返回后执行的 advice

after throwing advice, 当一个 join point 抛出异常后执行的 advice
after(final) advice, 无论一个 join point 是正常退出还是发生了异常, 都会被执行的 advice.
around advice, 在 join point 前和 joint point 退出后都执行的 advice. 这个是最常用的 advice.
introduction,introduction可以为原有的对象增加新的属性和方法。

代码如下:(配置文件)

 

<?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:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
    http://www.springframework.org/schema/aop 
    http://www.springframework.org/schema/aop/spring-aop-3.0.xsd ">

   <aop:config>
      <aop:pointcut id="selectAll" 
                    expression="execution(* com.aop.*.getName(..))"/>
    <aop:pointcut expression="execution(* com.aop.*.getAge(..))" id="getAge"/>            
      <aop:aspect id="log" ref="log1">
          <aop:before pointcut-ref="selectAll"  pointcut="name" method="beforeAdvice"/>
            <aop:after pointcut-ref="selectAll" method="afterAdvice"/>
            <aop:before method="beforeAdvice" pointcut-ref="getAge"/>
            <aop:after method="afterAdvice" pointcut-ref="getAge"/> 
      </aop:aspect>
   </aop:config>

   <!-- Definition for student bean -->
   <bean id="student" class="com.aop.Student">
      <property name="name"  value="Zara" />
      <property name="age"  value="11"/>      
   </bean>

   <!-- Definition for logging aspect -->
   <bean id="log1" class="com.aop.Logging"/> 

</beans>

 <!-- Definition for student bean -->
   <bean id="student" class="com.aop.Student">
      <property name="name"  value="Zara" />
      <property name="age"  value="11"/>      
   </bean>

   <!-- Definition for logging aspect -->
   <bean id="log1" class="com.aop.Logging"/> 

package com.aop;
public class Logging {
    /** 
        * This is the method which I would like to execute
        * before a selected method execution.
        */
    

       public void beforeAdvice(String name){
          System.out.println("Going to setup student profile."+name);
       }
       /** 
        * This is the method which I would like to execute
        * after a selected method execution.
        */
       public void afterAdvice(String name){
           if("小明".equals(name)) {
               System.out.println("小明登录了系统");
           }
          System.out.println("Student profile has been setup."+name);
       }
       /** 
        * This is the method which I would like to execute
        * when any method returns.
        */
       
       public void afterReturningAdvice(Object retVal){
          System.out.println("Returning:" + retVal.toString() );
       }
       /**
        * This is the method which I would like to execute
        * if there is an exception raised.
        */
       public void AfterThrowingAdvice(IllegalArgumentException ex){
          System.out.println("There has been an exception: " + ex.toString());   
       }  
}

------------------------------注解形式的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:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
    http://www.springframework.org/schema/aop 
    http://www.springframework.org/schema/aop/spring-aop-3.0.xsd ">

   <aop:aspectj-autoproxy/>

   <!-- Definition for student bean -->
   <bean id="student" class="com.aop.Student">
      <property name="name"  value="Zara" />
      <property name="age"  value="11"/>      
   </bean>

   <!-- Definition for logging aspect -->
   <bean id="log1" class="com.aop.Logging"/> 

</beans>

package com.aop;

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
@Aspect
public class Logging {
       @Pointcut("execution(* com.aop.Student.set*(..))")
       public void setAll() {};
       @Pointcut("execution(* com.aop.Student.get*(..))")
       public void getAll() {};
       
    /** 
        * This is the method which I would like to execute
        * before a selected method execution.
        */
    
       @Before("setAll()&& args(name)")
       public void beforeAdvice(String name){
          System.out.println("Going to setup student profile."+name);
       }
       /** 
        * This is the method which I would like to execute
        * after a selected method execution.
        */
       @AfterReturning(pointcut="getAll()",returning="name")
       public void afterAdvice(String name){
           if("小明".equals(name)) {
               System.out.println("小明登录了系统");
           }
          System.out.println("Student profile has been setup."+name);
       }
       /** 
        * This is the method which I would like to execute
        * when any method returns.
        */
       
       public void afterReturningAdvice(Object retVal){
          System.out.println("Returning:" + retVal.toString() );
       }
       /**
        * This is the method which I would like to execute
        * if there is an exception raised.
        */
       public void AfterThrowingAdvice(IllegalArgumentException ex){
          System.out.println("There has been an exception: " + ex.toString());   
       }  
}

package com.aop;

public class Student {
       private Integer age;
       private String name;
       public void setAge(Integer age) {
          this.age = age;
       }
       public Integer getAge() {
          System.out.println("Age : " + age );
          return age;
       }
       public void setName(String name) {
          this.name = name;
       }
       public String getName() {
          System.out.println("Name : " + name );
          return null;
       }  
       public void printThrowException(){
           System.out.println("Exception raised");
          // throw new IllegalArgumentException();
       }
}

package com.show;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.aop.Student;

public class MainApp2 {
    public static void main(String[] args) {
      ApplicationContext context = new ClassPathXmlApplicationContext("spring2.xml");
      Student student=(Student)context.getBean("student");
      student.setName("小明");
      student.getName();
     // student.getAge();      
    //  student.printThrowException();
    }
}
面向切面AOP的参数传递过程

表达式中的参数必须和切点方法中的参数名称一致,1.表达式参数名称匹配切点方法参数名称,根据切点方法名称找到切点方法的类型,2.连接点方法参数名称,类型匹配切点方法参数名称和类型。

表达式中*表示任意字符串,..表示任意参数

 

 


 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: