spring AOP原理

[toc]

aop的 实现

先添加依赖

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

在spring中配置一下

@Configuration
@EnableAspectJAutoProxy
public class AspectConf  {
}

aop的实现

@Component注入bean
@Aspect表示切面
@Pointcut 表示切点

@Aspect
@Component
public class AspectTest {

    private static final Logger logger = (Logger) LoggerFactory.getLogger(AspectTest.class);
    private long start;

    @Pointcut(value = "@annotation(com.example.demo.controler.TestCon.*)")
    public void timer(){}

    //在方法执行前执行
    @Before("timer()")
    public void before() {
        start = System.currentTimeMillis();
    }

    //在方法执行后执行
    @After("timer()")
    public void after() {
        long now = System.currentTimeMillis();
        logger.info("job took time {}s in summary"+(now - start) / 1000);
    }

}

pointcut的表示

AspectJ匹配模式

  • execution:用于匹配方法执行的连接点;
  • within:用于匹配指定类型内的方法执行;
  • this:用于匹配当前AOP代理对象类型的执行方法;注意是AOP代理对象的类型匹配,这样就可能包括引入接口也类型匹配;
  • target:用于匹配当前目标对象类型的执行方法;注意是目标对象的类型匹配,这样就不包括引入接口也类型匹配;
  • args:用于匹配当前执行的方法传入的参数为指定类型的执行方法;
  • @within:用于匹配所以持有指定注解类型内的方法;
  • @target:用于匹配当前目标对象类型的执行方法,其中目标对象持有指定的注解;
  • @args:用于匹配当前执行的方法传入的参数持有指定注解的执行;
  • @annotation:用于匹配当前执行方法持有指定注解的方法;
    参考

切点表达式

execution([可见性] 返回类型 [声明类型].方法名(参数) [异常])
  其中【】中的为可选,其他的还支持通配符的使用:

  *:匹配所有字符
..:一般用于匹配多个包,多个参数
+:表示类及其子类

  运算符有:&&、||、!

 1)execution:用于匹配子表达式。

            //匹配com.cjm.model包及其子包中所有类中的所有方法,返回类型任意,方法参数任意
            @Pointcut("execution(* com.cjm.model..*.*(..))")
            public void before(){}



      2)within:用于匹配连接点所在的Java类或者包。

            //匹配Person类中的所有方法
            @Pointcut("within(com.cjm.model.Person)")
            public void before(){}



            //匹配com.cjm包及其子包中所有类中的所有方法

            @Pointcut("within(com.cjm..*)")
            public void before(){}



     3) this:用于向通知方法中传入代理对象的引用。
            @Before("before() && this(proxy)")
            public void beforeAdvide(JoinPoint point, Object proxy){
                  //处理逻辑
            }



      4)target:用于向通知方法中传入目标对象的引用。
            @Before("before() && target(target)
            public void beforeAdvide(JoinPoint point, Object proxy){
                  //处理逻辑
            }



      5)args:用于将参数传入到通知方法中。
            @Before("before() && args(age,username)")
            public void beforeAdvide(JoinPoint point, int age, String username){
                  //处理逻辑
            }

      6)@within :用于匹配在类一级使用了参数确定的注解的类,其所有方法都将被匹配。

            @Pointcut("@within(com.cjm.annotation.AdviceAnnotation)") - 所有被@AdviceAnnotation标注的类都将匹配
            public void before(){}

  

      7)@target :和@within的功能类似,但必须要指定注解接口的保留策略为RUNTIME。
            @Pointcut("@target(com.cjm.annotation.AdviceAnnotation)")
            public void before(){}



      8)@args :传入连接点的对象对应的Java类必须被@args指定的Annotation注解标注。
            @Before("@args(com.cjm.annotation.AdviceAnnotation)")
            public void beforeAdvide(JoinPoint point){
                  //处理逻辑
            }

  

      9)@annotation :匹配连接点被它参数指定的Annotation注解的方法。也就是说,所有被指定注解标注的方法都将匹配。
            @Pointcut("@annotation(com.cjm.annotation.AdviceAnnotation)")
            public void before(){}

      10)bean:通过受管Bean的名字来限定连接点所在的Bean。该关键词是Spring2.5新增的。
            @Pointcut("bean(person)")
            public void before(){}

通知参数

任何通知方法可以将第一个参数定义为org.aspectj.lang.JoinPoint类型(环绕通知需要定义第一个参数为ProceedingJoinPoint类型,它是 JoinPoint 的一个子类)。JoinPoint接口提供了一系列有用的方法,比如 getArgs()(返回方法参数)、getThis()(返回代理对象)、getTarget()(返回目标)、getSignature()(返回正在被通知的方法相关信息)和 toString()(打印出正在被通知的方法的有用信息)

aop的实现原理

AspectJ

aspectJ 是静态代理的方式,AOP框架会在编译阶段生成AOP代理类,因此也称为编译时增强。在编译阶段通过把AspectJ向代码中插入java代码来调用Aspect对象函数来实现.

spring AOP

Spring AOP使用的动态代理,所谓的动态代理就是说AOP框架不会去修改字节码,而是在内存中临时为方法生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法。

分为两种:
– JDK动态代理: 通过反射来接受被代理的类,并且要求被代理的类必须实现一个接口。JDK动态代理的核心是InvocationHandler接口和Proxy类。
– CGLIB代理:可以在运行时动态的生成某个类的子类,注意,CGLIB是通过继承的方式做的动态代理
– 目标类没有实现InvocationHandler接口和Proxy类接口,那么Spring AOP会选择使用CGLIB来动态代理目标类;

aop使用源码

  • aop通知类型:
    • @Before 前置通知(Before advice) :在某连接点(JoinPoint)之前执行的通知,但这个通知不能阻止连接点前的执行。
    • @After 后通知(After advice) :当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。
    • @AfterReturning 返回后通知(After return advice) :在某连接点正常完成后执行的通知,不包括抛出异常的情况。
    • @Around 环绕通知(Around advice) :包围一个连接点的通知,类似Web中Servlet规范中的Filter的doFilter方法。可以在方法的调用前后完成自定义的行为,也可以选择不执行。
    • @AfterThrowing 抛出异常后通知(After throwing advice) : 在方法抛出异常退出时执行的通知。

参考博客:https://www.cnblogs.com/lic309/p/4079194.html
参考博客:http://www.importnew.com/24305.html


评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注