• Java代理模式


    静态代理

    代理类自己编写,在编译器已经确认了代理类。

    实现步骤

    1.定义接口及其实现类

    public interface SayHelloService {
        void say();
    }
    public class SayHelloServiceImpl implements SayHelloService {
        @Override
        public void say() {
            System.out.println("Hello Bitch");
        }
    }


    2.定义类代理对象

    public class SayHelloServiceProxy implements SayHelloService {
        private SayHelloService target;
    
        public SayHelloServiceProxy(SayHelloService service) {
            this.target = service;
        }
        
        @Override
        public void say() {
            System.out.println("记录日志。。。。。。");
            target.say();
            System.out.println("清理数据。。。。。。");
        }
    
        public static void main(String[] args) {
            SayHelloServiceProxy proxy = new SayHelloServiceProxy(new SayHelloServiceImpl());
            proxy.say();
        }
    
    }

    代理类实现了目标对象的接口,对原有得接口做了扩展,其中所有的对象都是在编译期都确定好了。

    缺点

    需要代理对象实现目标对象的接口,假如目标对象方法很多或者需要代理多个对象,复杂度就会很高。

    而动态代理不需要在编译期确定代理类,可以在运行时期动态生成,反射是动态代理的一种实现方式。

    java中的动态代理

    主要由以下两种方式实现:

    JDK动态代理

    JDK动态代理需要目标对象实现一个或多个接口,否则只能使用CGLIB实现动态代理。

    实现步骤

    1.定义目标类和公共接口

    public interface UserService {
         void add();
    }
    
    public class UserServiceImpl implements UserService {
        @Override
        public void add() {
            // TOD Auto-generated method stub
            System.out.println("-------add--------");
        }
    }


    2.定义调用处理器类,可以再运行时生成代理类,并带上一些增强的功能

    java.lang.reflect.Proxy : 这是生成代理类的主类,通过 Proxy 类生成的代理类都继承了 Proxy 类,即 DynamicProxyClas extends Proxy。

    java.lang.reflect.InvocationHandler:调用处理类

    public class MyInvocationHandler implements InvocationHandler {
        private Object target;
    
        public MyInvocationHandler(Object target) {
            super();
            this.target = target;
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("------begin " + method.getName() + "------");
            Object result = method.invoke(target, args);
            System.out.println("------end " + method.getName() + "-------");
            return result;
        }
    
        public Object getProxy() {
            return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), target.getClass().getInterfaces(), this);
        }
    
        public static void main(String[] args) {
            UserService service = new UserServiceImpl();
            MyInvocationHandler handler = new MyInvocationHandler(service);
            UserService proxy = (UserService) handler.getProxy();
            proxy.add();
        }
    
    }

    原理解析

    上面关键点在于Proxy.newProxyInstance() 方法创建了一个代理对象,查看他的源码,封装了创建代理类及对象的方法,如下:

    public static Object newProxyInstance(ClassLoader loader,
                                         Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
        Objects.requireNonNull(h);
    
        final Class<?>[] intfs = interfaces.clone();
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }
    
        /*
         * Look up or generate the designated proxy class.
         */
        Class<?> cl = getProxyClass0(loader, intfs);
    
        /*
         * Invoke its constructor with the designated invocation handler.
         */
        try {
            if (sm != null) {
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }
    
            final Constructor<?> cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            if (!Modifier.isPublic(cl.getModifiers())) {
                AccessController.doPrivileged(new PrivilegedAction<Void>() {
                    public Void run() {
                        cons.setAccessible(true);
                        return null;
                    }
                });
            }
            return cons.newInstance(new Object[]{h});
        } catch (IllegalAccessException|InstantiationException e) {
            throw new InternalError(e.toString(), e);
        } catch (InvocationTargetException e) {
            Throwable t = e.getCause();
            if (t instanceof RuntimeException) {
                throw (RuntimeException) t;
            } else {
                throw new InternalError(t.toString(), t);
            }
        } catch (NoSuchMethodException e) {
            throw new InternalError(e.toString(), e);
        }
    }

    其中的getProxyClass0(loader, intfs)实际生成了代理类,这个代理类是动态代理的关键,因为是在运行时动态生成的,我们可以通过下面的方法将生成的文件显示出来,探探究竟

    public static void main(String[] args) throws IOException {
    
        byte[] testProxies = ProxyGenerator.generateProxyClass("Proxy0", UserServiceImpl.class.getInterfaces());
        String path = "E:/userProxies.class";
        FileOutputStream fileOutputStream = new FileOutputStream(path);
        fileOutputStream.write(testProxies);
        fileOutputStream.flush();
        fileOutputStream.close();
    
    }

    反编译生成的文件如下

    public final class Proxy0 extends Proxy implements UserService {
        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});
            } 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 add() 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);
            } catch (RuntimeException | Error var2) {
                throw var2;
            } catch (Throwable var3) {
                throw new UndeclaredThrowableException(var3);
            }
        }
    
        static {
            try {
                m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
                m2 = Class.forName("java.lang.Object").getMethod("toString");
                m3 = Class.forName("org.example.proxy.inter.UserService").getMethod("add");
                m0 = Class.forName("java.lang.Object").getMethod("hashCode");
            } catch (NoSuchMethodException var2) {
                throw new NoSuchMethodError(var2.getMessage());
            } catch (ClassNotFoundException var3) {
                throw new NoClassDefFoundError(var3.getMessage());
            }
        }
    }

    分析:jdk动态生成了一个代理类,继承于Proxy,当我们调用add()方法时,将此方法当做参数传了进去,super.h.invoke(this, m3, (Object[])null)。 最终调用了InvocationHandler的invoke方法。

    InvocationHandler的invoke:

    public Object invoke(Object obj, Object... args)
        throws IllegalAccessException, IllegalArgumentException,
           InvocationTargetException
    {
        if (!override) {
            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
                Class<?> caller = Reflection.getCallerClass();
                checkAccess(caller, clazz, obj, modifiers);
            }
        }
        MethodAccessor ma = methodAccessor;             // read volatile
        if (ma == null) {
            ma = acquireMethodAccessor();
        }
        return ma.invoke(obj, args);
    }


    通过反射,得到被代理对象的方法实现。

    一整套下来,达到了代理的功能。

    Cglib动态代理

    Cglib 是一个强大的高性能的代码生成包,它可以在运行期扩展 Java 类与实现 Java接口。

    public class CglibProxy implements MethodInterceptor {
        private Enhancer enhancer = new Enhancer();
    
        public Object getProxy(Class clazz) {
            //设置需要创建子类的类
            enhancer.setSuperclass(clazz);
            enhancer.setCallback(this);
            //通过字节码技术动态创建子类实例
            return enhancer.create();
        }
    
        //实现 MethodInterceptor接口方法
        @Override
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
            System.out.println("前置代理");
            //通过代理类调用父类中的方法
            Object result = methodProxy.invokeSuper(obj, args);
            System.out.println("后置代理");
            return result;
        }
    
        public static void main(String[] args) {
            CglibProxy proxy = new CglibProxy();
            //通过生成子类的方式创建代理类
            UserServiceImpl proxyImp = (UserServiceImpl) proxy.getProxy(UserServiceImpl.class);
            proxyImp.add();
    
        }
    }

    二者区别

    使用动态代理的对象必须实现一个或多个接口

    使用 cglib 代理的对象则无需实现接口,达到代理类无侵入。

    SpringAOP

    主要由JDK动态代理和CGLIB动态代理实现

    JDK 动态代理通过反射来接收被代理的类,并且要求被代理的类必须实现一个接口。JDK 动态代理的核心是 InvocationHandler 接口和 Proxy 类。如果目标类没有实现接口,那么 Spring AOP 会选择使用 CGLIB 来动态代理目标类。

    CGLIB(Code Genration Libray),是一个代码生成的类库,可以在运行时动态的生成某个类的子类,CGLIB 是通过继承的方式做的动态代理,因此如果某个类被标记为 final,那么它是无法使用 CGLIB 做动态代理的。

  • 相关阅读:
    rsync命令 SCP命令
    Linux 性能分析 工具命令
    ntp时间服务器 时间同步
    Linux 邮件服务
    linux 手工释放内存 高内存 内存回收 方法思路
    LVM 逻辑卷 (logica volume manager)
    Linux 磁盘原理与管理 (分区 挂载)
    linux中查看nginx、apache、php、mysql配置文件路径
    shell脚本 监控ps 不存在则重启
    Shell脚本 一键重启
  • 原文地址:https://www.cnblogs.com/jiezai/p/15188774.html
Copyright © 2020-2023  润新知