• springAOP之代理


    AOP是指面向切面编程。

    在学习AOP之前先来了解一下代理,因为传说中的AOP其实也对代理的一种应用。

    首先来看这样一段代码:

    public interface Hello {
        void say(String name);
    }

    实现类:

    public class HelloImpl implements Hello {
    
        public void say(String name) {
            System.out.println("Hello!"+name);
        }
    }

    如果现在需要在say调用的前后做一些操作,那最简单的方法就是直接在say方面中增加代码,但这样肯定不够优雅。

    这时候可以用第一种代理模式:静态代理

    public class HelloProxy implements Hello {
    
        private Hello hello;
    
        public HelloProxy(){
    
            hello=new HelloImpl();
    
        }
    
        public void say(String name) {
            before();
            hello.say(name);
            after();
        }
    
        private void before(){
            System.out.println("before");
        }
    
        private void after(){
            System.out.println("after");
        }
    }

    这样我们在保留原来HelloImple中say方法的同时,用HelloProxy代理在say方法的前后增加了before和after

    调用一下试试:

     public static void main(String[] args){
            Hello helloProxy=new HelloProxy();
            helloProxy.say("Gary");
    }

    运行结果:

    那么新的问题来了,如果每次都需要写一个代理类不也很麻烦吗,项目中就会有很多个xxxProxy,因此就出现了 JDK动态代理

    代码如下:

    public class DynamicProxy implements InvocationHandler {
    
        private Object target;
    
        public DynamicProxy(Object target){
           this.target=target;
        }
    
        public <T> T getProxy(){
            return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
        }
    
    
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            before();
            Object result=method.invoke(target,args);
            after();
            return result;
        }
    
        private void before(){
            System.out.println("before");
        }
    
        private void after(){
            System.out.println("after");
        }
    }

    注:Proxy.newProxyInstance()参数有三个:

    • ClassLoader
    • 该实现类的所有接口
    • 动态代理对象

    在该类中target就是被代理的对象,该类实现了InvocationHandler接口,通过反射去动态创建Hello接口的代理类

    那么现在的调用就变简单了:

     public static void main(String[] args){
            DynamicProxy dynamicProxy=new DynamicProxy(new HelloImpl());
            Hello helloProxy= dynamicProxy.getProxy();
            helloProxy.say("gary");
        }

    用了JDK动态代理后,我们觉得还是有问题,如果要代理一个没有接口的类,该怎么办呢,于是就轮到我们的 CGlib动态代理 出场了。

    在Spring、Hibernate等框架中都用到了CGlib动态代理,maven资源如下:

     <!-- https://mvnrepository.com/artifact/cglib/cglib -->
            <dependency>
                <groupId>cglib</groupId>
                <artifactId>cglib</artifactId>
                <version>3.2.6</version>
            </dependency>

    他的使用需要实现MethodInterceptor类,并完成intercept方法。CGlib 提供的是方法级别的代理:

    public class CGLibProxy implements MethodInterceptor {
    
        public <T> T getProxy(Class<T> cls){
            return (T) Enhancer.create(cls,this);
        }
    
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            before();
            Object result=methodProxy.invokeSuper(o,objects);
            after();
            return result;
        }
    
        private void before(){
            System.out.println("before");
        }
    
        private void after(){
            System.out.println("after");
        }
    }

    这样使用时就不需要提供接口了:

      public static void main(String[] args){
            CGLibProxy cgLibProxy= new CGLibProxy();
            Hello hello=cgLibProxy.getProxy(HelloImpl.class);
            hello.say("Gary");
        }

    最后再改造一下,加上单例模式就更完美了

        private static CGLibProxy instance=new CGLibProxy();
        
        private CGLibProxy(){
        }
    public static CGLibProxy getInstance(){ return instance; }

    调用就改为:

    public static void main(String[] args){
            Hello hello=CGLibProxy.getInstance().getProxy(HelloImpl.class);
            hello.say("Gary");
        }
  • 相关阅读:
    linux 如何使用密钥登录 (CentOs)
    linux修改ssh端口 以及禁止root远程登录 (实验机 CentOs)
    查看Windows端口及端口关闭方法
    使用 Linux 终端 SSH 登录 VPS
    修改Chrome默认搜索引擎为Google.com
    Windows 小技巧: 變更輸入法順序
    CentOS 安装BitTorrent Sync详细步骤
    Android手机部分名词浅谈
    PPTP模式跟L2TP模式有什么不同
    .CO域名快被这帮搞IT的玩坏了……
  • 原文地址:https://www.cnblogs.com/GuoJunwen/p/9008610.html
Copyright © 2020-2023  润新知