• Spring AOP AspectJ


    本文讲述使用AspectJ框架实现Spring AOP。

    再重复一下Spring AOP中的三个概念,

    1. Advice:向程序内部注入的代码。
    2. Pointcut:注入Advice的位置,切入点,一般为某方法。
    3. Advisor:Advice和Pointcut的结合单元,以便将Advice和Pointcut分开实现灵活配置。

    AspectJ是基于注释(Annotation)的,所以需要JDK5.0以上的支持。

    AspectJ支持的注释类型如下:

    1. @Before
    2. @After
    3. @AfterReturning
    4. @AfterThrowing
    5. @Around

    首先定义一个简单的bean,CustomerBo实现了接口ICustomerBo

    ICustomerBo.java如下:

    复制代码
    package com.lei.demo.aop.aspectj;
    
    public interface ICustomerBo {
        void addCustomer();
        void deleteCustomer();
        String AddCustomerReturnValue();
        void addCustomerThrowException() throws Exception;
        void addCustomerAround(String name);
    
    }
    复制代码

     CustomerBo.java如下:

    复制代码
    package com.lei.demo.aop.aspectj;
    
    public class CustomerBo implements ICustomerBo {
    
        public void addCustomer() {
            System.out.println("addCustomer() is running ...");
        }
        
        public void deleteCustomer() {
            System.out.println("deleteCustomer() is running ...");
        }
    
        public String AddCustomerReturnValue() {
            System.out.println("AddCustomerReturnValue() is running ...");
            return "abc";
        }
    
        public void addCustomerThrowException() throws Exception {
            System.out.println("addCustomerThrowException() is running ...");
            throw new Exception("Generic Error");
        }
    
        public void addCustomerAround(String name) {
            System.out.println("addCustomerAround() is running ,args:"+name);
    
        }
    
    }
    复制代码

    一、      简单的AspectJ,Advice和Pointcut结合在一起

    首先没有引入Pointcut之前,Advice和Pointcut是混在一起的

    步骤,只需要两步,如下:

    1. 创建一个Aspect类
    2. 配置Spring配置文件

    第一步,创建Aspect类

    LoggingAspect.java如下:

    复制代码
    package com.lei.demo.aop.aspectj;
    
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.annotation.After;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    
    @Aspect
    public class LoggingAspect {
        
        @Before("execution(public * com.lei.demo.aop.aspectj.CustomerBo.addCustomer(..))")
        public void logBefore(JoinPoint joinPoint){
            System.out.println("logBefore() is running ...");
            System.out.println("hijacked:"+joinPoint.getSignature().getName());
            System.out.println("**********");
        }
        
        @After("execution(public * com.lei.demo.aop.aspectj.CustomerBo.deleteCustomer(..))")
        public void logAfter(JoinPoint joinPoint){
            System.out.println("logAfter() is running ...");
            System.out.println("hijacked:"+joinPoint.getSignature().getName());
            System.out.println("**********");
        }
    }
    复制代码

    解释:

    1.  必须使用@AspectLoggingAspect声明之前注释,以便被框架扫描到

    2.  此例AdvicePointcut结合在一起,类中的具体方法logBeforelogAfter即为Advice,是要注入的代码,Advice方法上的表达式为Pointcut表达式,即定义了切入点,上例中@Before注释的表达式代表执行CustomerBo.addCustomer方法时注入logBefore代码。

    3.  LoggingAspect方法上加入@Before或者@After等注释

    4.  "execution(public * com.lei.demo.aop.aspectj.CustomerBo.addCustomer(..))"Aspect的切入点表达式,其中,*代表返回类型,后边的就要定义要拦截的方法名,这里写的的是com.lei.demo.aop.aspectj.CustomerBo.addCustomer表示拦截CustomerBo中的addCustomer方法,(..)代表参数匹配,此处表示匹配任意数量的参数,可以是0个也可以是多个,如果你确定这个方法不需要使用参数可以直接用(),还可以使用(*)来匹配一个任意类型的参数,还可以使用 (* , String),这样代表匹配两个参数,第二个参数必须是String 类型的参数

    5.  AspectJ表达式,可以对整个包定义,例如,execution(* com.lei.service..*.*(..))表示切入点是com.lei.sevice包中的任意一个类的任意方法,具体的表达式请自行百度。

    第二步,配置Spring配置文件,

    配置Spring-AOP-AspectJ.xml文件,如下:

    复制代码
    <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/>
        
        <bean id="customerBo" class="com.lei.demo.aop.aspectj.CustomerBo"/>
        
        <bean id="logAspect" class="com.lei.demo.aop.aspectj.LoggingAspect" />
        
    </beans>
    复制代码

    解释:

    1.      <aop:aspectj-autoproxy/>启动AspectJ支持,这样Spring会自动寻找用@Aspect注释过的类,其他的配置与spring普通bean配置一样。

    测试:

    执行App.java如下:

    复制代码
    package com.lei.demo.aop.aspectj;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    
    public class App {
        public static void main(String[] args) {
            
            ApplicationContext appContext = new ClassPathXmlApplicationContext(
                    new String[] { "Spring-AOP-AspectJ.xml" });
            ICustomerBo customer=(ICustomerBo)appContext.getBean("customerBo");
            
    customer.addCustomer();
            
            System.out.println("-------------------------------------------");
            
    customer.deleteCustomer();
            
        }
    }
    复制代码

    结果:

    logBefore() is running ...

    hijacked:addCustomer

    **********

    addCustomer() is running ...

    -------------------------------------------

    deleteCustomer() is running ...

    logAfter() is running ...

    hijacked:deleteCustomer

    **********

    二、      将Advice和Pointcut分开

    需要三步,

    1. 创建Pointcut
    2. 创建Advice
    3. 配置Spring的配置文件

    第一步,PointcutsDefinition.java定义了Pointcut,如下:

    复制代码
    package com.lei.demo.aop.aspectj;
    
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Pointcut;
    
    @Aspect
    public class PointcutsDefinition {
    
        @Pointcut("execution(* com.lei.demo.aop.aspectj.CustomerBo.*(..))")
        public void customerLog() {
        }
    }
    复制代码

    解释:

    1. 类声明前加入@Aspect注释,以便被框架扫描到。

    2. @Pointcut是切入点声明,指定需要注入的代码的位置,如上例中指定切入点为CustomerBo类中的所有方法,在实际业务中往往是指定切入点到一个逻辑层,例如 execution (* com.lei.business.service.*.*(..)),表示aop切入点为service包中所有类的所有方法,具体的表达式后边会有介绍。

    3. 方法customerLog是一个签名,在Advice中可以用此签名代替切入点表达式,所以不需要在方法体内编写实际代码,只起到助记功能,例如此处代表操作CustomerBo类时需要的切入点。

    第二步,创建Advice类

    LoggingAspect.java如下:

    复制代码
    package com.lei.demo.aop.aspectj;
    
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.annotation.After;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    
    @Aspect
    public class LoggingAspect {
        
        @Before("com.lei.demo.aop.aspectj.PointcutsDefinition.customerLog()")
        public void logBefore(JoinPoint joinPoint){
            System.out.println("logBefore() is running ...");
            System.out.println("hijacked:"+joinPoint.getSignature().getName());
            System.out.println("**********");
        }
        
    @After("com.lei.demo.aop.aspectj.PointcutsDefinition.customerLog()")
        public void logAfter(JoinPoint joinPoint){
            System.out.println("logAfter() is running ...");
            System.out.println("hijacked:"+joinPoint.getSignature().getName());
            System.out.println("**********");
        }
    }
    复制代码

    注释:

    1.       @Before@After使用PointcutsDefinition中的方法签名代替Pointcut表达式找到相应的切入点,即通过签名找到PointcutsDefinitioncustomerLog签名上的Pointcut表达式,表达式指定切入点为CustomerBo类中的所有方法。所以此例中AdviceLoggingAdvice,为CustomerBo中的所有方法都加入了@Before@After两种类型的两种操作。

    2.       对于PointcutsDefinition来说,主要职责是定义Pointcut,可以在其中第一多个切入点,并且可以用便于记忆的方法签名进行定义。

    3.       单独定义Pointcut的好处是,一是通过使用有意义的方法名,而不是难读的Pointcut表达式,使代码更加直观;二是Pointcut可以实现共享,被多个Advice直接调用。若有多个Advice调用某个Pointcut,而这个Pointcut的表达式在将来有改变时,只需修改一个地方,维护更加方便。

    第三步,配置Spring配置文件,配置文件并没有改变

    配置Spring-AOP-AspectJ.xml文件,如下:

    复制代码
    <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/>
        
        <bean id="customerBo" class="com.lei.demo.aop.aspectj.CustomerBo"/>
        
        <bean id="logAspect" class="com.lei.demo.aop.aspectj.LoggingAspect" />
        
    </beans>
    复制代码

    App.java不变,运行测试代码App.java

    输出结果:

    logBefore() is running ...

    hijacked:addCustomer

    **********

    addCustomer() is running ...

    logAfter() is running ...

    hijacked:addCustomer

    **********

    -------------------------------------------

    logBefore() is running ...

    hijacked:deleteCustomer

    **********

    deleteCustomer() is running ...

    logAfter() is running ...

    hijacked:deleteCustomer

    **********

  • 相关阅读:
    YII2安装中遇到的错误解决Calling unknown method: yiiwebUrlManager::addRules()
    BZOJ 2049: [Sdoi2008]Cave 洞穴勘測 LCT
    【C语言】编写一个函数实现n^k,使用递归实现
    Kivy A to Z -- 怎样从python代码中直接訪问Android的Service
    java并发 使用ScheduledExecutor的温室控制器--thinking in java 21.7.5
    算法之-归并排序算法,插入排序算法
    J2EE之ServletContext读取资源文件
    STOMP 客户端 API 整理
    jQuery easyui datagrid 的数据加载
    扩展struts2的结果集StrutsResultSupport 自定义Result处理JSON
  • 原文地址:https://www.cnblogs.com/chinajava/p/5731326.html
Copyright © 2020-2023  润新知