第三章 : 面向切面编程(AOP)

Posted 墨迹测试

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第三章 : 面向切面编程(AOP)相关的知识,希望对你有一定的参考价值。

面向切面编程(AOP)在提供模块化的意义上补充了 OOP。但模块化的关键单元是切面而不是类。

AOP将程序逻辑分解为不同的部分(称为 called concerns)。它通过切点来增加模块化。

切点是能够影响整个应用程序的关注点,并且应该尽可能集中在代码中的一个位置,例如事务管理、身份验证、日志记录、安全性等

为什么使用AOP ?

它提供了可插入的方法,可以在实际逻辑之前,之后或周围动态添加其他关注点。假设一个类中有10个方法,如下所示:

 
   
   
 
  1. class A{  

  2. public void m1(){...}  

  3. public void m2(){...}  

  4. public void m3(){...}  

  5. public void m4(){...}  

  6. public void m5(){...}  

  7. public void n1(){...}  

  8. public void n2(){...}  

  9. public void p1(){...}  

  10. public void p2(){...}  

  11. public void p3(){...}  

  12. }    


有5种方法从m开始,2种从n开始,3种从p开始。了解场景,必须维护日志并在调用从m开始的方法后发送通知。如果没有AOP,我们可以从以m开头的方法调用方法(维护日志并发送通知)。在这种情况下,我们需要在所有5个方法中编写代码。

但是,如果客户说以后我不需要发送通知,你需要改变所有的方法。它导致了维护问题。AOP的解决方案我们不需要从方法中调用方法。现在,我们可以在类的方法中定义额外的关注点,比如维护日志、发送通知等。它的entry在xml文件中给出 ; 将来,如果客户机说要删除通知程序功能,我们只需要在xml文件中更改。因此,在AOP中维护很容易。

什么地方用 AOP ?

AOP主要用于以下情况:

  • 提供声明式企业服务,如声明式事务管理。

  • 它允许用户实现自定义方面。

AOP概念和术语

  • AOP概念和术语如下:

    • Join point

    • Advice

    • Pointcut

    • Introduction

    • Target Object

    • Aspect

    • Interceptor

    • AOP Proxy

    • Weaving


1)连接点(Joinpoint)

程序执行的某个特定位置:如类开始 初始化前、类初始化后、 某个方法调用前、调用后、方法抛出异常后。一个类或一段程序代码拥有一些具有边界性质的特定点,这些点中的特定点就称为“连接点”。Spring仅支持方法的连接点,即仅能在方法调用前、方法调用后、方法抛出异常时以及方法调用前后这些程序执行点织入增强。连接点由两个信息确定:第一是用方法表示的程序执行点;第二是用相对点表示的方位。

2)切点(Pointcut)

每个程序类都拥有多个连接点,如一个拥有两个方法的类,这两个方法都是连接点,即连接点是程序类中客观存在的事物。AOP通过“ 切点”定位特定的连接点。连接点相当于数据库中的记录,而切点相当于查询条件。切点和连接点不是一对一的关系,一个切点可以匹配多个连接点。在Spring中,切点通过 org.springframework.aop.Pointcut接口进行描述,它使用类和方法作为连接点的查询条件,Spring AOP的规则解析引擎负责切点所设定的查询条件,找到对应的连接点。其实确切地说,不能称之为查询连接点,因为连接点是方法执行前、执行后等包括方位信息的具体程序执行点,而切点只定位到某个方法上,所以如果希望定位到具体连接点上,还需要提供方位信息。

  • 通知表示方面在特定连接点上采取的行动。有不同类型的通知:

    • Before Advice:它在连接点之前执行。

    • After Returning Advice:节点正常完成后执行。

    • After Throwing Advice:如果方法退出,则通过抛出异常来执行。

    • After (finally) Advice:连接点之后执行,而不管连接点退出是正常返回还是异常返回。

    • Around Advice: 它在连接点之前和之后执行。

3)增强(Advice)

增强是织入到目标类连接点上的一段程序代码,在Spring中,增强除用于描述一段程序代码外,还拥有另一个和连接点相关的信息,这便是执行点的方位。结合执行点方位信息和切点信息,我们就可以找到特定的连接点。

4)目标对象(Target)

增强逻辑的织入目标类。如果没有AOP,目标业务类需要自己实现所有逻辑,而在AOP的帮助下,目标业务类只实现那些非横切逻辑的程序逻辑,而性能监视和事务管理等这些横切逻辑则可以使用AOP动态织入到特定的连接点上。

5)引介(Introduction)

引介是一种特殊的增强,它为类添加一些属性和方法。这样,即使一个业务类原本没有实现某个接口,通过AOP的引介功能,我们可以动态地为该业务类添加接口的实现逻辑,让业务类成为这个接口的实现类。

6)织入(Weaving)

织入是将增强添加对目标类具体连接点上的过程。AOP像一台织布机,将目标类、增强或引介通过AOP这台织布机天衣无缝地编织到一起。根据不同的实现技术,AOP有三种织入的方式:
a、编译期织入,这要求使用特殊的Java编译器。
b、类装载期织入,这要求使用特殊的类装载器。
c、动态代理织入,在运行期为目标类添加增强生成子类的方式。
Spring采用动态代理织入,而AspectJ采用编译期织入和类装载期织入。

7)代理(Proxy)

一个类被AOP织入增强后,就产出了一个结果类,它是融合了原类和增强逻辑的代理类。根据不同的代理方式,代理类既可能是和原类具有相同接口的类,也可能就是原类的子类,所以我们可以采用调用原类相同的方式调用代理类。

8)切面(Aspect)

切面由切点和增强(引介)组成,它既包括了横切逻辑的定义,也包括了连接点的定义,Spring AOP就是负责实施切面的框架,它将切面所定义的横切逻辑织入到切面所指定的连接点中。

