zoukankan      html  css  js  c++  java
  • Spring AOP原理

    一、AOP介绍

    AOP 全称Aspect Orient Programming,即面向切面编程,解决代码复用问题。是对OOP(Object Orient Programming)的一种补充。AOP实现的关键在于AOP框架自动创建的AOP代理,AOP代理分为静态代理和动态代理。

    应该场景:广泛应用于处理一些具有横切性质的系统服务,如日志输出,安全控制,事务管理,缓存,对象池,异常处理等

    1、静态代理:指使用AOP框架提供的命令进行编译,从而在编译阶段就生成AOP代理。也称编译时增强。

        静态代理说白了,就是程序运行前就已经存在代理类的字节码文件、代理类和原始类的关系在运行前就已经确定了。

    1) 静态代理Demo

    IPerson接口

    public interface IPerson {
        //找工作
        void findJob();
    
    }
    
    ZhangSan要去找工作
    /**
     * 目标对象
     */
    public class ZhangSan implements  IPerson {
        @Override
        public void findJob() {
            System.out.println("我是张三,我在找工作...");
        }
    }
    

      

    代理类:人才市场

    public class PersonMarketProxy implements  IPerson{
    
        private  IPerson target = new ZhangSan();
    
        @Override
        public void findJob() {
            System.out.println("找工作前,请把简历给我");
            target.findJob();
            System.out.println("找到工作后,要好好工作");
        }
    }
    

      

    测试

    public class Main {
        public static void main(String[] args) {
            //代理对象
            IPerson proxy = new PersonMarketProxy();
            //代理对象执行代理方法
            proxy.findJob();
        }
    }
    

      静态代理虽然保证了业务。如果代理方法增多,势必每一个方法多要进行代理。除了实现类要实现这个方法,代理类也要实现这个方法。维护成本增加。

          而动态代理很好的解决了这个问题。

      

    2、动态代理:在运行时借助于JDK动态代理、CGLIG等内存中“临时”生成的AOP动态代理类。也称运行时增强。

    动态代理Demo

    2.1 IPerson接口

    public interface IPerson {
        //找工作
        void findJob();
    
    }
    

     2.2 目标对象Zhangsan类

    /**
     * 目标对象
     */
    public class ZhangSan implements IPerson {
        @Override
        public void findJob() {
            System.out.println("我是张三,我在找工作...");
        }
    }
    

      

    2.3 ProxyFactory 类
    **
     * 动态代理
     * 给多个目标对象生成代理对象
     */
    public class ProxyFactory {
    
        //目标对象
        private Object target;
    
        public  ProxyFactory(Object target){
            this.target = target;
        }
    
        //返回代理对象
        public Object getProxyObject(){
            Object proxy = Proxy.newProxyInstance(
                    target.getClass().getClassLoader(), //目标对象类加载器
                    target.getClass().getInterfaces(), //目标对象实现的所有接口
                    new InvocationHandler() {           //执行代理对象方法时候触发
                        @Override
                        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                            String methodName = method.getName();
                            Object result = null;
                            if("findJob".equals(methodName)){
                                System.out.println("找工作前,请把简历给我");
                                result = method.invoke(target, args);
                                System.out.println("找到工作后,要好好工作");
                            }else{
                                result = method.invoke(target, args);
                            }
                            return result;
                        }
                    });
            return  proxy;
        }
    }
    

      

    2.4  测试

    public class Main {
        public static void main(String[] args) {
            //目标对象
            IPerson target = new ZhangSan();
            System.out.println("目标对象:" + target.getClass());
            //代理对象
            IPerson proxy = (IPerson)new ProxyFactory(target).getProxyObject();
            System.out.println("代理对象:" +  proxy.getClass());
            //代理对象执行代理方法
            proxy.findJob();
    
            createProxyClassFile(IPerson.class);
        }
    
        private static void createProxyClassFile(Class c){
            byte[] data = ProxyGenerator.generateProxyClass("$Proxy0", new Class[]{c});
            try{
                FileOutputStream fileOutputStream = new FileOutputStream("$Proxy0.class");
                fileOutputStream.write(data);
                fileOutputStream.close();
            }catch (FileNotFoundException e){
                e.printStackTrace();
            }catch (IOException e){
                e.printStackTrace();
            }
        }
    }
    

      

    
    

      

    2.5 打印结果:

    IPerson proxy = (IPerson)new ProxyFactory(target).getProxyObject();
    这行代码其实是JDK动态生成了一个类去实现接口
    public final class $Proxy0 extends Proxy implements IPerson
    完整的代码如2.6.

    2.6 然后使用使用createProxyClassFile,将代理类使用写入文件,文件的内容为

    //
    // Source code recreated from a .class file by IntelliJ IDEA
    // (powered by Fernflower decompiler)
    //
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    import java.lang.reflect.UndeclaredThrowableException;
    import spring_springmvc.proxyDongTai.IPerson;
    
    public final class $Proxy0 extends Proxy implements IPerson {
        private static Method m1;
        private static Method m2;
        private static Method m3;
        private static Method m0;
    
        public $Proxy0(InvocationHandler var1) throws  {
            super(var1);
        }
    
        public final boolean equals(Object var1) throws  {
            try {
                return ((Boolean)super.h.invoke(this, m1, new Object[]{var1})).booleanValue();
            } catch (RuntimeException | Error var3) {
                throw var3;
            } catch (Throwable var4) {
                throw new UndeclaredThrowableException(var4);
            }
        }
    
        public final String toString() throws  {
            try {
                return (String)super.h.invoke(this, m2, (Object[])null);
            } catch (RuntimeException | Error var2) {
                throw var2;
            } catch (Throwable var3) {
                throw new UndeclaredThrowableException(var3);
            }
        }
    
        public final void findJob() throws  {
            try {
                super.h.invoke(this, m3, (Object[])null);
            } catch (RuntimeException | Error var2) {
                throw var2;
            } catch (Throwable var3) {
                throw new UndeclaredThrowableException(var3);
            }
        }
    
        public final int hashCode() throws  {
            try {
                return ((Integer)super.h.invoke(this, m0, (Object[])null)).intValue();
            } catch (RuntimeException | Error var2) {
                throw var2;
            } catch (Throwable var3) {
                throw new UndeclaredThrowableException(var3);
            }
        }
    
        static {
            try {
                m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")});
                m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
                m3 = Class.forName("spring_springmvc.proxyDongTai.IPerson").getMethod("findJob", new Class[0]);
                m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
            } catch (NoSuchMethodException var2) {
                throw new NoSuchMethodError(var2.getMessage());
            } catch (ClassNotFoundException var3) {
                throw new NoClassDefFoundError(var3.getMessage());
            }
        }
    }
    

      

     2.7 使用JDK生成动态代理的前提示目标类必须有实现的接口。 CGLIB是以动态生成的子类继承目标方式实现。在运行期动态的内存中构建一个子类 

    AOP是基于动态代理的

    AOP是方法级别的

    AOP可以分离业务和重复代码

    二、实现AOP的技术

    主要实现AOP思想的技术有AspectJ和Spring AOP

    1、AspectJ的底层技术

        AspectJ的底层技术是静态代理,即用一种AspectJ支持的特定语言编写切面,通过一个命令来编译,生成一个新的代理类。写着是编译时增强,相对于运行时增强性能更好。

    2、Spring AOP

        Spring AOP采用动态代理,在运行期间对业务方法进行增强,不会生成新类。Spring AOP提供了对JDK动态代理支持和CGLib的支持。

        JDK动态代理只能为接口创建动态代理实例,而不能对类创建动态代理。需要获得被目标类的接口信息(使用反射技术),生成一个实现了代理接口的动态代理类(字节码),再通过反射机制获得动态代理的构造函数,利用构造函数生成代理类的实例对象,在调用具体方法前调用invokeHandler方法处理。

        CGLib动态代理需要依赖asm包,把被代理对象类的class文件加载进来,修改其字节码生成子类。

         但是Spring AOP基于注解配置的情况下,需要依赖于AspectJ包的标准注解,但是不需要额外的编译及AspectJ的织入器,而基于XML配置不需要。

    Spring Aop过程

    1、创建容器对象的时,根据切入点表达式拦截的类,生成代理对象

    2、 如果有接口,使用JDK代理。反之,使用CGLIB代理。然后从容器中获取代理对象,在运行期间植入“切面” 类的方法。

        如果目标类没有实现接口,且class为final, 则不能进行Spring AOP编程。

    JDK动态代理和CGLib动态代理的区别

    JDK动态代理需要接口,基于反射实现。(反射虚拟生成代理类)

    CGLib动态代理需要子类实现。基于ASM字节码包装的一个类库。(基于ASM字节码技术虚拟生成代理类)

     

  • 相关阅读:
    PHP多进程编程
    2013年中国数据库大会PPT
    python学习笔记
    策略分析方法论
    Linux操作系统下定时发送邮件
    PHP初学
    Linux操作下的进程管理利器 Supervise
    Hive中小表与大表关联(join)的性能分析zz
    工作杂记4
    PostgreSQL 13 源码安装【转载】 规格严格
  • 原文地址:https://www.cnblogs.com/linlf03/p/10469961.html
Copyright © 2011-2022 走看看