Spring框架笔记3 ---- AspectJ 对 AOP 的实现

AspectJ 对 AOP 的实现



前言

在 Spring 中使用 AOP 开发时,一般使用 AspectJ 的实现方式

a. AspectJ 中常用的通知有四种类型:

(1)前置通知@Before
(2)后置通知@AfterReturning
(3)环绕通知@Around
(4)最终通知@After

b. AspectJ 的切入点表达式

	(1) execution(访问权限 方法返回值 方法声明(参数) 异常类型)
	(2)符号定义:
	[ * ] : 任意n个字符
	[ . . ]:  用在方法参数中,表任意多个参数; 用在包名后,表当前包及其子路径

c. 实现的步骤:

添加依赖
  1)创建业务接口
  2)创建业务实现
  3)创建切面类,实现切面方法
  4)在applicationContext.xml文件中进行切面绑定

提示:AspectJ 对于 AOP 的实现有注解和配置文件两种方式,常用是注解方式。本文只说注解

一、@Before前置通知实现

1.1创建业务接口

public interface SumService {
    String doSome(String name,int age);
    String show();
}

1.2创建业务实现

@Service
public class SumServiceImpl implements SumService {
    @Override
    public String doSome(String name, int age) {
        System.out.println("doSome业务功能实现。。。。");
        return "aaabbbccc";
    }

    @Override
    public String show() {
        System.out.println("show的业务功能实现。。。。");
        return "111";
    }
}

1.3创建切面类,实现切面方法

@Aspect  //交给AspectJ的框架去识别切面类
@Component
public class MyAspectJ {
    /**
     * 所以切面功能都是有切面方法实现的
     * 可以将各种切面都在此类中开发
     *
     * 前置通知的切面方法规范
     * 1)访问权限:public
     * 2)方法返回值 void
     * 3)方法名称自定义
     * 4)方法没有参数 有也是joinPoint类型
     * 5) 必须使用@Before 注解来声明切入时机是前切功能和切入点
     */
    @Before(value = "execution(public String com.bjpowernode.s01.SumServiceImpl.*(..))")
    public void myBefore(JoinPoint jp){ 
    /**
    *不光前置通知的方法,可以包含一个 JoinPoint 类型参数,所有的通知方法均可包含该参数。
    */
        System.out.println("前切方法实现。。。。");
        System.out.println("目标方法签名: "+jp.getSignature());
        System.out.println("目标方法值: "+ Arrays.toString(jp.getArgs()));
    }
}

AspectJ框架切换JDK动态代理和CGLib动态代理

<aop:aspectj-autoproxy ></aop:aspectj-autoproxy>
===>默认是JDK动态代理,取时必须使用接口类型
<aop:aspectj-autoproxy proxy-target-class=“true”></aop:aspectj-autoproxy>
==>设置为CGLib子类代理,可以使用接口和实现类接

记住:使用接口来接,永远不出错.

1.4 在.xml配置文件里进行切面绑定

<!--    包扫描 创建对象-->
//包扫描 创建切面类对象 和 目标类对象
    <context:component-scan base-package="com.bjpowernode.s01"></context:component-scan>
<!--    绑定-->
//注册一个基于 aspectj 的自动代理生成器,其就会自动扫描到@Aspect 注解
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

1.5 测试类

使用目标对象id-----sumServiceImpl

public class Mytest01 {

    @Test
    public void  test01(){
        ApplicationContext ac = new ClassPathXmlApplicationContext("s01/applicationContext.xml");
        SumService s = (SumService) ac.getBean("sumServiceImpl");
        String ans = s.doSome("胡鳖",11);
        System.out.println(ans);
    }
    @Test
    public void  test02(){
        ApplicationContext ac = new ClassPathXmlApplicationContext("s01/applicationContext.xml");
        SumService s = (SumService) ac.getBean("sumServiceImpl");
        String ans = s.show();
        System.out.println(ans);
    }
}

二、@AfterReturning 后置通知

在目标方法执行之后执行。由
于是目标方法之后执行,所以可以获取到目标方法的返回值。
该注解的 returning 属性就是用于指定接收方法返回值的变量名的。所以,被注解为后置通知的方法,除了可以包含 JoinPoint 参数外,还可以包含用于接收返回值的变量。
该变量最好为 Object 类型,因为目标方法的返回值可能是任何类型。

2.1创建业务接口

public interface SumService {
    String doSome(String name,int age);
    String show();
}

2.2创建业务实现

@Service
public class SumServiceImpl implements SumService {
    @Override
    public String doSome(String name, int age) {
        System.out.println("doSome业务功能实现。。。。");
        return "aaabbbccc";
    }

    @Override
    public String show() {
        System.out.println("show的业务功能实现。。。。");
        return "111";
    }
}

2.3创建切面类,实现切面方法

