【Spring】Spring的AspectJ的AOP

Spring学习笔记(10)Spring的AspectJ的AOP

在Spring中使用AspectJ实现AOP

  • AspectJ 是一个面向切面的框架, 它扩展了 Java 语言。 AspectJ 定义了 AOP 语法所以它有一个专门的编译器用来生成遵守 Java 字节编码规范的 Class 文件。
  • AspectJ 是一个基于 Java 语言的 AOP 框架
  • Spring2.0 以后新增了对 AspectJ 切点表达式支持
  • @AspectJ 是 AspectJ1.5 新增功能, 通过 JDK5 注解技术, 允许直接在 Bean 类中定义切面
  • 新版本 Spring 框架, 建议使用 AspectJ 方式来开发 AOP

AspectJ 表达式

那些类允许增强的表达式

语法:execution(表达式)
execution(<访问修饰符>?<返回类型><方法名>(<参数>)<异常>)
[*代表方法的返回值为任意类型] [*代表所有方法] [..代表任意参数类型]

  • execution(* cn.itcast.spring3.demo1.dao.*(..)) —只检索当前包

  • execution(* cn.itcast.spring3.demo1.dao..*(..)) —检索包及当前包的子包.

  • execution(* cn.itcast.dao.GenericDAO+.*(..)) —检索 GenericDAO 及子类

  • 匹配所有类 public 方法 execution(public * *(..))

  • 匹配指定包下所有类方法 execution(* cn.itcast.dao.*(..)) 不包含子包

  • execution(* cn.itcast.dao..*(..)) ..*表示包、 子孙包下所有类

  • 匹配指定类所有方法 execution(*cn.itcast.service.UserService.*(..))

  • 匹配实现特定接口所有类方法execution(*cn.itcast.dao.GenericDAO+.*(..))

  • 匹配所有 save 开头的方法 execution(* save*(..))

AspectJ 增强

@Before 前置通知, 相当于 BeforeAdvice
@AfterReturning 后置通知, 相当于 AfterReturningAdvice
@Around 环绕通知, 相当于 MethodInterceptor
@AfterThrowing 抛出通知, 相当于 ThrowAdvice
@After 最终 final 通知, 不管是否异常, 该通知都会执行
@DeclareParents 引介通知, 相当于 IntroductionInterceptor

基于注解

1.引入jar包

  • pom.xml
<dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>${spring.version}</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-test</artifactId>
      <version>${spring.version}</version>
    </dependency>
    <!--解析切入点表达式-->
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.9.4</version>
    </dependency>

2.编写增强的类

  • UserDao
@Repository(value = "userDao") //注解的方式,spring管理对象的创建
public class UserDao {
    public void add(){
        System.out.println("添加用户");
    }
    public void addInfo(){
        System.out.println("添加用户信息");
    }
    public void update(){
        System.out.println("更新用户");
    }
    public void delete(){
        System.out.println("删除用户");
    }
    public void find(){
        System.out.println("查找用户");
    }
}

3.使用AspectJ注解形式

  • MyAspectJ
@Component // 注解的方式,spring管理对象的创建
@Aspect  // 用来定义且切面
public class MyAspectJ {
    /**
     * 前置通知
     * 对UserDao里面的以add方法进行增强
     * @param joinPoint
     */
    @Before("execution(* club.krislin.Dao.UserDao.add*(..))")
    public void before(JoinPoint joinPoint){
        //打印的是切点信息
        System.out.println(joinPoint);
        System.out.println("前置增强");
    }

    /**
     * 后置通知
     * 对update开头的方法进行增强
     * @param returnValue
     */
    @AfterReturning(value = "execution(* club.krislin.Dao.UserDao.update*(..))",returning = "returnValue") // 接受返回值,方法的返回值为任意类型
    public void after(Object returnValue){
        System.out.println("后置通知");
        System.out.println("方法的返回值为:"+returnValue);
    }

    /**
     * 环绕通知增强
     * 对以find开头的方法进行增强
     * @param proceedingJoinPoint
     * @return
     * @throws Throwable
     */
    @Around(value = "execution(* club.krislin.Dao.UserDao.find*(..))")
    public Object arount(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("环绕通知增强-----前");
        // 执行目标方法
        Object obj = proceedingJoinPoint.proceed();
        System.out.println("环绕通知增强-----后");
        return obj;
    }

    /**
     * 异常通知增强
     * 对以find开头的方法进行增强
     * @param e
     */
    @AfterThrowing(value = "execution(* club.krislin.Dao.UserDao.find(..))",throwing = "e")
    public void afterThrowing(Throwable e){
        System.out.println("出现异常"+e.getMessage());
    }

    @After(value = "execution(* club.krislin.Dao.UserDao.find(..))")
    public void after(){
        System.out.println("最终通知");
    }
}

4.配置applicationContext.xml

<!--自动生成代理底层就是 AnnotationAwareAspectJAutoProxyCreator-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

    <context:component-scan base-package="club.krislin"></context:component-scan>

5.测试

  • UserDaoTest
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class UserDaoTest {
    @Resource(name = "userDao")
    private UserDao userDao;

    @Test
    public void testUserDao(){
        userDao.add();
        userDao.addInfo();
        userDao.delete();
        userDao.find();
        userDao.update();
    }
}

基于xml

1.编写被增强的类

  • UserDao
public class UserDao {
    public void add(){
        System.out.println("添加用户");
    }
    public void addInfo(){
        System.out.println("添加用户信息");
    }
    public void update(){
        System.out.println("更新用户");
    }
    public void delete(){
        System.out.println("删除用户");
    }
    public void find(){
        System.out.println("查找用户");
        //int i = 1;
        //int n = i/0;
    }
}

2.编写增强的类

  • MyAspectJ
