美文网首页Spring
Spring_13_Spring框架的AOP

Spring_13_Spring框架的AOP

作者: 有_味 | 来源:发表于2018-07-16 21:56 被阅读25次

    Spring 框架的 AOP

    Spring框架的一个关键组件是面向切面编程(AOP)框架,面向切面的编程需要把程序逻辑分解成不同的部分称为关注点.跨一个应用程序的多个点的功能被称为横切关注点,这些横切关注点在概念上独立于应用程序的业务逻辑.有各种各样的常见的很好的方面的例子.如:日志,审计,声明式事务,安全性和缓存等.

    在OOP中,关键单元模块度类,而在AOP中单元模块度是方面.依赖注入帮助你对应用程序对象相互理解解耦和AOP可以帮助你从他们所影响的对象中对横切关注点解耦.AOP是像编程语言的触发物,如Perl,NET,java 或者其他.

    Spring AOP模块是提供拦截器来拦截一个应用程序,例如,当执行一个方法时,你可以在方法执行之前或之后添加额外的功能.

    AOP术语

    在我们开始使用AOP工作之前,让我们熟悉一些AOP概念的术语,这些术语并不特定与Spring,而是与AOP有关的.

    描述
    Aspect 一个模块具有一组提供横切需求的APIs.例如,一个日志模块为了记录日志将被AOP方面调用.应用程序可以用有任意数量的方面,这取决于需求.
    Join Point 在你的应用程序中它代表一个点,你可以在插件AOP方面.你也能说,它是在实际应用程序中,其中一个操作将使用Spring AOP 框架.
    Advice 这是实际行动之前或之后执行的方法.这是在应用程序执行期间通过Spring AOP 框架实际被调用的代码
    Pointcut 这是一组一个或多个连接点,通知应该被执行,你可以使用表达式或模式指定切入点正如我们将AOP的例子中看到的.
    Introduction 引用允许你添加新方法或属性到现有的类中.
    Target Object 被一个或者多个方面所通知的对象,这个对象永远是一个被代理对象.也称为被通知对象.
    Weaving Weaving 把方面连接到其他的应用程序类型或者对象上,并创建一个被通知的对象.这些可以在编译时,类加载时和运行时完成.

    Spring 方面可以使用下面提到的五种通知工作

    通知 描述
    前置通知 在一个方法执行前,执行通知
    后置通知 在一个方法执行后,不考虑其结果,执行通知.
    返回后通知 在一个方法执行后,只有在方法成功完成时,才能执行通知.
    抛出异常通知 在一个方法执行后,只有在方法退出抛出异常时,才能执行通知.
    环绕通知 在建议方法调用之后和之前,执行通知.

    实现自定义方面

    Spring 支持 @AspectJannotation style 的方法和基于模式的方法来实现自定义方面. 这两种方法已经在下面两个子节点进行了详细的介绍.

    方法 描述
    XML Schema based 方面是使用常规类一级基于配置的XML来实现的.
    @AspectJ based @AspectJ 引用一种声明方面的风格作为带有java5注释的常规的Java注释.

    Spring 中基于AOP的XML架构

    为了在本届描述使用AOP命名空间标签,你需要导入spring-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 ">
        <!-- bean definition & AOP specific configuration -->
    </beans>
    

    你还需要再你的应用程序的ClassPath中使用一下AspectJ库文件,这些库文件在一个AspectJ装置的lib目录中是可以用的,否则你可以在Internet中下载它们.

    jar
    aspectjrt.jar
    aspectjweaver.jar
    aspectj.jar
    aopalliance.jar

    声明一个aspect

    一个aspcet是使用元素声明的,支持bean时使用ref属性引用的.

    <aop:config>
    <aop:aspect id="myAspect" ref="aBean">
    ...
    </aop:aspect>
    </aop:config>
    <bean id="aBean" class="...">
    ...
    </bean>
    

    这里的"aBean"将被配置和依赖注入,就像前面的章节中你看到的其他的Spring bean 一样.

    声明一个切点

    一个切点有注入确定使用不同建议执行的感兴趣的连接点(即方法),在处理基于配置的XML架构时,切入点将会按照如下所示定义.

    <aop:config>
    <aop:aspect id="myAspect" ref="aBean">
    <aop:pointcut id="businessService"
    expression="execution(* com.xyz.myapp.service.*.*(..))"/>
    ...
    </aop:aspect>
    </aop:config>
    <bean id="aBean" class="...">
    ...
    </bean>
    

    下面的实例定义了一个名为"businessService"的切入点,该切入点将与com.tutorialspoint 包下的 Student类中的getName() 方法相匹配

    <aop:config>
    <aop:aspect id="myAspect" ref="aBean">
    <aop:pointcut id="businessService"
    expression="execution(* com.tutorialspoint.Student.getName(..))"/>
    ...
    </aop:aspect>
    </aop:config>
    <bean id="aBean" class="...">
    ...
    </bean>
    

    声明建议

    你可以使用 <aop:{ADVICE NAME}>元素在一个中声明五个建议中的任何一个,如下所示

    <aop:config>
    <aop:aspect id="myAspect" ref="aBean">
    <aop:pointcut id="businessService"
    expression="execution(* com.xyz.myapp.service.*.*(..))"/>
    <!-- a before advice definition -->
    <aop:before pointcut-ref="businessService"
    method="doRequiredTask"/>
    <!-- an after advice definition -->
    <aop:after pointcut-ref="businessService"
    method="doRequiredTask"/>
    <!-- an after-returning advice definition -->
    <!--The doRequiredTask method must have parameter named retVal -->
    <aop:after-returning pointcut-ref="businessService"
    returning="retVal"
    method="doRequiredTask"/>
    <!-- an after-throwing advice definition -->
    <!--The doRequiredTask method must have parameter named ex -->
    <aop:after-throwing pointcut-ref="businessService"
    throwing="ex"
    method="doRequiredTask"/>
    <!-- an around advice definition -->
    <aop:around pointcut-ref="businessService"
    method="doRequiredTask"/>
    ...
    </aop:aspect>
    </aop:config>
    <bean id="aBean" class="...">
    ...
    </bean>
    

    你可以对不同的建议使用相同的doRequiredTask 或者不同的方法。这些方法将会作为 aspect 模块的一部分来定义.

    基于AOP的xml架构的示例

    步骤 描述
    1 创建一个名为 SpringExample 的项目,并且在所创建项目的 c src 文件夹下创建一个名为 com.tutorialspoint的包
    2 使用 Add External JARs 选项添加所需的 Spring 库文件,就如在 Spring Hello World Example 章节中解释的
    3 在项目中添加 Spring AOP 指定的库文件 r aspectjrt.jar, aspectjweaver.jar 和 aspectj.jar。
    4 在 com.tutorialspoint 包下创建 Java 类 Logging, Student 和 MainApp
    5 在src 文件夹下创建 Beans 配置文件 Beans.xml 。
    6 最后一步是创建所有 Java 文件和 Bean 配置文件的内容,并且按如下解释的那样运行应用程序。

    Logging.java

    package com.tutorialspoint;
    
    public class Logging {
        /**
         * This is the method which I would like to execute before a selected method
         * execution.
         */
        public void beforeAdvice() {
            System.out.println("Going to setup student profile.");
        }
    
        /**
         * This is the method which I would like to execute after a selected method
         * execution.
         */
        public void afterAdvice() {
            System.out.println("Student profile has been setup.");
        }
    
        /**
         * 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());
        }
    }
    
    

    Student.java

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

    MainApp.java

    package com.tutorialspoint;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class MainApp {
    
        public static void main(String[] args) {
            ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
            Student student = (Student) context.getBean("student");
            student.getName();
            student.getAge();
            student.printThrowException();
        }
    }
    

    Beans.xml

    <?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:aspect id="log" ref="logging">
                <aop:pointcut id="selectAll"
                    expression="execution(* com.tutorialspoint.*.*(..))" />
                <aop:before pointcut-ref="selectAll" method="beforeAdvice" />
                <aop:after pointcut-ref="selectAll" method="afterAdvice" />
                <aop:after-returning pointcut-ref="selectAll"
                    returning="retVal" method="afterReturningAdvice" />
                <aop:after-throwing pointcut-ref="selectAll"
                    throwing="ex" method="AfterThrowingAdvice" />
            </aop:aspect>
        </aop:config>
        <!-- Definition for student bean -->
        <bean id="student" class="com.tutorialspoint.Student">
            <property name="name" value="Zara" />
            <property name="age" value="11" />
        </bean>
        <!-- Definition for logging aspect -->
        <bean id="logging" class="com.tutorialspoint.Logging" />
    
    </beans>
    

    运行程序后会报错

    Going to setup student profile.
    Name : Zara
    Student profile has been setup.
    Returning:Zara
    Going to setup student profile.
    Age : 11
    Student profile has been setup.
    Returning:11
    Going to setup student profile.
    Exception raised
    Student profile has been setup.
    There has been an exception: java.lang.IllegalArgumentException
    Exception in thread "main" java.lang.IllegalArgumentException
    

    让我们来解释一下上面定义的com.tutorialspoint中选择所有的方法,让我们假设一下,你想要在一个特殊的方法之前或者之后执行你的建议,你可以通过替换使用真实类和方法名称的切点定义中的星号(*)来定义你的切入点来缩短你的执行

    <?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:aspect id="log" ref="logging">
                <aop:pointcut id="selectAll"
                    expression="execution(* com.tutorialspoint.Student.getName(..))" />
                <aop:before pointcut-ref="selectAll" method="beforeAdvice" />
                <aop:after pointcut-ref="selectAll" method="afterAdvice" />
            </aop:aspect>
        </aop:config>
        <!-- Definition for student bean -->
        <bean id="student" class="com.tutorialspoint.Student">
            <property name="name" value="Zara" />
            <property name="age" value="11" />
        </bean>
        <!-- Definition for logging aspect -->
        <bean id="logging" class="com.tutorialspoint.Logging" />
    </beans>
    

    Spring 中基于AOP的@AspectJ

    @AspectJ作为Java5 注释的普通java类,它指明的是上面aspects的一种风格,通过你再基于架构的XML配置文件中包含以下元素,@AspectJ支持是可以用的.

    <aop:aspectj-autoproxy/>
    

    你还需要再你的应用程序的classPath中使用一下AspectJ库文件.这些库文件子一个AspectJ装置的"lib"目录中是可用的,否则你可以在internet中下载它们

    jar
    aspectjr.jar
    aspectjweaver.jar
    aspectj.jar
    aopalliance.jar

    声明一个aspect

    Aspects类和其他任何正常的bean一样,除了他们将会用@AspectJ注释之外,它和其他类一样可能有方法和字段 如下:

    package org.xyz;
    import org.aspectj.lang.annotation.Aspect;
    @Aspect
    public class AspectModule {
    }
    

    它们将在XML中按照如下进行配置,就和其他任何bean一样.

    <bean id="myAspect" class="org.xyz.AspectModule">
    <!-- configure properties of aspect here as normal -->
    </bean>
    

    声明一个切入点

    一个切入点有助于确定使用不同建议执行的感兴趣的连接点(即方法).在处理基于配置的XML架构时,欺辱的的生命有两部分.

    • 一个切入点表达式决定了我们感兴趣的哪个方法会真正被执行
    • 一个切入点标签包含一个名称和任意数量的参数.方法的真正内容是不相干的,并且实际上它应该是空的.

    下面的实例中定义了一个名为"businessService"的切入点,该切入点将与com.tutorialspoint包下的类中可用的每一个方法相匹配:

    import org.aspectj.lang.annotation.Pointcut;
    @Pointcut("execution(* com.xyz.myapp.service.*.*(..))") // expression
    private void businessService() {} // signature
    

    下面的示例中定义了一个名为"getname"的切入点,该切入点将与com.tutorialspoint包下的Student类中的getName() 方法相匹配.

    import org.aspectj.lang.annotation.Pointcut;
    @Pointcut("execution(* com.tutorialspoint.Student.getName(..))")
    private void getname() {}
    

    声明建议

    你可以使用 @{ADVICE-NAME} 注释来声明五个建议中的任意一个,如下所示.这个假设你已经定义了一个切入点标签方法businessService()

    @Before("businessService()")
    public void doBeforeTask(){
    ...
    }
    @After("businessService()")
    public void doAfterTask(){
    ...
    }
    @AfterReturning(pointcut = "businessService()", returning="retVal")
    public void doAfterReturnningTask(Object retVal){
    // you can intercept retVal here.
    ...
    }
    @AfterThrowing(pointcut = "businessService()", throwing="ex")
    public void doAfterThrowingTask(Exception ex){
    // you can intercept thrown exception here.
    ...
    }
    @Around("businessService()")
    public void doAroundTask(){
    ...
    }
    

    你可以为任意一个建议定义你的切入点内联.下面是在建立之前定义内联切入点的一个示例:

    @Before("execution(* com.xyz.myapp.service.*.*(..))")
    public doBeforeTask(){
    ...
    }
    

    基于AOP 的@AspectJ示例

    步骤 描述
    1 创建一个名为 SpringExample 的项目,并且在所创建项目的 c src 文件夹下创建一个名为 com.tutorialspoint 的包。
    2 使用 Add External JARs 选项添加所需的 Spring 库文件,就如在 Spring Hello World Example 章节中解释的那样。
    3 在项目中添加 Spring AOP 指定的库文件 r aspectjrt.jar, aspectjweaver.jar 和 aspectj.jar。
    4 在 com.tutorialspoint 包下创建 Java 类 Logging, Student 和 MainApp
    5 在src 文件夹下创建 Beans 配置文件 Beans.xml
    6 最后一步是创建所有 Java 文件和 Bean 配置文件的内容,并且按如下解释的那样运行应用程序。

    Logging.java

    package com.tutorialspoint;
    
    import org.aspectj.lang.annotation.After;
    import org.aspectj.lang.annotation.AfterReturning;
    import org.aspectj.lang.annotation.AfterThrowing;
    import org.aspectj.lang.annotation.Before;
    import org.aspectj.lang.annotation.Pointcut;
    
    public class Logging {
        /**
         * Following is the definition for a pointcut to select all the methods
         * available. So advice will be called for all the methods.
         */
        @Pointcut("execution(* com.tutorialspoint.*.*(..))")
        private void selectAll() {
        }
    
        /**
         * This is the method which I would like to execute before a selected method
         * execution.
         */
        @Before("selectAll()")
        public void beforeAdvice() {
            System.out.println("Going to setup student profile.");
        }
    
        /**
         * This is the method which I would like to execute after a selected method
         * execution.
         */
        @After("selectAll()")
        public void afterAdvice() {
            System.out.println("Student profile has been setup.");
        }
    
        /**
         * This is the method which I would like to execute when any method returns.
         */
        @AfterReturning(pointcut = "selectAll()", returning = "retVal")
        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 by any method.
         */
        @AfterThrowing(pointcut = "selectAll()", throwing = "ex")
        public void AfterThrowingAdvice(IllegalArgumentException ex) {
            System.out.println("There has been an exception: " + ex.toString());
        }
    }
    
    

    Student.java

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

    MainApp.java

    package com.tutorialspoint;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class MainApp {
    
        public static void main(String[] args) {
            ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
            Student student = (Student) context.getBean("student");
            student.getName();
            student.getAge();
            student.printThrowException();
        }
    }
    

    Beans.xml

    <?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.tutorialspoint.Student">
            <property name="name" value="Zara" />
            <property name="age" value="11" />
        </bean>
        <!-- Definition for logging aspect -->
        <bean id="logging" class="com.tutorialspoint.Logging" />
    </beans>
    

    结果

    Age : 11
    Exception raised
    java.lang.IllegalArgumentException
    

    相关文章

      网友评论

        本文标题:Spring_13_Spring框架的AOP

        本文链接:https://www.haomeiwen.com/subject/nodipftx.html