Spring AOP底层的那些事

问题1.什么是AOP?
AOP:面向切面编程,听这名字完全不明白他是干什么用的,我们知道OOP是面向对象编程,请看下面这个案例。


public interface StudentDAO {
    void save();
    void delete();
    void update();
    void select();
}


package com.ibuyi.free.Case_three;

public class StudentDAOImpl implements StudentDAO{
    @Override
    public void save() {
        System.out.println("学生保存方法....");
    }

    @Override
    public void delete() {
        System.out.println("学生删除方法....");
    }

    @Override
    public void update() {
        System.out.println("学生修改方法....");
    }

    @Override
    public void select() {
        System.out.println("学生查询方法....");
    }
}

package com.ibuyi.free.Case_three;

public class Person implements StudentDAO {

    @Override
    public void save() {
        System.out.println("普通人的保存");
    }

    @Override
    public void delete() {
        System.out.println("普通人的删除");
    }

    @Override
    public void update() {
        System.out.println("普通人的修改");
    }

    @Override
    public void select() {
        System.out.println("普通人的查找");
    }
}

如果我们想要在save()方法执行之前,想要检查一下执行该方法用户是否具有权限,该怎么做呢?
第一,我们可以在该类中直接写一个权限检验的方法,然后再save()执行之前进行调用。
第二,我们可以写一个顶层的父类,在父类中写上权限检验的方法,这样子类继承父类以后就可以直接调用该方法了。

这两个方法有几个问题:试想一下,如果我们的项目有成千上百个方法在执行前需要检验权限,那么我们不是要在每个方法执行前添加检验权限的方法?这是第一种方法的缺点,第二个方法虽然用继承的方式减去一些不必要的重复代码,但是我们依旧要在方法之前前调用。

这时候,就有厉害的人物提出了AOP,他是OOP的一个补充,那么AOP到底能干什么呢?

问题2.AOP的作用?
AOP的底层原理是动态代理,请看下面代码

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class MyProxy implements InvocationHandler {
    private StudentDAO studentDAO;
    public MyProxy(StudentDAO studentDAO){
        this.studentDAO=studentDAO;
    }

    public Object CreateProxy(){
      Object proxy= Proxy.newProxyInstance(studentDAO.getClass().getClassLoader(),studentDAO.getClass().getInterfaces(),this);
      return proxy;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if("save".equals(method.getName())){
            //如果是保存方法
            System.out.println("保存之前要校验权限");
            //执行完检验以后,继续回到正常的逻辑
            return method.invoke(studentDAO,args);
        }

        return method.invoke(studentDAO,args);
    }

}

该类实现了InvocationHanlder,并重写了Invoke的方法,该类的构造方法中,需要传入一个对象,就是需要创建代理的对象,谁需要创建代理就传入谁,CreateProxy中调用了JDK提供的创建动态代理的方法,invoke方法中,我们进行判断,如果代理的方法名称是save,我们就要执行权限校验,然后返回正常的执行逻辑。

这样做有什么好处呢?

    @Test
    public void demo1(){
        //传统方法
        StudentDAO studentdao=new StudentDAOImpl();
        StudentDAO proxy= (StudentDAO) new MyProxy(studentdao).CreateProxy();
        proxy.save();
        proxy.delete();
        proxy.select();
        proxy.update();


    }

    @Test
    public void demo2(){
        //这里我们的普通人在执行保存之前也需要进行校验,需要添加任何代码嘛?
        StudentDAO studentdao=new Person();
        StudentDAO proxy= (StudentDAO)new MyProxy(studentdao).CreateProxy();
        proxy.save();
        proxy.delete();
        proxy.select();
        proxy.update();

    }

执行结果如下:
在这里插入图片描述
在这里插入图片描述

我们只是添加了一个代理,所有实现了StudentDAO接口的类,在执行save方法之前可以使用代理类进行权限检验。

这里不得不提一下,对于不使用接口的业务类,JDK无法创建动态代理,那如果我们想要代理没有实现接口的类该怎么做呢?这就要看CGlib了!CGlib采用非常底层的字节码技术,可以为一个创建子类,解决无接口代理的问题,详细使用请看下面

package com.ibuyi.free.Case_four;

public class Product {

    public void save() {
        System.out.println("商品的保存");
    }


    public void delete() {
        System.out.println("商品的删除");
    }


    public void update() {
        System.out.println("商品的修改");
    }


    public void select() {
        System.out.println("商品的查找");
    }
}


public class MyCGProxy implements MethodInterceptor {
    private Product product;
    public MyCGProxy(Product product){
        this.product=product;
    }

    public Object createProxy(){
        //1.创建核心类
        Enhancer enhancer=new Enhancer();
        //2.设置
        enhancer.setSuperclass(product.getClass());
        //3.设置回调
        enhancer.setCallback(this);
        //4.创建代理
        Object proxy=enhancer.create();
        return proxy;
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
       if(method.getName().equals("save")){
           System.out.println("商品保存前需要校验权限");
           return methodProxy.invokeSuper(o,objects);
       }
        return methodProxy.invokeSuper(o,objects);
    }
}

  @Test
    public void demo1(){
        Product product=new Product();
        MyCGProxy myCGProxy=new MyCGProxy(product);
        Product proxy= (Product) myCGProxy.createProxy();
        proxy.save();
        proxy.delete();
        proxy.select();
        proxy.update();
    }

就这样,就算没有接口的业务类也能实现代理!

猜你喜欢

转载自blog.csdn.net/weixin_43927892/article/details/104402245