AOP 的详细说明以及基本的使用

AOP复习

1、AOP简介

AOP(Aspect-OrientedProgramming,面向切面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善。

​ OOP引入封装、继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合。当我们需要为分散的对象引入公共行为的时候,OOP则显得无能为力。也就是说,OOP允许你定义从上到下的关系,但并不适合定义从左到右的关系。例如日志功能。日志代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心功能毫无关系。对于其他类型的代码,如安全性、异常处理和透明的持续性也是如此。这种散布在各处的无关的代码被称为横切(cross-cutting)代码,在OOP设计中,它导致了大量代码的重复,而不利于各个模块的复用。

而AOP技术则恰恰相反,它利用一种称为“横切”的技术

​ 剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其名为“Aspect”,即方面。所谓“方面”,简单地说,就是将那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。AOP代表的是一个横向的关系,如果说“对象”是一个空心的圆柱体,其中封装的是对象的属性和行为;那么面向方面编程的方法,就仿佛一把利刃,将这些空心圆柱体剖开,以获得其内部的消息。而剖开的切面,也就是所谓的“方面”了。然后它又以巧夺天功的妙手将这些剖开的切面复原,不留痕迹。

在这里插入图片描述

2、AOP作用

想象下面的场景,开发中在多个模块间有某段重复的代码,我们通常是怎么处理的?显然,没有人会靠“复制粘贴”吧。在传统的面向过程编程中,我们也会将这段代码,抽象成一个方法,然后在需要的地方分别调用这个方法,这样当这段代码需要修改时,我们只需要改变这个方法就可以了。然而需求总是变化的,有一天,新增了一个需求,需要再多出做修改,我们需要再抽象出一个方法,然后再在需要的地方分别调用这个方法,又或者我们不需要这个方法了,我们还是得删除掉每一处调用该方法的地方。实际上涉及到多个地方具有相同的修改的问题我们都可以通过 AOP 来解决。

3、AOP基本术语

Advice 通知

AOP 的主要作用就是在不侵入原有程序的基础上实现对原有功能的增强, 而增强的方式就是添加通知,就是额外增强一个方法。按照不同的方式通知又分为前置、后置、环绕、异常、带有返回值。

JointPoint 连接点

​ 在上述通知的描述中我们知道,AOP增强就是为原有方法在不侵入的情况下额外添加了一个新的功能,**而新功能和原有方法之间是如何联系到一起的呢?**这里就是引入了连接点的概念了。在AOP中连接点的表现形式为

@Around("execution(* io.renren.test.service.Buy.Play(..))")
// 通过注解来把增强方法和原有方法链接到一起,实现了增强的功能。

Pointcut 切入点

​ 在上述连接点的叙述中,我们知道了AOP 是如何实现都原有功能增强的, 但是通过连接点,增强方法是如何增强原有方法的呢? 这里就需要切入点来实现对原有方法的切入。在AOP的代码中表现形式为

    @Around("execution(* io.renren.test.service.Buy.Play(..))")
    public void Around(ProceedingJoinPoint point) throws Throwable {

        System.out.println("环绕前.....");
        System.out.println(point);
    }

// ProceedingJoinPoint point  过程切入点, 增强方法在此实现对被增强方法的功能增强。通过切入点我们可以得到很多东西, 举例如下

        /**
         * 得到参数
         */
        Object[] args = point.getArgs();
        System.out.println("args=> " + args.toString());
        /**
         * 得到切入点的类型
         */
        String kind = point.getKind();
        System.out.println("kind=> " + kind);
        /**
         *  切入点 得到被增强方法的方法签名
         */
        MethodSignature methodSignature = (MethodSignature) point.getSignature();

        /**
         *  方法签名 到被增强方法的方法
         */
        Method method = methodSignature.getMethod();
        System.out.println("method = > " + method);
        /**
         *  方法 名 到被增强方法的方法 上面的注解
         */
        SysLog sysLog = method.getAnnotation(SysLog.class);
        TestAnnotation test = method.getAnnotation(TestAnnotation.class);
        System.out.println(sysLog.value());
        System.out.println(test.value());
        Signature signature = point.getSignature();
        String name = signature.getName();
        Class declaringType = signature.getDeclaringType();
        int modifiers = signature.getModifiers();
        String declaringTypeName = signature.getDeclaringTypeName();
        System.out.println("name= > " + name + " declaringType => " + declaringType + " modifiers => " + modifiers + " declaringTypeName => " + modifiers);
        System.out.println("signature=> " + signature);
        /**
         *    得到目标
         */
        Object target = point.getTarget();
        System.out.println("target=> " + target);
        System.out.println("环绕后.....");

Aspect 切面

	切面是一个类, **由通知和切点组成, 在AOP代码的实现中为主要部分。**, 而一个通知则包括; 切点、连接点, 所以说, 一个切面就直接包括 AOP中所有东西了。 
/**
 * 切面类
 *
 * @author cyt
 */

@Aspect
@Component
public class Point {

    @Before("execution(* io.renren.test.service.Buy.Play(..))")
    public void Before(ProceedingJoinPoint point) {
        System.out.println("男孩女都有自己喜欢的事情");
    } 
}

4、AOP通知方式

在这里插入图片描述

5、AOP基本使用

目录结构

在这里插入图片描述

主要: 接口、实现类、切面、配置类、测试类

接口和实现类

public interface Buy {
    public void Play(String info);  
}
@Component
public class BoyBuy implements Buy {

    @Override
    public void Play(String info) {
        System.out.println(info);
    }
}

配置类

@ComponentScan(basePackages = {"io.renren.test"})
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true)
@ComponentScan(basePackageClasses = {io.renren.test.service.Buy.class})
public class config {

}

