Spring-AOP初解

28 篇文章 0 订阅

结构图

在这里插入图片描述

代码

接口实现

首先定义一个接口,有两个类来实现它

public interface Buy {
    public void Play(String info);
}

实现类

分别实现两个类,boybuy和girlbuy

@Component
public class BoyBuy implements Buy {
    @Override
    public void Play(String info) {
        System.out.println(info);
    }
}
@Component
public class GirlBuy implements Buy {
    @Override
    public void Play(String info) {
        System.out.println(info);
    }
}

config

这部分代码主要用来:1.扫描指定位置的component组件并且将其加入spring容器中

//扫描com.example.demo包下的所有组件,并将这些组件添加到spring容器中。
@ComponentScan(basePackages = {"com.example.demo"})
@ComponentScan(basePackageClasses = com.example.demo.service.Buy.class)

//告诉Spring Boot这是一个配置类。
@Configuration
//spring要在类上加上@EnableAspectJAutoProxy注解开启AOP的使用
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class config {

}

启动部分

创建一个类,执行两个类的buy方法

public class Test {
    public static void main(String[] args) {
    	//加载配置
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(config.class);
        BoyBuy boy = context.getBean(BoyBuy.class);
        GirlBuy girl = context.getBean(GirlBuy.class);

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

启动后是这样的
在这里插入图片描述

切面

注解含义

@Aspect:切面。表示一个横切进业务的一个对象。它里面包含切入点(Pointcut)和Advice(通知)。
需要在切面类上方定义,就像@component一样,说明下面我要开始写一些切入方法了。

@Pointcut:切入点。表示需要切入的位置,比如某些类或者某些方法,也就是先定一个范围。
指定符合要求的方法作为被切入方法。

对于被指定的方法,可以用以下不同的注解,进行不同位置的注入。
@Before:Advice(通知)的一种,切入点的方法体执行之前执行。
@Around:Advice(通知)的一种,环绕切入点执行也就是把切入点包裹起来执行。
@After:Advice(通知)的一种,在切入点正常运行结束后执行。
@AfterReturning:Advice(通知)的一种,在切入点正常运行结束后执行,异常则不执行
@AfterThrowing:Advice(通知)的一种,在切入点运行异常时执行。

@Pointcut语法

语法有点复杂,目前也没完全掌握,只做个记录

   /**
     * 1、使用within表达式匹配
     * 下面示例表示匹配com.leo.controller包下所有的类的方法
     */
    @Pointcut("within(com.leo.controller..*)")
    public void pointcutWithin(){

    }

    /**
     * 2、this匹配目标指定的方法,此处就是HelloController的方法
     */
    @Pointcut("this(com.leo.controller.HelloController)")
    public void pointcutThis(){

    }

    /**
     * 3、target匹配实现UserInfoService接口的目标对象
     */
    @Pointcut("target(com.leo.service.UserInfoService)")
    public void pointcutTarge(){

    }

    /**
     * 4、bean匹配所有以Service结尾的bean里面的方法,
     * 注意:使用自动注入的时候默认实现类首字母小写为bean的id
     */
    @Pointcut("bean(*ServiceImpl)")
    public void pointcutBean(){

    }

    /**
     * 5、args匹配第一个入参是String类型的方法
     */
    @Pointcut("args(String, ..)")
    public void pointcutArgs(){

    }

    /**
     * 6、@annotation匹配是@Controller类型的方法
     */
    @Pointcut("@annotation(org.springframework.stereotype.Controller)")
    public void pointcutAnnocation(){

    }
    /**
     * 7、@within匹配@Controller注解下的方法,要求注解的@Controller级别为@Retention(RetentionPolicy.CLASS)
     */
    @Pointcut("@within(org.springframework.stereotype.Controller)")
    public void pointcutWithinAnno(){

    }
    /**
     * 8、@target匹配的是@Controller的类下面的方法,要求注解的@Controller级别为@Retention(RetentionPolicy.RUNTIME)
     */
    @Pointcut("@target(org.springframework.stereotype.Controller)")
    public void pointcutTargetAnno(){

    }
    /**
     * 9、@args匹配参数中标注为@Sevice的注解的方法
     */
    @Pointcut("@args(org.springframework.stereotype.Service)")
    public void pointcutArgsAnno(){

    }


    /**
     * 10、使用excution表达式
     * execution(
     *  modifier-pattern?           //用于匹配public、private等访问修饰符
     *  ret-type-pattern            //用于匹配返回值类型,不可省略
     *  declaring-type-pattern?     //用于匹配包类型
     *  name-pattern(param-pattern) //用于匹配类中的方法,不可省略
     *  throws-pattern?             //用于匹配抛出异常的方法
     * )
     *
     * 下面的表达式解释为:匹配com.leo.controller.HelloController类中以hello开头的修饰符为public返回类型任意的方法
     */
    @Pointcut(value = "execution(public * com.leo.controller.HelloController.hello*(..))")
    public void pointCut() {

    }

切面代码

下面的代码首先声明了作为一个切面,且作为一个容器,然后定义了一个@pointcut,即哪些方法作为可以被切入的方法。
所以下面的@before和@Around只需要获得这个切点的value就可以对这个切点的方法进行各种操作了。
注意@Around其中的point.proceed()方法可以控制方法的执行,如果使用了@Around又没有执行proceed方法,被切入的方法连执行都不会执行,而proceed还可以替换方法内部的参数,功能十分强大。

@Aspect
@Component
public class Point {

    /**
     * 定义一个切点
     */
    //Pointcut 是指那些方法需要被执行"AOP",
    @Pointcut("execution(* com.example.demo.service.Buy.Play(..))")
    public void AspectJPoint() {
    }


    //在play这个方法执行之前执行
    @Before(value = "AspectJPoint()")
    public void Before(){
        System.out.println("男孩女孩都有自己喜欢的事情");
    }

    @Around(value = "AspectJPoint()")
    //开启环绕通知, 以及打印切入点的信息 point指进入的方法
    //应该叫增强通知
    public void Around(ProceedingJoinPoint point) throws Throwable {
        System.out.println("环绕前....");
        System.out.println(point);

        //得到point方法的参数
        Object[] args = point.getArgs();
        System.out.println("args=> "+args.toString());
        //得到point方法的类型
        String kind = point.getKind();
        System.out.println("kind=> "+kind);
        //得到point方法的方法签名
        MethodSignature signature = (MethodSignature) point.getSignature();
        //得到其方法(?)确实有点像反射了。
        Method method = signature.getMethod();
        System.out.println("method=> "+method);
        //获得其名字
        Signature signature1 = point.getSignature();
        String name = signature1.getName();
        Class declaringType = signature1.getDeclaringType();
        int modifiers = signature1.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);
        //执行这个方法
        point.proceed();
        //修改play方法的参数 打印新东西
        point.proceed(new String[]{"玩新的游戏"});
        System.out.println("环绕后.....");
    }
}

执行顺序

@Around ->@Before->主方法体->@Around中proceed()->@After->@AfterReturning

运行结果

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值