Spring AOP的实现

  • Spring AOP实现由以下提供:

    • AspectJ

    • Spring AOP

    • JBoss AOP

Spring AOP

以下三种方法可以使用Spring AOP。但是广泛使用的方法是 SpringAspectJ注释样式。下面给出了使用spring AOP的三种方法:

  1. 由Spring1.2旧样式(基于dtd)(在Spring3中也支持)

  2. 由AspectJ注释风格

  3. 通过Spring XML配置样式(基于模式)

Spring AOP示例

以下是Spring1.2旧式AOP(基于dtd)实现的示例。虽然在Spring3也支持,但是advice将spring aop与aspectJ一起使用,

spring1.2旧式aop实现支持4种类型的advice。

  1. Before Advice ,在实际方法调用之前执行。

  2. After Advice ,在实际的方法调用之后执行。如果方法有返回值,则在返回值之后执行

  3. Around Advice ,在实际方法调用之前和之后执行。

  4. Throws Advice ,如果实际方法抛出异常,则执行 3在advice之后,它在实际方法调用之后执行。如果method返回一个值,则在返回值后执行。 在advice周围,它在实际方法调用之前和之后执行。 抛出advice如果实际方法抛出异常则执行它。

让我们通过下面给出的图表来理解advice 层次结构:

1)MethodBeforeAdvice示例

创建一个包含实际业务逻辑的类。

文件:A.java

 
   
   
 
  1. package com.javatpoint;

  2. public class A {

  3.    public void m() {

  4.        System.out.println("actual business logic");

  5.    }

  6. }  

现在,创建实现 MethodBeforeAdvice接口的advisor类。

文件:BeforeAdvisor.java

 
   
   
 
  1. package com.javatpoint;

  2. import java.lang.reflect.Method;

  3. import org.springframework.aop.MethodBeforeAdvice;

  4. public class BeforeAdvisor implements MethodBeforeAdvice {

  5.    @Override

  6.    public void before(Method method, Object[] args, Object target) throws Throwable {

  7.        System.out.println("additional concern before actual logic");

  8.    }

  9. }  

在xml文件中,创建3个bean,一个用于A类,第二个用于 Advisor类,第三个用于 ProxyFactoryBean类。

文件:applicationContext.xml

 
   
   
 
  1. <?xml version="1.0" encoding="UTF-8"?>

  2. <beans

  3.        xmlns="http://www.springframework.org/schema/beans"

  4.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

  5.        xmlns:p="http://www.springframework.org/schema/p"

  6.        xsi:schemaLocation="http://www.springframework.org/schema/beans  

  7. http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

  8.    <bean id="obj" class="com.javatpoint.A"></bean>

  9.    <bean id="ba" class="com.javatpoint.BeforeAdvisor"></bean>

  10.    <bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">

  11.        <property name="target" ref="obj"></property>

  12.        <property name="interceptorNames">

  13.            <list>

  14.                <value>ba</value>

  15.            </list>

  16.        </property>

  17.    </bean>

  18. </beans>  

ProxyFactoryBean类:

该ProxyFactoryBean的类是由Spring Famework提供。它包含2个属性target和 interceptorNames。A类的实例将被视为目标对象,而advisor类的实例将被视为拦截器。您需要将advisor对象作为列表对象传递,如上面给出的xml文件中所示。

ProxyFactoryBean类的编写如下:

 
   
   
 
  1. public class ProxyFactoryBean {

  2.    private Object target;

  3.    private List interceptorNames;

  4. //getters and setters

  5. }  

文件:Test.java

 
   
   
 
  1. package com.javatpoint;

  2. import org.springframework.beans.factory.BeanFactory;

  3. import org.springframework.beans.factory.xml.XmlBeanFactory;

  4. import org.springframework.core.io.ClassPathResource;

  5. import org.springframework.core.io.Resource;

  6. public class Test {

  7.    public static void main(String[] args) {

  8.        Resource r=new ClassPathResource("applicationContext.xml");

  9.        BeanFactory factory=new XmlBeanFactory(r);

  10.        A a=factory.getBean("proxy",A.class);

  11.        a.m();

  12.    }

  13. }  

Output:

 
   
   
 
  1. additional concern before actual logic  

  2. actual business logic  

在MethodBeforeAdvice中打印其他信息

我们可以打印其他信息,如方法名称, 方法参数,目标对象, 目标对象类名,代理类等。

您只需要更改两个类 BeforeAdvisor.java和Test.java。

文件:BeforeAdvisor.java

 
   
   
 
  1. package com.javatpoint;

  2. import java.lang.reflect.Method;

  3. import org.springframework.aop.MethodBeforeAdvice;

  4. public class BeforeAdvisor implements MethodBeforeAdvice {

  5.    @Override

  6.    public void before(Method method, Object[] args, Object target) throws Throwable {

  7.        System.out.println("additional concern before actual logic");

  8.        System.out.println("method info:" + method.getName() + " " + method.getModifiers());

  9.        System.out.println("argument info:");

  10.        for (Object arg : args)

  11.            System.out.println(arg);

  12.        System.out.println("target Object:" + target);

  13.        System.out.println("target object class name: " + target.getClass().getName());

  14.    }

  15. }  

File: Test.java

 
   
   
 
  1. package com.javatpoint;

  2. import org.springframework.beans.factory.BeanFactory;

  3. import org.springframework.beans.factory.xml.XmlBeanFactory;

  4. import org.springframework.core.io.ClassPathResource;

  5. import org.springframework.core.io.Resource;

  6. public class Test {

  7.    public static void main(String[] args) {

  8.        Resource r = new ClassPathResource("applicationContext.xml");

  9.        BeanFactory factory = new XmlBeanFactory(r);

  10.        A a = factory.getBean("proxy", A.class);

  11.        System.out.println("proxy class name: " + a.getClass().getName());

  12.        a.m();

  13.    }

  14. }  

