浅谈自己对于spring aop的理解

  • 开始学习spring就被重点的关注ioc和aop这两个关键的部分,今天着重了解下关于aop的一些实现和原理。
    • aop 面向切面编程 即可以在业务逻辑前后加上需要的无关业务的处理如日志,权限控制等操作,与实际的业务相分离。
    • 首先需要介绍的技术就是AspectJ 了解了这个之后会对spring的aop实现有对比显示出两者的差异。aspectJ是一个由java实现的aop框架,通过对编译期的代码进行编译 让代码具有aop的功能。
      • 切面就是切点与通知的一个组合,在切面内部定义了两个部分
        • 切点 pointcut 即需要应用切面的方法,
        • pointcut 函数名 call(){匹配表达式}
        • pointcut recordLog():call(* HelloWord.sayHello(..));
        • 通知 advice 需要在目标方法前后执行的函数
          • before 前置通知 目标方法执行前
          • after 后置通知 目标方法执行后
          • after returning 方法返回通知 目标方法返回时执行
          • after throwing 异常通知 目标方法抛出异常时执行
          • around 目标函数中 执行 可以控制目标函数是否执行 环绕通知
        • 目标函数 称为连接点 joinPoint
        • 织入 指代码切入到目标函数的过程 例如aspectJ到java程序的过程称为织人
          • 静态织入 aspectJ 编译为class文件后在目标类中织入
            • idea进行aspectJ
          • 动态织入 jdk动态代理 cglib
            • @Aspect
@Aspect
public class AspectJ {
    /**
     * 前置通知
     */
    @Before("execution(* aop.UserDao.addUser(..))")
    public void before(){
        System.out.println("前置通知");
    }

    /**
     * 后置通知
     * returnVal,切点方法执行后的返回值
     */
    @AfterReturning(value="execution(* aop.UserDao.addUser(..))",returning = "returnVal")
    public void AfterReturning(Object returnVal){
        System.out.println("后置通知...."+returnVal);
    }
    /**
     * 环绕通知
     * @param joinPoint 可用于执行切点的类
     * @return
     * @throws Throwable
     */
    @Around(value="execution(* aop.UserDao.addUser(..))")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("环绕前.....");
        Object result = joinPoint.proceed();
        System.out.println("环绕后.....");
        return result;
    }
    /**
     * 抛出通知
     * @param e
     */
    @AfterThrowing(value = "execution(* aop.UserDao.addUser(..))",throwing = "e")
    public void afterThrowable(Throwable e){
        System.out.println("出现异常:msg="+e.getMessage());
    }

    /**
     * 无论什么时候都会执行
     */
    @After(value = "execution(* aop.UserDao.addUser(..))")
    public void after(){
        System.out.println("最终通知....");
    }
}
或者
@Pointcut(value = "execution( * aop.UserDao.addUser(..))")
public void p1(){}
/**
 * 前置通知
 */
@Before(value = "p1()")
public void before(){
    System.out.println("前置通知");
}
  • 切点指示符
.. 匹配方法中任意参数数量的方法
within(com.zejian.dao..*) 匹配该类中的所有方法
within(com.zejian.dao.DaoUser+) 匹配该类的所有子类/实现该接口的类的所有方法
within(com.zejian.service..*) 匹配 该包及子包下的所有方法
类型签名表达式
within(<type name>)
方法签名表达式
//匹配UserDaoImpl类中的所有方法
    @Pointcut("execution(* com.zejian.dao.UserDaoImpl.*(..))")
    //匹配UserDaoImpl类中的所有公共的方法
    @Pointcut("execution(public * com.zejian.dao.UserDaoImpl.*(..))")
    //匹配UserDaoImpl类中的所有公共方法并且返回值为int类型
    @Pointcut("execution(public int com.zejian.dao.UserDaoImpl.*(..))")
    //匹配UserDaoImpl类中第一个参数为int类型的所有公共的方法
    @Pointcut("execution(public * com.zejian.dao.UserDaoImpl.*(int , ..))")
bean
@Pointcut("bean(*Service)") 用于匹配后缀为service的bean
    private void myPointcut1(){}
this 
用于匹配当前AOP代理对象类型的执行方法
and or not ! && ||

Aspect的优先级

  • 不同切面

    • 实现 ordered接口 实现getOrder() 越小的优先级越高
    • 基于注解的 @Order(0,1,2)
      AOP的应用场景

      • 模拟系统性能监控
      • 异常统计
        实现原理

      • cglib 继承

        • interface methodInterceptor
        • Enhancer 产生代理对象(被代理对象的子类)
      • jdk动态代理 基于反射

附上代码

public class CglibProxy implements MethodInterceptor {

    //被代理对象
    private A target;

    public CglibProxy(A target) {
        super();
        this.target = target;
    }

    public A createProxy(){
        // 1.声明增强类实例,用于生产代理类
        Enhancer enhancer = new Enhancer();
        // 2.设置被代理类字节码,CGLIB根据字节码生成被代理类的子类
        enhancer.setSuperclass(target.getClass());
        // 3.设置回调函数
        enhancer.setCallback(this);
        // 创建代理
        return (A) enhancer.create();
    }

    /**
     * 回调函数
     */
    @Override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        if("execute".equals(method.getName())) {
            //调用前验证权限(动态添加其他要执行业务)
          //  AuthCheck.authCheck();

            //调用目标对象的方法(执行A对象即被代理对象的execute方法)
            Object result = methodProxy.invokeSuper(proxy, args);

            //记录日志数据(动态添加其他要执行业务)
           // Report.recordLog();

            return result;
        }
        return methodProxy.invokeSuper(proxy,args);
    }
}

参考博客 神一样的aspectj-aop的领跑者

猜你喜欢

转载自blog.csdn.net/sinat_32197439/article/details/81261119