AOP详解

参考资料:https://blog.csdn.net/javazejian/article/details/56267036

一. AOP是什么

1.AOP简介

AOP的出现确实解决外围业务代码与核心业务代码分离的问题,但它并不会替代OOP,如果说OOP的出现是把编码问题进行模块化,那么AOP就是把涉及到众多模块的某一类问题进行统一管理 AspectJ是一个java实现的AOP框架,它能够对java代码进行AOP编译(一般在编译期进行),让java代码具有AspectJ的AOP功能
在这里插入图片描述

2.定义语法

切点语法:

pointcut recordLog():call(* HelloWord.sayHello(..));
pointcut		:切点定义
recordLog()	:AOP方法名
call			:调用 * HelloWord.sayHello(..)方法时调用切点方法
*			:返回任意类型
..			:参数类型任意

通知语法:

before 目标方法执行前执行,前置通知
after 目标方法执行后执行,后置通知
after returning 目标方法返回时执行,后置返回通知
after throwing 目标方法抛出异常时执行异常通知
around 在目标函数执行中执行,可控制目标函数是否执行,环绕通知

Object around():aroundAdvice(){
     System.out.println("sayAround 执行前执行");
     Object result=proceed();//执行目标函数
     System.out.println("sayAround 执行后执行");
     return result;
 }

3.AspectJ的植入方式及其原理概要

3.1织入

  • 静态织入:
    ApectJ采用的就是静态织入的方式。ApectJ主要采用的是编译期织入,在这个期间使用AspectJ的acj编译器(类似javac)把aspect类编译成class字节码后,在java目标类编译时织入,即先编译aspect类再编译目标类

  • 动态织入: 方式是在运行时动态将要增强的代码织入到目标类中,这样往往是通过动态代理技术完成的,如Java
    JDK的动态代理(Proxy,底层通过反射实现)或者CGLIB的动态代理(底层通过继承实现),Spring
    AOP采用的就是基于运行时增强的代理技术.

    静态织入
    在这里插入图片描述

二. 基于Aspect Spring AOP开发

Spring没有采用ajc编译器,而是采用JDk动态代理技术来实现AOP功能

三. 基于注解的SprigAOP开发

1. 定义切入点函数

/**
 * 使用Pointcut定义切点
*/
@Pointcut("execution(*com.zejian.spring.springAop.dao.UserDao.addUser(..))")
private void myPointcut(){}

/**
 * 应用切入点函数
 */
@After(value="myPointcut()")
public void afterDemo(){
    System.out.println("最终通知....");
}

2. 切入点指示符

2.1 通配符

 .. :匹配方法定义中的任意数量的参数,此外还匹配类定义中的任意数量包 
 //任意返回值,任意名称,任意参数的公共方法
   execution(public * *(..)) //匹配com.zejian.dao包及其子包中所有类中的所有方法
   within(com.zejian.dao..*)

+ :匹配给定类的任意子类
//匹配实现了DaoUser接口的所有子类的方法
within(com.zejian.dao.DaoUser+)

* :匹配任意数量的字符
//匹配com.zejian.service包及其子包中所有类的所有方法
within(com.zejian.service..*)
//匹配以set开头,参数为int类型,任意返回值的方法
execution(* set*(int))

3. Aspect优先级

  • 同一个切面:顺序执行
  • 不同切面: 进入时则优先级高的切面类中的通知函数优先执行,退出时则最后执行 切面通过实现Ordered接口
@Override    public int getOrder() {
       return 0;//返回的值越小,那么优先级越大    
 }

四. Spring AOP的实现原理概要

1. JDK动态代理

  1. 实际上动态代理的底层是通过反射技术来实现,只要拿到A类的class文件和 A类的实现接口,很自然就可以生成相同接口的代理类并调用a对象的方法了.

  2. java的动态代理是有先决条件的,该条件是目标对象必须带接口(Proxy类需要 通过接口来构建一个新类),如A类的接口是ExInterface,通过ExInterface接口动态 代理技术便可以创建与A类类型相同的代理对象

  3. 代理类(Demo中的JDKProxy)还需要实现InvocationHandler接口,也是由 JDK提供,代理类必须实现的并重写invoke方法,完全可以把InvocationHandler看成 一个回调函数(Callback),Proxy方法创建代理对象proxy后,当调用execute方法 (代 理对象也实现ExInterface)时,将会回调InvocationHandler#invoke方法,因此我们可 以在invoke方法中来控制被代理对象(目标对象)的方法执行,从而在该方法前后动态增 加其他需要执行的业务

   /**
         * Created by zejian on 2017/2/11.
         * Blog : http://blog.csdn.net/javazejian [原文地址,请尊重原创]
         */
        //自定义的接口类,JDK动态代理的实现必须有对应的接口类
        public interface ExInterface {
            void execute();
        }
        //A类,实现了ExInterface接口类
        public class A implements ExInterface{
            public void execute(){
                System.out.println("执行A的execute方法...");
            }
        }
        //代理类的实现
        public class JDKProxy implements InvocationHandler{

    
        /**
         * 要被代理的目标对象
         */
        private A target;
    
        public JDKProxy(A target){
            this.target=target;
        }
    
        /**
         * 创建代理类
         * @return
         */
        public ExInterface createProxy(){
            return (ExInterface) Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
        }
    
        /**
         * 调用被代理类(目标对象)的任意方法都会触发invoke方法
         * @param proxy 代理类
         * @param method 被代理类的方法
         * @param args 被代理类的方法参数
         * @return
         * @throws Throwable
         */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            //过滤不需要该业务的方法
            if("execute".equals(method.getName())) {
                //调用前验证权限
                AuthCheck.authCheck();
                //调用目标对象的方法
                Object result = method.invoke(target, args);
                //记录日志数据
                Report.recordLog();
                return result;
            }eles if("delete".equals(method.getName())){
                //.....
            }
            //如果不需要增强直接执行原方法
            return method.invoke(target,args);
        }
    }
    
     //测试验证
     public static void main(String args[]){
          A a=new A();
          //创建JDK代理
          JDKProxy jdkProxy=new JDKProxy(a);
          //创建代理对象
          ExInterface proxy=jdkProxy.createProxy();
          //执行代理对象方法
          proxy.execute();
      }

2. CGLIB动态代理(接口换成继承)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值