Output

 
   
   
 
  1. proxy class name: com.javatpoint.A$$EnhancerByCGLIB$$409872b1  

  2. additional concern before actual logic  

  3. method info:m 1  

  4. argument info:  

  5. target Object:com.javatpoint.A@11dba45  

  6. target object class name: com.javatpoint.A  

  7. actual business logic  `

2)AfterReturningAdvice 示例

创建一个包含实际业务逻辑的类。

文件:A.java 与前一个示例相同。

现在,创建实现 AfterReturningAdvice接口的advisor类。

文件:AfterAdvisor.java

 
   
   
 
  1. package com.javatpoint;

  2. import java.lang.reflect.Method;

  3. import org.springframework.aop.AfterReturningAdvice;

  4. public class AfterAdvisor implements AfterReturningAdvice {

  5.    @Override

  6.    public void afterReturning(Object returnValue, Method method,

  7.                               Object[] args, Object target) throws Throwable {

  8.        System.out.println("additional concern after returning advice");

  9.    }

  10. }  

File: Test.java Same as in the previous example.

Output

 
   
   
 
  1. actual business logic  

  2. additional concern after returning advice  

3)MethodInterceptor(AroundAdvice)示例

创建一个包含实际业务逻辑的类。

文件:A.java 与前一个示例相同。

现在,创建实现 MethodInterceptor接口的advisor类。

文件:AroundAdvisor.java

 
   
   
 
  1. package com.javatpoint;

  2. import org.aopalliance.intercept.MethodInterceptor;

  3. import org.aopalliance.intercept.MethodInvocation;

  4. public class AroundAdvisor implements MethodInterceptor {

  5.    @Override

  6.    public Object invoke(MethodInvocation mi) throws Throwable {

  7.        Object obj;

  8.        System.out.println("additional concern before actual logic");

  9.        obj = mi.proceed();

  10.        System.out.println("additional concern after actual logic");

  11.        return obj;

  12.    }

  13. }  

如上例所示创建xml文件,您只需在此处更改advisor 类。

文件:applicationContext.xml

 
   
   
 
  1. <?xml version="1.0" encoding="UTF-8"?>

  2. <beans

  3.        xmlns="http://www.springframework.org/schema/beans"

  4.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

  5.        xmlns:p="http://www.springframework.org/schema/p"

  6.        xsi:schemaLocation="http://www.springframework.org/schema/beans  

  7. http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

  8.    <bean id="obj" class="com.javatpoint.A"></bean>

  9.    <bean id="ba" class="com.javatpoint.AroundAdvisor"></bean>

  10.    <bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">

  11.        <property name="target" ref="obj"></property>

  12.        <property name="interceptorNames">

  13.            <list>

  14.                <value>ba</value>

  15.            </list>

  16.        </property>

  17.    </bean>

  18. </beans>  

文件:Test.java与前一个示例相同。

Output:

 
   
   
 
  1. additional concern before actual logic  

  2. actual business logic  

  3. additional concern after actual logic  

4) ThrowsAdvice 示例

File: Validator.java

 
   
   
 
  1. package com.javatpoint;

  2. public class Validator {

  3.    public void validate(int age) throws Exception {

  4.        if (age < 18) {

  5.            throw new ArithmeticException("Not Valid Age");

  6.        } else {

  7.            System.out.println("vote confirmed");

  8.        }

  9.    }

  10. }  

File: ThrowsAdvisor.java
Create a class that contains actual business logic.

 
   
   
 
  1. package com.javatpoint;

  2. import org.springframework.aop.ThrowsAdvice;

  3. public class ThrowsAdvisor implements ThrowsAdvice {

  4.    public void afterThrowing(Exception ex) {

  5.        System.out.println("additional concern if exception occurs");

  6.    }  

  7. }  

像前面的示例一样创建xml文件,您只需要更改Validator类和advisor类。

文件:applicationContext.xml

 
   
   
 
  1. <?xml version="1.0" encoding="UTF-8"?>  

  2. <beans  

  3.    xmlns="http://www.springframework.org/schema/beans"  

  4.    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  

  5.    xmlns:p="http://www.springframework.org/schema/p"  

  6.    xsi:schemaLocation="http://www.springframework.org/schema/beans  

  7. http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">  

  8. <bean id="obj" class="com.javatpoint.Validator"></bean>  

  9. <bean id="ba" class="com.javatpoint.ThrowsAdvisor"></bean>  

  10. <bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">  

  11. <property name="target" ref="obj"></property>  

  12. <property name="interceptorNames">  

  13. <list>  

  14. <value>ba</value>  

  15. </list>  

  16. </property>  

  17. </bean>  

  18. </beans>  

File: Test.java

 
   
   
 
  1. package com.javatpoint;

  2. import org.springframework.beans.factory.BeanFactory;

  3. import org.springframework.beans.factory.xml.XmlBeanFactory;

  4. import org.springframework.core.io.ClassPathResource;

  5. import org.springframework.core.io.Resource;

  6. public class Test {

  7.    public static void main(String[] args) {

  8.        Resource r = new ClassPathResource("applicationContext.xml");

  9.        BeanFactory factory = new XmlBeanFactory(r);

  10.        Validator v = factory.getBean("proxy", Validator.class);

  11.        try {

  12.            v.validate(12);

  13.        } catch (Exception e) {

  14.            e.printStackTrace();

  15.        }

  16.    }

  17. }  

Output

 
   
   
 
  1. java.lang.ArithmeticException: Not Valid Age  

  2. additional concern if exception occurs  

  3.    at com.javatpoint.Validator.validate(Validator.java:7)  

  4.    at com.javatpoint.Validator$$FastClassByCGLIB$$562915cf.invoke(<generated>)  

  5.    at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:191)  

  6.    at org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation.invoke  

  7. Joinpoint(Cglib2AopProxy.java:692)  

  8.    at org.springframework.aop.framework.ReflectiveMethodInvocation.  

  9. proceed(ReflectiveMethodInvocation.java:150)  

  10.    at org.springframework.aop.framework.adapter.ThrowsAdviceInterceptor.  

  11. invoke(ThrowsAdviceInterceptor.java:124)  

  12.    at org.springframework.aop.framework.ReflectiveMethodInvocation.  

  13. proceed(ReflectiveMethodInvocation.java:172)  

  14.    at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.  

  15. intercept(Cglib2AopProxy.java:625)  

  16.    at com.javatpoint.Validator$$EnhancerByCGLIB$$4230ed28.validate(<generated>)  

  17.    at com.javatpoint.Test.main(Test.java:15)  

Spring AOP AspectJ注释示例

  Spring框架advice您使用 SpringAspectJAOP实现,而不是Spring 1.2老式的基于dtd的AOP实现,因为它提供了更多的控制,而且易于使用。

有两种方法可以使用Spring AOP AspectJ实现:

  1. 通过注释。

  2. 通过xml配置(基于模式)

Spring AspectJ AOP实现提供了许多注释:
  1. @Aspect将该类声明为aspect。

  2. @Pointcut声明了切入点表达式。

用于创建advices 的注释如下:

  1. @Before 在调用实际方法之前应用它。

  2. @After 调用实际方法之后和返回结果之前应用。

  3. @AfterReturning 在调用实际方法之后和返回结果之前应用。但是你可以在advices中得到结果值。

  4. @Around 在调用实际方法之前和之后应用。

  5. @AfterThrowing 如果实际方法抛出异常,则应用它。

理解切入点理解切(入)点(Pointcut)

切入点是Spring AOP的一种表达语言。

@Pointcut注释用于定义切点。我们还可以通过名称引用切点表达式。以下为切入点表达式的简单示例。

 
   
   
 
  1. @Pointcut("execution(* Operation.*(..))")  

  2. private void doSomething() {}  

切入点表达式的名称是doSomething()。无论返回类型如何,它都将应用于Operation类的所有方法。

理解切点表示式

让我们通过以下示例来理解切入点表达式:


 
   
   
 
  1. @Pointcut("execution(public * *(..))")  

它将适用于所有的 公共方法。


 
   
   
 
  1. @Pointcut("execution(public Operation.*(..))")  

它将应用于Operation 的所有 公共方法


 
   
   
 
  1. @Pointcut("execution(* Operation.*(..))")  

它将应用于Operation类的 所有方法。


 
   
   
 
  1. @Pointcut("execution(public Employee.set*(..))")  


它将应用于Employee 的所有 公共setter方法。


 
   
   
 
  1. @Pointcut (“executionint Operation。*(..))”  

它将应用于 返回int值的Operation类的所有方法。


1)@Before示例

AspectJBeforeAdvice在实际业务逻辑方法之前应用。您可以在此处执行任何操作,例如conversion,authentication等。

创建一个包含实际业务逻辑的类。

文件:Operation.java

 
   
   
 
  1. package com.javatpoint;

  2. public class Operation {

  3.    public void msg() {

  4.        System.out.println("msg method invoked");

  5.    }

  6.    public int m() {

  7.        System.out.println("m method invoked");

  8.        return 2;

  9.    }

  10.    public int k() {

  11.        System.out.println("k method invoked");

  12.        return 3;

  13.    }

  14. }  

现在,创建包含在advice之前的aspect 类。

文件:TrackOperation.java

 
   
   
 
  1. package com.javatpoint;

  2. import org.aspectj.lang.JoinPoint;

  3. import org.aspectj.lang.annotation.Aspect;

  4. import org.aspectj.lang.annotation.Before;

  5. import org.aspectj.lang.annotation.Pointcut;

  6. @Aspect

  7. public class TrackOperation {

  8.    @Pointcut("execution(* Operation.*(..))")

  9.    public void k() {

  10.    }//pointcut name  

  11.    @Before("k()")//applying pointcut on before advice  

  12.    public void myadvice(JoinPoint jp)//it is advice (before advice)  

  13.    {

  14.        System.out.println("additional concern");

  15.        //System.out.println("Method Signature: "  + jp.getSignature());  

  16.    }

  17. }  

现在创建定义bean的 applicationContext.xml文件。

文件:applicationContext.xml

 
   
   
 
  1. <?xml version="1.0" encoding="UTF-8"?>

  2. <beans xmlns="http://www.springframework.org/schema/beans"

  3.       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

  4.       xmlns:aop="http://www.springframework.org/schema/aop"

  5.       xsi:schemaLocation="http://www.springframework.org/schema/beans  

  6.       http://www.springframework.org/schema/beans/spring-beans.xsd  

  7.       http://www.springframework.org/schema/aop  

  8.       http://www.springframework.org/schema/aop/spring-aop.xsd">

  9.    <bean id="opBean" class="com.javatpoint.Operation"></bean>

  10.    <bean id="trackMyBean" class="com.javatpoint.TrackOperation"></bean>

  11.    <bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator"></bean>

  12. </beans>  

现在,让我们调用实际方法。

文件:Test.java

 
   
   
 
  1. package com.javatpoint;

  2. import org.springframework.context.ApplicationContext;

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

  4. public class Test {

  5.    public static void main(String[] args) {

  6.        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

  7.        Operation e = (Operation) context.getBean("opBean");

  8.        System.out.println("calling msg...");

  9.        e.msg();

  10.        System.out.println("calling m...");

  11.        e.m();

  12.        System.out.println("calling k...");

  13.        e.k();

  14.    }

  15. }  

Output :

 
   
   
 
  1. calling msg...  

  2. additional concern  

  3. msg() method invoked  

  4. calling m...  

  5. additional concern  

  6. m() method invoked  

  7. calling k...  

  8. additional concern  

  9. k() method invoked  

如果您更改如下所示的切点表达式:

 
   
   
 
  1. @Pointcut("execution(* Operation.m*(..))")  

Output :

 
   
   
 
  1. calling msg...  

  2. additional concern  

  3. msg() method invoked  

  4. calling m...  

  5. additional concern  

  6. m() method invoked  

  7. calling k...  

  8. k() method invoked  

可以看到,在调用k()方法之前没有打印内容。

2) @After Example

在调用实际的业务逻辑方法之后应用AspectJ通知。它可以用来维护日志、安全、通知等。

在这里,我们假设Operation.java, applicationContext.xml和Test.java文件与@Before示例中给出的相同。

文件:TrackOperation.java

 
   
   
 
  1. package com.javatpoint;

  2. import org.aspectj.lang.JoinPoint;

  3. import org.aspectj.lang.annotation.Aspect;

  4. import org.aspectj.lang.annotation.After;

  5. import org.aspectj.lang.annotation.Pointcut;

  6. @Aspect

  7. public class TrackOperation {

  8.    @Pointcut("execution(* Operation.*(..))")

  9.    public void k() {

  10.    }//pointcut name  

  11.    @After("k()")//applying pointcut on after advice  

  12.    public void myadvice(JoinPoint jp)//it is advice (after advice)  

  13.    {

  14.        System.out.println("additional concern");

  15.        //System.out.println("Method Signature: "  + jp.getSignature());  

  16.    }

  17. }  

Output:

 
   
   
 
  1. calling msg...  

  2. msg() method invoked  

  3. additional concern  

  4. calling m...  

  5. m() method invoked  

  6. additional concern  

  7. calling k...  

  8. k() method invoked  

  9. additional concern  

可以看到,在调用 msg()、m()和 k()方法之后,会打印出额外concern ;

3) @AfterReturning Example

通过在返回advice后使用,我们可以在advice中得到结果。

创建包含业务逻辑的类。

文件:Operation.java

 
   
   
 
  1. package com.javatpoint;

  2. public class Operation {

  3.    public int m() {

  4.        System.out.println("m() method invoked");

  5.        return 2;

  6.    }

  7.    public int k() {

  8.        System.out.println("k() method invoked");

  9.        return 3;

  10.    }

  11. }  

File: TrackOperation.java

 
   
   
 
  1. package com.javatpoint;

  2. import org.aspectj.lang.JoinPoint;

  3. import org.aspectj.lang.annotation.AfterReturning;

  4. import org.aspectj.lang.annotation.Aspect;

  5. @Aspect

  6. public class TrackOperation {

  7.    @AfterReturning(pointcut = "execution(* Operation.*(..))", returning = "result")

  8.    public void myadvice(JoinPoint jp, Object result)//it is advice (after returning advice)  

  9.    {

  10.        System.out.println("additional concern");

  11.        System.out.println("Method Signature: " + jp.getSignature());

  12.        System.out.println("Result in advice: " + result);

  13.        System.out.println("end of after returning advice...");

  14.    }

  15. }  

File: applicationContext.xml

它与 @Beforeadvice示例中给出的相同

文件:Test.java

现在创建调用实际方法的测试类。

 
   
   
 
  1. package com.javatpoint;

  2. import org.springframework.context.ApplicationContext;

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

  4. public class Test {

  5.    public static void main(String[] args) {

  6.        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

  7.        Operation e = (Operation) context.getBean("opBean");

  8.        System.out.println("calling m...");

  9.        System.out.println(e.m());

  10.        System.out.println("calling k...");

  11.        System.out.println(e.k());

  12.    }

  13. }  

Output:

 
   
   
 
  1. calling m...  

  2. m() method invoked  

  3. additional concern  

  4. Method Signature: int com.javatpoint.Operation.m()  

  5. Result in advice: 2  

  6. end of after returning advice...  

  7. 2  

  8. calling k...  

  9. k() method invoked  

  10. additional concern  

  11. Method Signature: int com.javatpoint.Operation.k()  

  12. Result in advice: 3  

  13. end of after returning advice...  

  14. 3  

可以看到返回值打印了两次,一次是通过 TrackOperation类打印的,另一次是通过测试类打印的。

4) @Around 示例

在调用实际的业务逻辑方法之前和之后应用 AspectJaround通知 。

在这里,我们假设 applicationContext.xml文件与 @Before示例中给出的相同。

创建一个包含实际业务逻辑的类。

文件:Operation.java

 
   
   
 
  1. package com.javatpoint;

  2. public class Operation {

  3.    public void msg() {

  4.        System.out.println("msg() is invoked");

  5.    }

  6.    public void display() {

  7.        System.out.println("display() is invoked");

  8.    }

  9. }  

创建包含advise的aspect类。

您需要在advice方法中传递 PreceedingJoinPoint引用,以便我们可以通过调用 proceed()方法来继续请求。

文件:TrackOperation.java

 
   
   
 
  1. package com.javatpoint;

  2. import org.aspectj.lang.ProceedingJoinPoint;

  3. import org.aspectj.lang.annotation.Around;

  4. import org.aspectj.lang.annotation.Aspect;

  5. import org.aspectj.lang.annotation.Pointcut;

  6. @Aspect

  7. public class TrackOperation {

  8.    @Pointcut("execution(* Operation.*(..))")

  9.    public void abcPointcut() {

  10.    }

  11.    @Around("abcPointcut()")

  12.    public Object myadvice(ProceedingJoinPoint pjp) throws Throwable {

  13.        System.out.println("Additional Concern Before calling actual method");

  14.        Object obj = pjp.proceed();

  15.        System.out.println("Additional Concern After calling actual method");

  16.        return obj;

  17.    }

  18. }  

`` 文件:Test.java 现在创建调用实际方法的测试类。

 
   
   
 
  1. package com.javatpoint;

  2. import org.springframework.context.ApplicationContext;

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

  4. public class Test {

  5.    public static void main(String[] args) {

  6.        ApplicationContext context = new classPathXmlApplicationContext("applicationContext.xml");

  7.        Operation op = (Operation) context.getBean("opBean");

  8.        op.msg();

  9.        op.display();

  10.    }

  11. }  

Output :

 
   
   
 
  1. Additional Concern Before calling actual method  

  2. msg() is invoked  

  3. Additional Concern After calling actual method  

  4. Additional Concern Before calling actual method  

  5. display() is invoked  

  6. Additional Concern After calling actual method  

5) @AfterThrowing 示例

通过使用after throw advice,我们可以在 TrackOperation类中打印异常。让我们看看AspectJ在抛出advice之后的例子。

File: Operation.java

 
   
   
 
  1. package com.javatpoint;

  2. public class Operation {

  3.    public void validate(int age) throws Exception {

  4.        if (age < 18) {

  5.            throw new ArithmeticException("Not valid age");

  6.        } else {

  7.            System.out.println("Thanks for vote");

  8.        }

  9.    }

  10. }  

文件:applicationContext.xml 它与 @Beforeadvice示例中给出的相同

文件:Test.java 现在创建调用实际方法的Test类。

 
   
   
 
  1. package com.javatpoint;

  2. import org.springframework.context.ApplicationContext;

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

  4. public class Test {

  5.    public static void main(String[] args) {

  6.        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

  7.        Operation op = (Operation) context.getBean("opBean");

  8.        System.out.println("calling validate...");

  9.        try {

  10.            op.validate(19);

  11.        } catch (Exception e) {

  12.            System.out.println(e);

  13.        }

  14.        System.out.println("calling validate again...");

  15.        try {

  16.            op.validate(11);

  17.        } catch (Exception e) {

  18.            System.out.println(e);

  19.        }

  20.    }  

`Output :

 
   
   
 
  1. calling validate...  

  2. Thanks for vote  

  3. calling validate again...  

  4. additional concern  

  5. Method Signature: void com.javatpoint.Operation.validate(int)  

  6. Exception is: java.lang.ArithmeticException: Not valid age  

  7. end of after throwing advice...  

  8. java.lang.ArithmeticException: Not valid age  

