zoukankan      html  css  js  c++  java
  • 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();
        }
    

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

  • 相关阅读:
    EasyUI treegrid 加载checked
    html 文字垂直居中
    SQLSERVER 2008 查询数据字段名类型
    EasyUI TreeJson
    win7 网站发布备注
    LVS Nginx HAProxy 优缺点
    快速安装laravel和依赖
    Whoops, looks like something went wrong
    View.findViewById()和Activity.findViewById()区别
    ListView下拉刷新,上拉自动加载更多
  • 原文地址:https://www.cnblogs.com/hzcya1995/p/13309416.html
Copyright © 2011-2022 走看看