使用AspectJ进行AOP开发

在普通AOP开发中,有几个通知,就要建几个类,很麻烦,如果能将这些通知类全浓缩到一个类中,会方便许多,因此可以使用AspectJ进行Aop开发。

AspectJ介绍

AspectJ是一个基于Java语言的AOP框架,Spring2.0 开始引入对AspectJ的支持,AspectJ扩展了Java语言,提供了专门的编译器,在编译时提供了横向代码的注入。
@AspectJ是AspectJ1.5新增功能,通过JDK1.5注解技术,允许直接在Bean中定义切面
新版本的Spring中,建议使用AspectJ方式开发AOP
AspectJ开发的两种方式:

  1. 基于xml配置文件方式开发
  2. 基于注解方式开发
    开发前的准备:
    在进行开发前需要导入jar包
    在这里插入图片描述

1. 基于xml配置文件方式开发

创建一个目标类Man.java

public class Man {
     public void eat() {
          System.out.println("喝酒");
     }
}

创建一个切面类,切面类中有各种通知,其方法名可以随意定义,只要在配置文件中对应即可;
此处要注意,环绕通知的方法需要传入一个ProceedingJoinPoint对象,这个对象的作用是执行目标对象的方法的执行;
异常通知的方法需要传入一个Throwable对象,用于接收目标对象执行时抛出的异常,从而执行这个通知的功能;切面类的创建如下

public class MyAdvice {
     /*
      * 前置通知
      */
     public void beforeAdvice() {
          System.out.println("抽烟");
     }

     /**
      * 后置通知
      */
     public void afterAdvice() {
          System.out.println("烫头");
     }

     /**
      * 环绕通知
      * @param jp
      * @throws Throwable
      */
     public void arroundAdvice(ProceedingJoinPoint jp) throws Throwable {
          System.out.println("抽烟");
          jp.proceed(); // 执行目标方法
         System.out.println("烫头");
     }

     /**
      * 异常通知
      * @param tw
      */
     public void exceptionAdvice(Throwable tw) {
          System.out.println("====发生了异常=====");
     }
 }

切面类创建好了,接下来需要配置applicationContext.xml文件,先要声明目标对象和切面对象,声明后在aop:config标签内写切入点标签,以及各个通知的标签;需要注意的是:

  1. 与普通AOP开发不同的是,AspectJ开发中,切入点标签和各个通知的标签是写在aop:config标签内的 aop:aspect内的;
  2. aop:aspect标签的ref属性的值指向切面对象,与切面对象的id的值一致
  3. 通知标签中, aop:before表示前置通知、 aop:after表示后置通知、aop:around表示环绕通知、aop:after-throwing表示异常通知
  4. 异常通知标签aop:after-throwing中必须添加throwing属性,其值必须与切面类中的异常通知方法传入的参数名一致;
    配置方法如下
<bean id="man" class="com.sxt.bean.Man"></bean>

<bean id="myAdvice" class="com.sxt.bean.MyAdvice"></bean>

<aop:config>
     <aop:aspect ref="myAdvice">
          <!-- 配置切入点 -->
          <aop:pointcut expression="execution(* com.sxt.bean.Man.*())" id="pc"/>
          <!-- 配置切面方法 -->
          <aop:before method="beforeAdvice" pointcut-ref="pc"/>

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

          <aop:around method="arroundAdvice" pointcut-ref="pc"/>

          <aop:after-throwing method="exceptionAdvice" pointcut-ref="pc" throwing="tw"/>
     </aop:aspect>
</aop:config>

测试:

public class Test {
	public static void main(String[] args) {
		ApplicationContext app = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
		Man bean = app.getBean(Man.class);
		bean.eat();
	}
}

2. 基于注解方式开发

创建一个目标类Man.java,每一个注解中的都要声明切入点,例如 @Before(“execution(* com.sxt.bean.Man.*())”),异常注解中的throwing的值必须与参数名称一致

public class Man {
     public void eat() {
          System.out.println("喝酒");
     }
}

在切面类上加入注解

@Component // 让Spring的IOC容器创建对象
@Aspect // 表示是一个切面类
public class MyAdvice {
     /*
      * 前置通知
     */

     @Before("execution(* com.sxt.bean.Man.*())")
    public void beforeAdvice() {
          System.out.println("抽烟");
     }

     /**
      * 后置通知
      */
     @After("execution(* com.sxt.bean.Man.*())")
     public void afterAdvice() {
          System.out.println("烫头");
     }

     /**
      * 环绕通知
      * @param jp
      * @throws Throwable
      */
     @Around("execution(* com.sxt.bean.Man.*())")
     public void arroundAdvice(ProceedingJoinPoint jp) throws Throwable {
          System.out.println("抽烟");
          jp.proceed();
          System.out.println("烫头");
     }

     /**
     * 异常通知
      * @param tw
      */
     @AfterThrowing(value="execution(* com.sxt.bean.Man.*())",throwing="tw")
     public void exceptionAdvice(Throwable tw) {
          System.out.println("====发生了异常=====");
     }
 }

配置xml文件的思路
有了切面类,切面类上有@componet注解,在applicationContext.xml文件中可以不声明切面类对象,但是要声明目标类对象;
因为使用了注解,所以在xml文件中需要扫描注解;
扫描到注解后需要解析,所以还需要开启用于解析的标签;
按照这个思路,我们可以写出正确的xml文件

<!--声明目标对象-->
<bean id="man" class="com.sxt.bean.Man"></bean>
<!--开启AOP的自动代理,Spring框架会解析切面注解-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
<!---开启注解扫描-->
<context:component-scan base-package="com.sxt.bean"></context:component-scan>

由切面类的代码可以发现,每个通知的切入点都一样,要写很多重复的代码,那么可不可以用一个什么东西来代替这个切入点呢?
答案是肯定的,如果在切面类中声明切入点,就可以达到想要的效果,具体代码实现如下

@Component
@Aspect
public class MyAdvice {

     /**
      * 声明切入点
      */

     @Pointcut("execution(* com.sxt.bean.Man.*())")
     public void p() {
     }

     /*
      * 前置通知
      */
     @Before(value="p()") // 使用切入点注解注释的方法名代替冗长的切入点
     public void beforeAdvice() {
         System.out.println("抽烟");
     }

     /**
      * 后置通知
      */
     @After(value="p()")
     public void afterAdvice() {
          System.out.println("烫头");
     }

     /**
      * 环绕通知
      * @param jp
      * @throws Throwable
      */
     @Around(value="p()")
     public void arroundAdvice(ProceedingJoinPoint jp) throws Throwable {
          System.out.println("抽烟");
          jp.proceed();
          System.out.println("烫头");
     }    

     /**
      * 异常通知
      * @param tw
      */
     @AfterThrowing(value="p()",throwing="tw")
     public void exceptionAdvice(Throwable tw) {
          System.out.println("====发生了异常=====");
     }
 }

除此之外,还有更骚的操作,有一种注解,叫做@EnableAspectJAutoProxy,它的意思是开启切面的注解配置。
简单来说,只要它注释在切面类上,xml文件中就不需要写开启AOP自动代理的标签了,也就是下面这个标签。

<!--开启AOP的自动代理,Spring框架会解析切面注解-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值