AspectJ AOP学习基础

Stella981
• 阅读 530

一、切入点表达式

  1、execution:匹配方法的执行

    格式:execution(修饰符 返回值类型 包.类.方法(参数) throw 异常)

      1.1修饰符,表示方法的修饰符,一般省略。

      1.2返回类型 String表示返回String;void表示没有返回值;*表示返回任意类型,包括无返回值。

      1.3包

        hjp.spring.service 表示指定的包

        hjp.spring.*.service 表示spring下子模块包含service的包

        hjp.spring.service.. 表示service目录及其子目录

        综合:hjp.spring.*.service..

      1.4类 UserService表示指定的类;*Service表示以Service结尾;Test*表示以Test开头;*表示任意类名。

      1.5方法(与类相似)

        addUser表示指定方法;add*表示以add开头;*Do表示以Do结尾;*表示任意。

      1.6参数 ()表示没有参数;(int)表示一个int类型参数;(int,int)表示两个int类型参数(如果是java.lang包下的可以省略,其他类型必须写完全限定类名);(..)表示

          任意,包括无参。

      1.7throws 异常,一般省略。

  综合:execution(* hjp.spring.*.service..*.*(..))

2、within:匹配包或子包中的方法,如:within(hjp.spring.service..*)

3、this:匹配实现接口的代理对象中的方法,如:this(hjp.spring.dao.UserDao)

4、target:匹配实现接口的目标对象中的方法,如:target(hjp.spring.daoImpl.UserDao)

5、args:匹配参数格式符合标准的方法,如args(int,int)

6、bean:匹配指定的bean,如:bean("userServiceId")

二、AspectJ规定的通知类型

1、before:前置通知(应用:各种校验),在方法执行前执行,如果通知抛出异常,阻止方法运行。

2、afterReturning:后置通知(应用:常规数据处理),方法正常返回后执行,如果方法中抛出异常,通知无法执行;在方法执行后执行,所以才可以获得方法的返回值。

3、around:环绕通知(应用:可以做任何事),方法执行前后分别执行,可以阻止方法的执行。

4、afterThrowing:抛出异常通知(应用:包装异常信息),方法抛出异常后执行,如果方法没有抛出异常,无法执行。

5、after:最终通知(应用:清理现场),方法执行完毕后执行,无论方法是否有异常出现。

  环绕通知类似代码块:  

AspectJ AOP学习基础 AspectJ AOP学习基础

try{
//前置通知(before)
//手动执行目标方法
//后置通知(after),可获得返回值
}catch{
//抛出异常通知(afterThrowing),可获得具体异常信息
}finally{
//最终(finally)
}

环绕通知类似代码块

 三、基于XML配置的代码示例

1、代码结构:

AspectJ AOP学习基础

2、aspectj aop不是针对接口的,所有有没有接口不影响AOP实现,下面是UserService接口和UserServiceImpl实现类(目标类)代码

AspectJ AOP学习基础 AspectJ AOP学习基础

package hjp.springAOP.springAspectJXml;

public interface UserService {
    void addUser();

    void updateUser();
}

UserService

AspectJ AOP学习基础 AspectJ AOP学习基础

package hjp.springAOP.springAspectJXml;

public class UserServiceImpl implements UserService {

    @Override
    public void addUser() {
        // TODO Auto-generated method stub
        System.out.println("aspectj xml add user");
    }

    @Override
    public void updateUser() {
        // TODO Auto-generated method stub
        //int i=9/0;
        System.out.println("aspectj xml update user");
    }

}

UserServiceImpl

3、切面类MyAspect代码

AspectJ AOP学习基础 AspectJ AOP学习基础

package hjp.springAOP.springAspectJXml;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;

public class MyAspect {
    public void myBefore(JoinPoint joinPoint) {
        System.out.println("前置通知:" + joinPoint.getSignature().getName());
    }

    public void myAfterReturning(JoinPoint joinPoint, Object ret) {
        System.out.println("后置通知:方法名," + joinPoint.getSignature().getName() + ";返回值," + ret);
    }

    public Object myAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("环绕通知前");
        // 手动执行目标方法
        Object object = proceedingJoinPoint.proceed();
        System.out.println("环绕通知后");
        return object;
    }

    public void myAfterThrowing(JoinPoint joinPoint, Throwable e) {
        System.out.println("目标类方法" + joinPoint.getSignature().getName() + "抛出异常:" + e.getMessage());
    }

    public void myAfter(JoinPoint joinPoint) {
        System.out.println("最终执行通知:方法:" + joinPoint.getSignature().getName());
    }
}