```

Spring AOP AspectJ Xml配置示例

Spring允许您在xml文件中定义方面,建advices 和pointcuts 。

在上文中,我们已经看到了使用注释的aop示例。现在我们将通过xml配置文件看到相同的示例。

  • 让我们看一下用于定义advice的xml元素。


    • aop:before在调用实际业务逻辑方法之前应用它之前。

    • aop:after在调用实际业务逻辑方法后应用它。

    • aop:after-returning 在返回后,在调用实际的业务逻辑方法之后应用它。它可以用来拦截advice中的返回值。

    • aop:around它在调用实际业务逻辑方法之前和之后应用。

    • aop:after-throwing 如果实际的业务逻辑方法抛出异常,则应用它。

1) aop:before 示例

AspectJ Before Advice在实际业务逻辑方法之前应用。您可以在此处执行任何操作,例如conversion,authentication 等。

创建一个包含实际业务逻辑的类。

文件:Operation.java

 
   
   
 
  1. package com.javatpoint;

  2. public class Operation {

  3.    public void msg() {

  4.        System.out.println("msg method invoked");

  5.    }

  6.    public int m() {

  7.        System.out.println("m method invoked");

  8.        return 2;

  9.    }

  10.    public int k() {

  11.        System.out.println("k method invoked");

  12.        return 3;

  13.    }

  14. }  

`现在,创建包含在advice之前的aspect 类。

