美文网首页
从零开始写Spring AOP框架-(基本技术)

从零开始写Spring AOP框架-(基本技术)

作者: d3f59bfc7013 | 来源:发表于2019-08-12 22:45 被阅读0次

    AOP为Aspect Oriented Programming的缩写,意为:面向切面编程。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。这里介绍AOP的基本技术JDK动态代理和Cglib

    示例代码github链接

    应用场景

    public interface Greeting {
        void sayHello();
    }
    
    class Programmer implements Greeting {
        @Override
        public void sayHello() {
            System.out.println("Hello,I'm programmer");
        }
    }
    
    class Student implements Greeting {
        @Override
        public void sayHello() {
            System.out.println("Hello,I'm student");
        }
    }
    
    class Teacher implements Greeting {
        @Override
        public void sayHello() {
            System.out.println("Hello,I'm teacher");
        }
    }
    
    public class Client {
        public static void main(String args[]) {
            Greeting greeting=new Student();
            greeting.sayHello();
            greeting=new Teacher();
            greeting.sayHello();
            greeting=new Programmer();
            greeting.sayHello();
        }
    }
    
    ebIptA.jpg

    需要在sayHello方法前后,分别输出call before,call after.

    方法一(写死代码)

    我们可以用最简单的方式,写死代码来完成这个功能。

    class Programmer implements Greeting {
        @Override
        public void sayHello() {
            System.out.println("call before");
            System.out.println("Hello,I'm programmer");
            System.out.println("call after");
        }
    }
    
    class Student implements Greeting {
        @Override
        public void sayHello() {
            System.out.println("call before");
            System.out.println("Hello,I'm student");
            System.out.println("call after");
        }
    }
    
    class Teacher implements Greeting {
        @Override
        public void sayHello() {
            System.out.println("call before");
            System.out.println("Hello,I'm teacher");
            System.out.println("call after");
        }
    }
    
    public class Client1 {
        public static void main(String args[]) {
            Greeting greeting=new Student();
            greeting.sayHello();
            greeting=new Teacher();
            greeting.sayHello();
            greeting=new Programmer();
            greeting.sayHello();
        }
    }
    
    ebIPpt.jpg

    这种写死代码的方式,如果类文件多至几百个,那么就需要改几百处代码。同时,如果我们引用的是第三方jar,这个时候我们不太容易去改变第三方的jar。

    方法二(静态代理)

    我们不去写死原来文件代码,我们给greeting接口写一个静态代理

    public class GreetingStaticProxy implements Greeting {
        private Greeting greeting;
    
        public GreetingStaticProxy(Greeting greeting) {
            this.greeting = greeting;
        }
    
        @Override
        public void sayHello() {
            before();
            greeting.sayHello();
            after();
        }
    
        private void after() {
            System.out.println("call after");
        }
    
        private void before() {
            System.out.println("call before");
        }
    }
    
    public class Client2 {
        public static void main(String args[]) {
            Greeting studentStaticProxy=new GreetingStaticProxy(new Student());
            studentStaticProxy.sayHello();
            Greeting teacherStaticProxy=new GreetingStaticProxy(new Teacher());
            teacherStaticProxy.sayHello();
            Greeting programmerStaticProxy=new GreetingStaticProxy(new Programmer());
            programmerStaticProxy.sayHello();
        }
    }
    
    ebIi1P.jpg

    我们通过给greeting接口提供一个静态代理GreetingStaticProxy成功的解决了写死代码的问题,但是如果接口增多,比如增加一个Complain接口,那么就需要增加一个ComplainStaticProxy。最终XxxxStaticProxy类会越来越多。如何才能让这些代理类尽可能的减少?最好只有一个代理类,我们可以用JDK的动态代理。

    方法三(JDK动态代理)

    JDK动态代理关键类,InvocationHandler,Proxy这两个类。

    public class DynamicProxy {
    
        public static <T> T createProxy(final T t) {
            return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), t.getClass().getInterfaces(), new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    before();
                    Object result = method.invoke(t, args);
                    after();
                    return result;
                }
                private void after() {
                    System.out.println("call after");
                }
    
                private void before() {
                    System.out.println("call before");
                }
            });
        }
    }
    
    
    public class Client3 {
        public static void main(String args[]) {
            Greeting studentDynaminProxy = DynamicProxy.createProxy(new Student());
            studentDynaminProxy.sayHello();
            Greeting teacherDynicProxy = DynamicProxy.createProxy(new Teacher());
            teacherDynicProxy.sayHello();
            Greeting programmerDynicProxy = DynamicProxy.createProxy(new Programmer());
            programmerDynicProxy.sayHello();
        }
    }
    
    ebI9fI.jpg

    及时增加了很多Greeting之外的接口,我们都可以通过DynamicProxy一个代理类来进行代理。但是这样做仍然存在一个问题,就是JDK提供的代理类只能代理接口,而不能代理没有接口的类。有什么方案可以解决这个问题么?

    方法四(Cglib代理)

    Cglib代理关键类,MethodInterceptor,Enhancer这两个类

    public class CglibDynamicProxy {
        public static <T> T createProxy(Class<T> tClass) {
            return (T) Enhancer.create(tClass, new MethodInterceptor() {
                public Object intercept(Object targerObject, Method method, Object[] params, MethodProxy methodProxy) throws Throwable {
                    before();
                    Object result = methodProxy.invokeSuper(targerObject, params);
                    after();
                    return result;
                }
                private void after() {
                    System.out.println("call after");
                }
                private void before() {
                    System.out.println("call before");
                }
            });
        }
    }
    
    public class Client4 {
        public static void main(String args[]) {
            Student studentCglibProxy=CglibDynamicProxy.createProxy(Student.class);
            studentCglibProxy.sayHello();
            Teacher teacherCglibProxy=CglibDynamicProxy.createProxy(Teacher.class);
            teacherCglibProxy.sayHello();
            Programmer programmerCglibProxy=CglibDynamicProxy.createProxy(Programmer.class);
            programmerCglibProxy.sayHello();
        }
    }
    

    [图片上传失败...(image-3e97d1-1565621044900)]

    Spring AOP就是基于JDK的动态代理和Cglib来实现的。

    相关文章

      网友评论

          本文标题:从零开始写Spring AOP框架-(基本技术)

          本文链接:https://www.haomeiwen.com/subject/eptmjctx.html