public class MyAspectJ {
    /**
     * 前置通知
     * @param joinPoint
     */
    public void before(JoinPoint joinPoint){
        //打印的是切点信息
        System.out.println(joinPoint);
        System.out.println("前置增强");
    }

    /**
     * 后置通知
     * @param returnValue
     */
       public void after(Object returnValue){
        System.out.println("后置通知");
        System.out.println("方法的返回值为:"+returnValue);
    }

    /**
     * 环绕通知增强
     * @param proceedingJoinPoint
     * @return
     * @throws Throwable
     */
    public Object arount(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("环绕通知增强-----前");
        // 执行目标方法
        Object obj = proceedingJoinPoint.proceed();
        System.out.println("环绕通知增强-----后");
        return obj;
    }

    /**
     * 异常通知增强
     * @param e
     */
    public void afterThrowing(Throwable e){
        System.out.println("出现异常"+e.getMessage());
    }

    /**
     * 最终通知增强
     */
    public void after(){
        System.out.println("最终通知");
    }
}

3配置applicationContext.xml

<!--定义被增强的类-->
    <bean name="userDao" class="club.krislin.Dao.UserDao"></bean>
    <!--定义切面类-->
    <bean name="myAspectJ" class="club.krislin.MyAspectJ"></bean>

    <!--定义aop配置-->
    <aop:config>
        <!--定义哪些方法上使用增强-->
        <aop:pointcut expression="execution(* club.krislin.Dao.UserDao.add*(..))" id="myPointcut"/>

        <aop:pointcut expression="execution(* club.krislin.Dao.UserDao.add(..))" id="myPointcut1"/>

        <aop:aspect ref="myAspectJ">
            <!--在add开头的方法上采用前置通知-->
            <aop:before method="before" pointcut-ref="myPointcut"/>
        </aop:aspect>
        <aop:aspect ref="myAspectJ">
            <!--后置通知-->
            <aop:after-returning method="after" pointcut-ref="myPointcut" returning="returnValue"/>
        </aop:aspect>
        <aop:aspect ref="myAspectJ">
            <!--环绕通知-->
            <aop:around method="arount" pointcut-ref="myPointcut"/>
        </aop:aspect>
        <aop:aspect ref="myAspectJ">
            <!--异常通知-->
            <aop:after-throwing method="afterThrowing" pointcut-ref="myPointcut" throwing="e"/>
        </aop:aspect>
        <aop:aspect ref="myAspectJ">
            <!--最终通知-->
            <aop:after method="after" pointcut-ref="myPointcut1"/>
        </aop:aspect>
    </aop:config>

4.测试

  • UsetDaoTest
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class UserDaoTest {
    @Resource(name = "userDao")
    private UserDao userDao;

    @Test
    public void testUserDao(){
        userDao.add();
        userDao.addInfo();
        userDao.delete();
        userDao.update();
        userDao.find();
    }
}

xml方式的AOP配置步骤

1.配置被增强的类和通知(即增强方法)

2.使用aop:config声明aop配置

aop:config 用于声明开始aop的配置

<aop:config>
    <!-- 配置的代码都写在此处 -->
</aop:config>

3.使用aop:aspect配置切面

aop:aspect 用于配置切面
属性: id:给切面提供一个唯一的表示
ref:引用配置好的通知类bean的id

<aop:aspect id="txAdvice" ref="txManager">
    <!--配置通知的类型要写在此处-->
</aop:aspect>

4.使用aop:pointcut配置切入点表达式

aop:pointcut 用于配置切入点表达式.就是指定对哪些类的哪些方法进行增强
属性: expression:由于定义切入表达式
id:用于给切入点表达式提供唯一的标识

<aop:pointcut expression="execution(* club.krislin.Dao.UserDao.add*(..))" id="myPointcut"/>

5.使用aop:xxx配置对应的通知类型

aop:before 用于配置前置通知.指定增强的方法在切入点方法之前执行
属性: method:用于指定通知类中的增强方法名称
pointcut-ref:用于指定切入点表达式的引用
pointcut:用于指定切入点表达式
执行时间: 切入点方法执行之前

<aop:before method="before" pointcut-ref="myPointcut"/>

aop:after-returning 用于配置后置通知
属性: method:用于指定通知类中的增强方法名称
pointcut-ref:用于指定切入点表达式的引用
pointcut:用于指定切入点表达式
returning:后置通知返回值
执行时间:切入点方法正常执行之后,它和异常通知只能有一个执行

 <aop:after-returning method="after" pointcut-ref="myPointcut" returning="returnValue"/>

aop:after-throwing 用于配置异常通知
属性: method:用于指定通知类中的增强方法名称
pointcut-ref:用于指定切入点表达式的引用
pointcut:用于指定切入点表达式
throwing:指定抛出的异常
执行时间:切入点方法执行异常后执行,它和后置通知只能有一个执行

<aop:after-throwing method="afterThrowing" pointcut-ref="myPointcut" throwing="e"/>

aop:after: 用于配置最终通知
属性: method:用于指定通知类中的增强方法名称
pointcut-ref:用于指定切入点表达式的引用
pointcut:用于指定切入点表达式
执行时间:无论切入点方法执行时是否异常,它都会在后面执行

<aop:after method="after" pointcut-ref="myPointcut1"/>

aop:around 用于配置环绕通知
属性: method:用于指定通知类中的增强方法名称
pointcut-ref:用于指定切入点表达式的引用
pointcut:用于指定切入点表达式

<aop:around method="arount" pointcut-ref="myPointcut"/>

Advisor 和 Aspect 的区别?(都叫切面)

  • Advisor:Spring 传统意义上的切面:支持一个切点和一个通知的组合.
  • Aspect:可以支持多个切点和多个通知的组合.
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

攻城狮·建哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值