文件:TrackOperation.java

 
   
   
 
  1. package com.javatpoint;

  2. import org.aspectj.lang.JoinPoint;

  3. public class TrackOperation {

  4.    public void myadvice(JoinPoint jp)//it is advice  

  5.    {

  6.        System.out.println("additional concern");

  7.        //System.out.println("Method Signature: "  + jp.getSignature());  

  8.    }

  9. }  

`

File: applicationContext.xml

 
   
   
 
  1. <?xml version="1.0" encoding="UTF-8"?>

  2. <beans xmlns="http://www.springframework.org/schema/beans"

  3.       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

  4.       xmlns:aop="http://www.springframework.org/schema/aop"

  5.       xsi:schemaLocation="http://www.springframework.org/schema/beans  

  6.    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  

  7.    http://www.springframework.org/schema/aop  

  8.    http://www.springframework.org/schema/aop/spring-aop-3.0.xsd ">

  9.    <aop:aspectj-autoproxy/>

  10.    <bean id="opBean" class="com.javatpoint.Operation"></bean>

  11.    <bean id="trackAspect" class="com.javatpoint.TrackOperation"></bean>

  12.    <aop:config>

  13.        <aop:aspect id="myaspect" ref="trackAspect">

  14.            <!-- @Before -->

  15.            <aop:pointcut id="pointCutBefore" expression="execution(* com.javatpoint.Operation.*(..))"/>

  16.            <aop:before method="myadvice" pointcut-ref="pointCutBefore"/>

  17.        </aop:aspect>

  18.    </aop:config>

  19. </beans>  

File: Test.java

 
   
   
 
  1. package com.javatpoint;

  2. import org.springframework.context.ApplicationContext;

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

  4. public class Test {

  5.    public static void main(String[] args) {

  6.        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

  7.        Operation e = (Operation) context.getBean("opBean");

  8.        System.out.println("calling msg...");

  9.        e.msg();

  10.        System.out.println("calling m...");

  11.        e.m();

  12.        System.out.println("calling k...");

  13.        e.k();

  14.    }

  15. }  

Output:

 
   
   
 
  1. calling msg...  

  2. additional concern  

  3. msg() method invoked  

  4. calling m...  

  5. additional concern  

  6. m() method invoked  

  7. calling k...  

  8. additional concern  

  9. k() method invoked  

可以看见 : 调用 msg(),m()和 k()方法之前会打印 additional concern

2) aop:after 示例

我们假设Operation.java,TrackOperation.java和Test.java文件与aop中给出的相同: aop:before example

现在创建定义bean的applicationContext.xml文件。

文件:applicationContext.xml

 
   
   
 
  1. <?xml version="1.0" encoding="UTF-8"?>

  2. <beans xmlns="http://www.springframework.org/schema/beans"

  3.       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

  4.       xmlns:aop="http://www.springframework.org/schema/aop"

  5.       xsi:schemaLocation="http://www.springframework.org/schema/beans  

  6.    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  

  7.    http://www.springframework.org/schema/aop  

  8.    http://www.springframework.org/schema/aop/spring-aop-3.0.xsd ">

  9.    <aop:aspectj-autoproxy/>

  10.    <bean id="opBean" class="com.javatpoint.Operation"></bean>

  11.    <bean id="trackAspect" class="com.javatpoint.TrackOperation"></bean>

  12.    <aop:config>

  13.        <aop:aspect id="myaspect" ref="trackAspect">

  14.            <!-- @After -->

  15.            <aop:pointcut id="pointCutAfter" expression="execution(* com.javatpoint.Operation.*(..))"/>

  16.            <aop:after method="myadvice" pointcut-ref="pointCutAfter"/>

  17.        </aop:aspect>

  18.    </aop:config>

  19. </beans>  

Output :

 
   
   
 
  1. calling msg...  

  2. msg() method invoked  

  3. additional concern  

  4. calling m...  

  5. m() method invoked  

  6. additional concern  

  7. calling k...  

  8. k() method invoked  

  9. additional concern  

3) aop:after-returning 示例

通过使用 afterreturnadvice,我们可以在advice中得到结果。

File: Operation.java

 
   
   
 
  1. package com.javatpoint;

  2. public class Operation {

  3.    public int m() {

  4.        System.out.println("m() method invoked");

  5.        return 2;

  6.    }

  7.    public int k() {

  8.        System.out.println("k() method invoked");

  9.        return 3;

  10.    }

  11. }  

File: TrackOperation.java

 
   
   
 
  1. package com.javatpoint;

  2. import org.aspectj.lang.JoinPoint;

  3. public class TrackOperation {

  4.    public void myadvice(JoinPoint jp, Object result)//it is advice (after advice)  

  5.    {

  6.        System.out.println("additional concern");

  7.        System.out.println("Method Signature: " + jp.getSignature());

  8.        System.out.println("Result in advice: " + result);

  9.        System.out.println("end of after returning advice...");

  10.    }

  11. }  

`File: applicationContext.xml

 
   
   
 
  1. <?xml version="1.0"encoding="UTF-8"?>

  2. <beans xmlns="http://www.springframework.org/schema/beans"

  3.       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

  4.       xmlns:aop="http://www.springframework.org/schema/aop"

  5.       xsi:schemaLocation="http://www.springframework.org/schema/beans  

  6.        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  

  7.        http://www.springframework.org/schema/aop  

  8.        http://www.springframework.org/schema/aop/spring-aop-3.0.xsd ">

  9.    <aop:aspectj-autoproxy/>

  10.    <bean id="opBean" class="com.javatpoint.Operation"></bean>

  11.    <bean id="trackAspect" class="com.javatpoint.TrackOperation"></bean>

  12.    <aop:config>

  13.        <aop:aspect id="myaspect" ref="trackAspect">

  14.            <!--@AfterReturning -->

  15.            <aop:pointcut id="pointCutAfterReturning" expression="execution(* com.javatpoint.Operation.*(..))"/>

  16.            <aop:after-returning method="myadvice" returning="result" pointcut-ref="pointCutAfterReturning"/>

  17.        </aop:aspect>

  18.    </aop:config>

  19. </beans>  