MyAspect

4、beans.xml配置文件,记得添加aop命名空间和引用地址

AspectJ AOP学习基础 AspectJ 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.xsd
                              http://www.springframework.org/schema/aop 
                              http://www.springframework.org/schema/aop/spring-aop.xsd">
    <!-- 1、创建目标类 -->
    <bean id="userServiceId" class="hjp.springAOP.springAspectJXml.UserServiceImpl"></bean>
    <!-- 2、创建切面类 (通知) -->
    <bean id="myAspectId" class="hjp.springAOP.springAspectJXml.MyAspect"></bean>
    <!-- aop编程
         如果强制使用CGLIB,则设置aop:config 属性proxy-target-class="true"
     -->
    <aop:config>
        <!-- aspectj 编程
             ref指向切面类 -->
        <aop:aspect ref="myAspectId">
            <!-- 声明切入点,确定目标类上哪些方法需被增强 -->
            <aop:pointcut expression="execution(* hjp.springAOP.springAspectJXml.*.*(..))" id="myPointCut" />
            <!-- 声明通知方式 -->
            <!-- 1、前置通知
                 method切面类中具体方法名
                 pointcut-ref指向切入点(使用pointcut,也可以在通知里配置自己的切入点表达式)
            <aop:before method="myBefore" pointcut-ref="myPointCut"/>
             -->
             <!-- 2、后置通知,可获取到返回值
                   returning用于设置通知的第二个参数名称,类型为Object(注意:此处参数名称要与切面类后置通知方法第二个参数名称一致)
             <aop:after-returning method="myAfterReturning" pointcut-ref="myPointCut" returning="ret"/>
              -->
              <!-- 3、环绕通知                     
              <aop:around method="myAround" pointcut-ref="myPointCut"/>
               -->
               <!-- 4、抛出异常通知(测试此通知时,将目标类中updateUser方法中int i=9/0;代码注释去掉)
                       目标方法在抛出异常时执行,如果没有则不执行
                       throwing设置抛出异常通知的第二个参数,参数名称和此处设置的e一致,类型Throwable        
                <aop:after-throwing method="myAfterThrowing" pointcut-ref="myPointCut" throwing="e"/>
                -->
                <!-- 5、最终通知,即任何情况下都会执行 -->
                <aop:after method="myAfter" pointcut-ref="myPointCut"/>
        </aop:aspect>
    </aop:config>
</beans>

beans.xml

5、测试类

AspectJ AOP学习基础 AspectJ AOP学习基础

package hjp.springAOP.springAspectJXml;

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

public class TestApp {
    @Test
    public void demo1() {
        String xmlPath="hjp/springAOP/springAspectJXml/beans.xml";
        ApplicationContext applicationContext=new ClassPathXmlApplicationContext(xmlPath);
        UserService userService = (UserService)applicationContext.getBean("userServiceId");
        userService.addUser();
        userService.updateUser();
    }
}

测试类

 四、基于注解的代码示例

1、代码结构和上面差不多

AspectJ AOP学习基础

2、目标类的接口代码不变,目标类加注解后代码:

AspectJ AOP学习基础 AspectJ AOP学习基础

package hjp.springAOP.springAspectJAnnotation;

import org.springframework.stereotype.Service;

@Service("userServiceId")//<bean id="userServiceId" class="hjp.springAOP.springAspectJAnnotation.UserServiceImpl"></bean>
public class UserServiceImpl implements UserService {

    @Override
    public void addUser() {
        // TODO Auto-generated method stub
        System.out.println("aspectj xml add user");
    }

    @Override
    public void updateUser() {
        // TODO Auto-generated method stub
        //int i=9/0;
        System.out.println("aspectj xml update user");
    }

}

目标类

3、切面类加注解后代码(注意:代码里面使用了引用公共切入点表达式的方法):

AspectJ AOP学习基础 AspectJ AOP学习基础

