6、AOP(spring笔记)

一、AOP中的术语简介

6、AOP(spring笔记)_第1张图片
AOP.png

说明:

  • 1.这里我们拿安全性检查来进行说明。对于安全性检查来说,这和我们真正的业务是没有任何关系的,只是我们将其横向插入进去,在spring中这叫横切性关注点(cross cutting concern)。

  • 2.对于横切性关注点来说,我们可以实现各种模块化的类,即切面类(aspect),而我们实现安全性检查的类SecurityHandler类就叫Advice。同时Advice类根据其切入点的不同可以分为Before Advice、After Advice。

  • 3.所谓切入点(pointcut),表示advice能应用咋什么地方,即应用在哪些jointpoint,在spring中指能应用在哪些方法上,因为方法只支持方法的连接点(jointpoint),而应用的过程叫植入(weave)。

  • 4.另外两个术语proxy表示代理,introduction表示动态的给一个类加上一些方法。

二、spring对AOP的支持(采用注解方式)(工程spring_aop_1

  • 1.依赖库
    这里需要在之前依赖包基础上再加上一些依赖包SPRING_HOME/lib/aspectj/*.jar,同时注意:如果JDK版本较高,则低版本的aspectj包可能会出现问题,此时请使用目录中1.8版本的aspectj包。

  • 2.采用aspect注解定义切面;

  • 3.在aspect定义pointcut和advice。

  • 4.启用aspect对注解的支持,同时将切面和目标对象配置到IOC容器中。

动态代理类:SecurityHandler.java

package com.bjsxt.spring;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
/**
 * 定义Aspect
 */
@Aspect
public class SecurityHandler {
    
    /*下面的注解表示应用范围,使用Pointcut注解,而其名称是allAddMethod,
    不能有返回值和参数,该方法只是一个Pointcut标识,没有其他意义。
    *Pointcut的内容是一个表达式,描述应用到哪些方法上(Joinpoint),括
    号里面第一个*号表示
    *返回值(即返回值可有可没有),而add*表示所有的add方法,(..)表示
    任意参数。
    */
    @Pointcut("execution(* add*(..)) || execution(* del*(..))")
    private void allAddMethod(){};
    
    /*检查安全性,注解表示在方法之前调用,而方法使用allAddMethod()标识
     *定义Advice,标识在哪个切入点植入此方法
     * */
    @Before("allAddMethod()")
    private void checkSecurity() {
        System.out.println("----------checkSecurity()---------------");
    }
}

说明:这里一定要注意,切入点方法是不会执行的,存在的目的仅仅是作为一个标识,我们可以在advice中通过此方法名引用此切入点。

配置:




    
    
               
    

测试:Client.java

package com.bjsxt.spring;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Client {

    public static void main(String[] args) {
        BeanFactory factory = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserManager userManager = (UserManager)factory.getBean("userManager");
        
        userManager.addUser("张三", "123");
        userManager.deleteUser(1);
    }
}

三、spring对AOP的支持(采用配置方式)(工程spring_aop_2

首先将之前的注解全部取消,然后在配置文件中进行配置:




    
               
    
    
    
    
        
            
            
        
       

SecurityHandler.java

package com.bjsxt.spring;
public class SecurityHandler {
    
    private void checkSecurity() {
        System.out.println("----------checkSecurity()---------------");
    }
}

说明:两种配置方式本质上是一样的,我们推荐使用配置文件的方式进行配置。

我们还可以通过advice中添加一个jointpoint参数,这个值会由spring自动传入,从jointpoint中可以取到要检查的方法的参数和方法名(工程spring_aop_3

SecurityHandler.java

package com.bjsxt.spring;
import org.aspectj.lang.JoinPoint;
public class SecurityHandler {
    
    private void checkSecurity(JoinPoint joinPoint){
        
        //此时我们就可以拿到对某个方法进行安全性检查的参数和方法名字
        //比如addUser("Tom", "123");中的参数"Tom"和"123"和方法名
        //addUser
        Object[] args = joinPoint.getArgs();
        for(int i = 0; i < args.length; i++){
            System.out.println(args[i]);
        }
        
        System.out.println(joinPoint.getSignature().getName());//拿到方法签名
        System.out.println("----UserManagerImpl.checkSecurity()---");
    }
}

四、使用CGLIB库实现动态代理(工程spring_aop_4

  • 1.如果目标对象实现了接口(比如这里的业务类),默认情况下会采用JDK的动态代理实现AOP;

  • 2.如果目标对象实现了接口,也可以强制使用CGLIB实现AOP;

  • 3.没有实现接口那就必须使用CGLIB实现AOP了,spring会自动在JDK动态代理和CGLIB之间转换,就是实现了接口的使用JDK动态代理,没有实现接口的使用CGLIB实现,spring自动完成此转换。

4.1 强制使用CGLIB实现动态代理

  • 添加CGLIB库
  • 在spring的配置文件中进行配置:,此时我们会发现实现的代理类就是由CGLIB实现的。当然我们还是推荐使用JDK的动态代理,这就要求我们实现接口。

4.2 JDK动态代理和CGLIB字节码生成的区别:

  • JDK动态代理只能对实现了接口的类生成代理,不能针对类生成代理
  • CGLIB是针对类实现代理,实现原理是生成一个子类作为一个代理。因为是继承,所以该类或方法最好不要声明成final类型。实际中我们建议使用JDK的动态代理。

你可能感兴趣的:(6、AOP(spring笔记))