测试

public class Test {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(config.class);
        BoyBuy buy = context.getBean(BoyBuy.class);
        GirlBuy girl = context.getBean(GirlBuy.class);

        girl.Play("around info  ");
    }
}

在这里插入图片描述

AOP

/**
 * 切面类
 *
 * @author cyt
 */

@Aspect
@Component
public class Point {

     @Before("execution(* io.renren.test.service.Buy.Play(..))")
    public void Before() {
        System.out.println("男孩女都有自己喜欢的事情");
    }
}

在这里插入图片描述

开启环绕通知, 以及打印切入点的信息

  @Around("execution(* io.renren.test.service.Buy.Play(..))")
    public void Around(ProceedingJoinPoint point) throws Throwable {
        System.out.println("环绕前.....");
        System.out.println(point);
        /**
         * 得到参数
         */
        Object[] args = point.getArgs();
        System.out.println("args=> " + args.toString());
        /**
         * 得到切入点的类型
         */
        String kind = point.getKind();
        System.out.println("kind=> " + kind);
        /**
         *  切入点 得到被增强方法的方法签名
         */
        MethodSignature methodSignature = (MethodSignature) point.getSignature();

        /**
         *  方法签名 到被增强方法的方法
         */
        Method method = methodSignature.getMethod();
        System.out.println("method = > " + method);
        /**
         *  方法 名 到被增强方法的方法 上面的注解
         */
        SysLog sysLog = method.getAnnotation(SysLog.class);
        TestAnnotation test = method.getAnnotation(TestAnnotation.class);
        System.out.println(sysLog.value());
        System.out.println(test.value());
        Signature signature = point.getSignature();
        String name = signature.getName();
        Class declaringType = signature.getDeclaringType();
        int modifiers = signature.getModifiers();
        String declaringTypeName = signature.getDeclaringTypeName();
        System.out.println("name= > " + name + " declaringType => " + declaringType + " modifiers => " + modifiers + " declaringTypeName => " + modifiers);
        System.out.println("signature=> " + signature);
        /**
         *    得到目标
         */
        Object target = point.getTarget();
        System.out.println("target=> " + target);
        System.out.println("环绕后.....");
    }

在这里插入图片描述

直接编写连接点, 实现对方法的增强

我们定义了一个切点, 并且把切点配置到通知上面

    /**
     * 定义一个切点
     */
    @Pointcut("execution(* io.renren.test.service.Buy.Play(..))")
    public void AspectJPoint() {
    }

    @Before("AspectJPoint()")
    public void point1() {
        System.out.println("前置通知");
    }

修改切面类中 内容如下。

在这里插入图片描述

  • 47
    点赞
  • 189
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值