package hjp.springAOP.springAspectJAnnotation;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Component//<bean id="myAspectId" class="hjp.springAOP.springAspectJAnnotation.MyAspect"></bean>
@Aspect//<aop:aspect ref="myAspectId">
public class MyAspect {
    //@Before("execution(* hjp.springAOP.springAspectJAnnotation.*.*(..))")//<aop:before method="myBefore" pointcut="myPointCut"/>
    public void myBefore(JoinPoint joinPoint) {
        System.out.println("前置通知:" + joinPoint.getSignature().getName());
    }
    //@AfterReturning(value="execution(* hjp.springAOP.springAspectJAnnotation.*.*(..))",returning="ret")
    public void myAfterReturning(JoinPoint joinPoint, Object ret) {
        System.out.println("后置通知:方法名," + joinPoint.getSignature().getName() + ";返回值," + ret);
    }
    //编写共有的切入点表达式
    @Pointcut("execution(* hjp.springAOP.springAspectJAnnotation.*.*(..))")
    private void myPointCut(){}
    //@Around("myPointCut()")//注意加括号
    public Object myAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("环绕通知前");
        // 手动执行目标方法
        Object object = proceedingJoinPoint.proceed();
        System.out.println("环绕通知后");
        return object;
    }
    //@AfterThrowing(value="myPointCut()",throwing="e")
    public void myAfterThrowing(JoinPoint joinPoint, Throwable e) {
        System.out.println("目标类方法" + joinPoint.getSignature().getName() + "抛出异常:" + e.getMessage());
    }
    @After("myPointCut()")
    public void myAfter(JoinPoint joinPoint) {
        System.out.println("最终执行通知:方法:" + joinPoint.getSignature().getName());
    }
}

切面类

4、beans.xml配置文件,注意新加context和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"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
                              http://www.springframework.org/schema/beans/spring-beans.xsd
                              http://www.springframework.org/schema/aop 
                              http://www.springframework.org/schema/aop/spring-aop.xsd
                              http://www.springframework.org/schema/context 
                              http://www.springframework.org/schema/context/spring-context.xsd">
    <!-- spring注解扫描 -->
    <context:component-scan base-package="hjp.springAOP.springAspectJAnnotation"></context:component-scan>
    <!-- 使AOP注解生效 -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

5、测试类

AspectJ AOP学习基础 AspectJ AOP学习基础

package hjp.springAOP.springAspectJAnnotation;

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

public class TestApp {
    @Test
    public void demo1() {
        String xmlPath="hjp/springAOP/springAspectJAnnotation/beans.xml";
        ApplicationContext applicationContext=new ClassPathXmlApplicationContext(xmlPath);
        UserService userService = (UserService)applicationContext.getBean("userServiceId");
        userService.addUser();
        userService.updateUser();
    }
}

测试类

3、

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Wesley13 Wesley13
2年前
java常用类(2)
三、时间处理相关类Date类:计算机世界把1970年1月1号定为基准时间,每个度量单位是毫秒(1秒的千分之一),用long类型的变量表示时间。Date分配Date对象并初始化对象,以表示自从标准基准时间(称为“历元”(epoch),即1970年1月1日08:00:00GMT)以来的指定毫秒数。示例:packagecn.tanjian
Wesley13 Wesley13
2年前
mysql中时间比较的实现
MySql中时间比较的实现unix\_timestamp()unix\_timestamp函数可以接受一个参数,也可以不使用参数。它的返回值是一个无符号的整数。不使用参数,它返回自1970年1月1日0时0分0秒到现在所经过的秒数,如果使用参数,参数的类型为时间类型或者时间类型的字符串表示,则是从1970010100:00:0
Wesley13 Wesley13
2年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Stella981 Stella981
2年前
HIVE 时间操作函数
日期函数UNIX时间戳转日期函数: from\_unixtime语法:   from\_unixtime(bigint unixtime\, string format\)返回值: string说明: 转化UNIX时间戳(从19700101 00:00:00 UTC到指定时间的秒数)到当前时区的时间格式举例:hive   selec
Stella981 Stella981
2年前
Smali语法学习二
方法签名methodName(III)Lpackage/name/Object;methodName表示方法名,\\(III)\\表示该方法有三个int型参数,Lpackage/name/Object表示方法返回类型。方法的表示Lpackage/name/Object;—methodName(III)Z
Wesley13 Wesley13
2年前
Java 中的方法
定义一个方法的语法是:访问修饰符 返回值类型 方法名(参数列表){方法体;}其中:1、访问修饰符:方法允许被访问的权限范围,可以是public、protected、private甚至可以省略 ,其中public表示该方法可以被其他任何代码调用, protected只有子类可用, pr
Wesley13 Wesley13
2年前
JAVA自学笔记05
JAVA自学笔记051、方法1)方法就是完成特定功能的代码块,类似C语言中的函数。2)格式:修饰符返回值类型方法名(参数类型参数名1,参数类型参数名2,…){函数体;return返回值;}①修饰符:对于初学者使用publicstatic②返回值类型:方法结果的类型③方
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
3个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这