@Aspect  //交给AspectJ的框架去识别切面类
@Component
public class MyAspectJ {
    /**
     * 所以切面功能都是有切面方法实现的
     * 可以将各种切面都在此类中开发
     *
     * 前置通知的切面方法规范
     * 1)访问权限:public
     * 2)方法返回值 void
     * 3)方法名称自定义
     * 4)方法有参数 (也可以没参数,如果目标方法没有返回值 ,则可以写无)
     * 5) 必须使用@AfterReturning 注解来声明切入时机是前切功能和切入点\
     *       value: 制定切入点表达式
     *       returning : 制定目标方法的返回值名称,则名称必须与切面方法参数名称一至
     */
    @AfterReturning(value = "execution(* com.bjpowernode.s02.SumServiceImpl.*(..))",returning = "obj")
    public void myAfter(Object obj){
        System.out.println("后切方法实现。。。。");
        if(obj!=null){
            if(obj instanceof String){
                obj = obj.toString().toUpperCase();
                System.out.println("通知中返回值: "+obj);
            }else if(obj instanceof Student){
                Student stu = (Student) obj;
                stu.setName("李四");
                System.out.println("切面方法的返回值:" + obj);
            }

        }
    }
}

2.4 在.xml配置文件里进行切面绑定

<!--    包扫描 创建对象-->
//包扫描 创建切面类对象 和 目标类对象
    <context:component-scan base-package="com.bjpowernode.s01"></context:component-scan>
<!--    绑定-->
//注册一个基于 aspectj 的自动代理生成器,其就会自动扫描到@Aspect 注解
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

2.5 测试类

使用目标对象id-----sumServiceImpl

public class Mytest01 {

    @Test
    public void  test01(){
        ApplicationContext ac = new ClassPathXmlApplicationContext("s01/applicationContext.xml");
        SumService s = (SumService) ac.getBean("sumServiceImpl");
        String ans = s.doSome("胡鳖",11);
        System.out.println(ans);
    }
  

三、(4) @Around 环绕通知

在目标方法执行之前之后执行。被注解为环绕增强的方法要有返回值,Object 类型。
并且方法可以包含一个 ProceedingJoinPoint 类型的参数。
接口 ProceedingJoinPoint 其有一个proceed()方法,用于执行目标方法。若目标方法有返回值,则该方法的返回值就是目标方法的返回值。
最后,环绕增强方法将其返回值返回。该增强方法实际是拦截了目标方法的执行。

3.1创建业务接口

public interface SumService {
    String doSome(String name,int age);
}

3.2创建业务实现

@Service
public class SumServiceImpl implements SumService {
    @Override
    public String doSome(String name, int age) {
        System.out.println("doSome业务功能实现。。。。");
        return "aaabbbccc";
    }

3.3创建切面类,实现切面方法

@Aspect  //交给AspectJ的框架去识别切面类
@Component
public class MyAspectJ {
    /**
     * 所以切面功能都是有切面方法实现的
     * 可以将各种切面都在此类中开发
     * <p>
     * 前置通知的切面方法规范
     * 1)访问权限:public
     * 2)方法返回值 目标函数的返回值
     * 3)方法名称自定义
     * 4)方法有参数 为目标函数
     * 5) 回避异常 Throwable
     * 6) 必须使用@Around 注解来声明切入时机是前切功能和切入点
     *      value: 制定切入点表达式
     */
    @Around(value = "execution(* com.bjpowernode.s03.SumServiceImpl.*(..))")
    public Object myAfter(ProceedingJoinPoint pip) throws Throwable {
        //前切功能实现
        System.out.println("环绕通知功能后置功能实现。。。。");
        //目标方法调用
        Object obj = pip.proceed(pip.getArgs());
        //后切功能实现
        System.out.println("环绕通知后置功能实现");
        return obj.toString().toUpperCase();
    }
}

3.4 在.xml配置文件里进行切面绑定

<!--    包扫描 创建对象-->
//包扫描 创建切面类对象 和 目标类对象
    <context:component-scan base-package="com.bjpowernode.s01"></context:component-scan>
<!--    绑定-->
//注册一个基于 aspectj 的自动代理生成器,其就会自动扫描到@Aspect 注解
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

3.5 测试类

使用目标对象id-----sumServiceImpl

public class Mytest01 {

    @Test
    public void  test01(){
        ApplicationContext ac = new ClassPathXmlApplicationContext("s01/applicationContext.xml");
        SumService s = (SumService) ac.getBean("sumServiceImpl");
        String ans = s.doSome("胡鳖",11);
        System.out.println(ans);
    }
  

四. @After 最终通知

无论目标方法是否抛出异常,该增强均会被执行。


总结

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

GGood_Name

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

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

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

打赏作者

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

抵扣说明:

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

余额充值