File: Test.java

 
   
   
 
  1. package com.javatpoint;

  2. import org.springframework.context.ApplicationContext;

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

  4. public class Test {

  5.    public static void main(String[] args) {

  6.        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

  7.        Operation e = (Operation) context.getBean("opBean");

  8.        System.out.println("calling m...");

  9.        System.out.println(e.m());

  10.        System.out.println("calling k...");

  11.        System.out.println(e.k());

  12.    }

  13. }  

`Output:

 
   
   
 
  1. calling m...  

  2. m() method invoked  

  3. additional concern  

  4. Method Signature: int com.javatpoint.Operation.m()  

  5. Result in advice: 2  

  6. end of after returning advice...  

  7. 2  

  8. calling k...  

  9. k() method invoked  

  10. additional concern  

  11. Method Signature: int com.javatpoint.Operation.k()  

  12. Result in advice: 3  

  13. end of after returning advice...  

  14. 3  

`4) aop:around 示例

在调用实际业务逻辑方法之前和之后应用 AspectJaround advice

创建一个包含实际业务逻辑的类。

文件:Operation.java

 
   
   
 
  1. package com.javatpoint;

  2. public class Operation {

  3.    public void msg() {

  4.        System.out.println("msg() is invoked");

  5.    }

  6.    public void display() {

  7.        System.out.println("display() is invoked");

  8.    }

  9. }  

在advice方法中传递 PreceedingJoinPoint引用,以便我们可以通过调用 proceed()方法来继续请求。

文件:TrackOperation.java

 
   
   
 
  1. package com.javatpoint;

  2. import org.aspectj.lang.ProceedingJoinPoint;

  3. public class TrackOperation {

  4.    public Object myadvice(ProceedingJoinPoint pjp) throws Throwable {

  5.        System.out.println("Additional Concern Before calling actual method");

  6.        Object obj = pjp.proceed();

  7.        System.out.println("Additional Concern After calling actual method");

  8.        return obj;

  9.    }

  10. }  

File: applicationContext.xml

 
   
   
 
  1. <?xml version="1.0" encoding="UTF-8"?>

  2. <beans xmlns="http://www.springframework.org/schema/beans"

  3.       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

  4.       xmlns:aop="http://www.springframework.org/schema/aop"

  5.       xsi:schemaLocation="http://www.springframework.org/schema/beans  

  6.    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  

  7.    http://www.springframework.org/schema/aop  

  8.    http://www.springframework.org/schema/aop/spring-aop-3.0.xsd ">

  9.    <aop:aspectj-autoproxy />

  10.    <bean id="opBean" class="com.javatpoint.Operation">   </bean>

  11.    <bean id="trackAspect" class="com.javatpoint.TrackOperation"></bean>

  12.    <aop:config>

  13.        <aop:aspect id="myaspect" ref="trackAspect" >

  14.            <!-- @Around -->

  15.            <aop:pointcut id="pointCutAround"   expression="execution(* com.javatpoint.Operation.*(..))" />

  16.            <aop:around method="myadvice" pointcut-ref="pointCutAround" />

  17.        </aop:aspect>

  18.    </aop:config>

  19. </beans>  

File: Test.java

 
   
   
 
  1. package com.javatpoint;

  2. import org.springframework.context.ApplicationContext;

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

  4. public class Test {

  5.    public static void main(String[] args) {

  6.        ApplicationContext context = new classPathXmlApplicationContext("applicationContext.xml");

  7.        Operation op = (Operation) context.getBean("opBean");

  8.        op.msg();

  9.        op.display();

  10.    }

  11. }  

Output

 
   
   
 
  1. Additional Concern Before calling actual method  

  2. msg() is invoked  

  3. Additional Concern After calling actual method  

  4. Additional Concern Before calling actual method  

  5. display() is invoked  

  6. Additional Concern After calling actual method  

5) aop:after-throwing 示例

通过使用 afterthrowadvice,我们可以在 TrackOperation类中打印异常。让我们看看AspectJ在抛出advice之后的例子。

File: Operation.java

 
   
   
 
  1. package com.javatpoint;

  2. public class Operation {

  3.    public void validate(int age) throws Exception {

  4.        if (age < 18) {

  5.            throw new ArithmeticException("Not valid age");

  6.        } else {

  7.            System.out.println("Thanks for vote");

  8.        }

  9.    }

  10. }  

File: TrackOperation.java

 
   
   
 
  1. package com.javatpoint;

  2. import org.aspectj.lang.JoinPoint;

  3. public class TrackOperation {

  4.    public void myadvice(JoinPoint jp, Throwable error)//it is advice  

  5.    {

  6.        System.out.println("additional concern");

  7.        System.out.println("Method Signature: " + jp.getSignature());

  8.        System.out.println("Exception is: " + error);

  9.        System.out.println("end of after throwing advice...");

  10.    }

  11. }  

`` File: applicationContext.xml

 
   
   
 
  1. <?xml version="1.0"encoding="UTF-8"?>

  2. <beans xmlns="http://www.springframework.org/schema/beans"

  3.       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

  4.       xmlns:aop="http://www.springframework.org/schema/aop"

  5.       xsi:schemaLocation="http://www.springframework.org/schema/beans  

  6.        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  

  7.        http://www.springframework.org/schema/aop  

  8.        http://www.springframework.org/schema/aop/spring-aop-3.0.xsd ">

  9.    <aop:aspectj-autoproxy/>

  10.    <bean id="opBean" class="com.javatpoint.Operation"></bean>

  11.    <bean id="trackAspect" class="com.javatpoint.TrackOperation"></bean>

  12.    <aop:config>

  13.        <aop:aspect id="myaspect" ref="trackAspect">

  14.            <!--@AfterThrowing -->

  15.            <aop:pointcut id="pointCutAfterThrowing" expression="execution(* com.javatpoint.Operation.*(..))"/>

  16.            <aop:after-throwing method="myadvice" throwing="error" pointcut-ref="pointCutAfterThrowing"/>

  17.        </aop:aspect>

  18.    </aop:config>

  19. </beans>  

File: Test.java

 
   
   
 
  1. package com.javatpoint;

  2. import org.springframework.context.ApplicationContext;

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

  4. public class Test {

  5.    public static void main(String[] args) {

  6.        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

  7.        Operation op = (Operation) context.getBean("opBean");

  8.        System.out.println("calling validate...");

  9.        try {

  10.            op.validate(19);

  11.        } catch (Exception e) {

  12.            System.out.println(e);

  13.        }

  14.        System.out.println("calling validate again...");

  15.        try {

  16.            op.validate(11);

  17.        } catch (Exception e) {

  18.            System.out.println(e);

  19.        }

  20.    }

  21. }  

Output :

 
   
   
 
  1. calling validate...  

  2. Thanks for vote  

  3. calling validate again...  

  4. additional concern  

  5. Method Signature: void com.javatpoint.Operation.validate(int)  

  6. Exception is: java.lang.ArithmeticException: Not valid age  

  7. end of after throwing advice...  

  8. java.lang.ArithmeticException: Not valid age  


END  

以上是关于第三章 : 面向切面编程(AOP)的主要内容,如果未能解决你的问题,请参考以下文章

Java——面向切面编程,Spring中的AOP编程

AOP面向切面编程

AOP 面向切面编程

AOP面向切面编程

Spring的AOP面向切面编程

面向切面编程