zoukankan      html  css  js  c++  java
  • proxy 简化版本

    public interface People {
        public String eat(String param);
    }
    
    public class Jack implements People {
        @Override
        public String eat(String param) {
            System.out.println("=========Jack老师喜欢吃东=======");
            return "=========Jack老师喜欢吃东=======";
        }
    }
    
    public class Advice implements InvocationHandler1 {
        
        People people;//接口,传进来实例
        
        public Advice(People people) {
            this.people = people;
        }
        
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            //前置增强
            before();
            //被代理方
            Object value = method.invoke(people,args);
            //后置增强
            after();
            return value;
        }
    
        private void before() {
            System.out.println("===========jack吃饭之前�?要洗�?==========");
        }
    
        private void after() {
            System.out.println("===========jack吃完饭要洗碗=============");
        }
    }
    
    public class MyTest {
        public static void main(String[] args) {
            People proxyObject = (People) Proxy1.newProxyInstance(MyTest.class.getClassLoader(),
                    new Class<?>[] { People.class }, new Advice(new Jack())); // 获取代理,MyTest.class.getClassLoader()是类加载器,
            //new Advice是对实现类new Jack()的增强,People.class是接口,在吃饭之前之后要洗手,
    
            proxyObject.eat("chi");// proxyObject是在内存的代理对象,对象名字$Proxy数字,
      
            //proxyObject = com.zhuguang.jack.aop.jdkProxy.Jack@5e5792a0,里面的h = com.zhuguang.jack.aop.jdkProxy.Advice@26653222

         // $Proxy0/1 extends Proxy1 implements People,Proxy里面有一个属性InvocationHandler h; // proxyObject.eat("chi")调用的是h.invoke(Object proxy, Method method, Object[] // args), // h.invoke()方法调到advice.invoke(), } }
    public class Proxy1 implements java.io.Serializable {
    
        private static final long serialVersionUID = -2222568056686623797L;
        private static final Class<?>[] constructorParams = { InvocationHandler1.class };
        private static final WeakCache1<ClassLoader, Class<?>[], Class<?>> proxyClassCache = new WeakCache1<>( new ProxyClassFactory());
        protected InvocationHandler1 h;
        private Proxy1() {}
    
        protected Proxy1(InvocationHandler1 h) {
            Objects.requireNonNull(h);
            this.h = h;
        }
    
        //一个利用给定的类加载器和接口类数组生成,定义并返回代理类对象的工厂方法。代理类生成工厂。
        private static final class ProxyClassFactory implements BiFunction<ClassLoader, Class<?>[], Class<?>> {
            private static final String proxyClassNamePrefix = "$Proxy1";
            private static final AtomicLong nextUniqueNumber = new AtomicLong();
            @Override
            public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
                String proxyPkg = null; // 代理类的包名
                int accessFlags = Modifier.PUBLIC | Modifier.FINAL;//生成代理类的访问标志, 默认是public final的
                //验证所有非公共代理接口都在同一个包中
                for (Class<?> intf : interfaces) {
                    int flags = intf.getModifiers();//获取接口的访问标志
                    //如果接口的访问标志不是public, 那么生成代理类的包名和接口包名相同
                    if (!Modifier.isPublic(flags)) {
                        accessFlags = Modifier.FINAL;//生成的代理类的访问标志设置为final
                        String name = intf.getName();//获取接口全限定名, 例如:java.util.Collection
                        int n = name.lastIndexOf('.');
                        String pkg = ((n == -1) ? "" : name.substring(0, n + 1));//剪裁后得到包名:java.util
                        if (proxyPkg == null) {//生成的代理类的包名和接口包名是一样的
                            proxyPkg = pkg;
                        } else if (!pkg.equals(proxyPkg)) {//代理类如果实现不同包的接口, 并且接口都不是public的, 那么就会在这里报错
                            throw new IllegalArgumentException("non-public interfaces from different packages");
                        }
                    }
                }
                //如果接口访问标志都是public的话, 那生成的代理类都放到默认的包下:com.sun.proxy
                if (proxyPkg == null) {
                    proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
                }
                long num = nextUniqueNumber.getAndIncrement();
                String proxyName = proxyPkg + proxyClassNamePrefix + num;
                byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags);//com.sun.proxy.$Proxy10,[interface proxy.People],
                try {// 返回代理类对象,根据二进制文件生成相应的Class实例。
                    return defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length);
                } catch (Exception  e) {
                    System.out.println(e.toString());
                }
                return null;
            }
        }
    
        public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler1 h) throws IllegalArgumentException {
            final Class<?>[] intfs = interfaces.clone();//[interface proxy.People], 
            Class<?> cl =  proxyClassCache.get(loader, intfs);//先走WeakCache的get(),再通过Factory的get方法,最后通过ProxyClassFactory的apply()获取代理类的Class对象。
            try {
                // 从代理类对象中查找参数为InvocationHandler的构造器,获取参数类型是InvocationHandler.class的代理类构造器
                final Constructor<?> cons = cl.getConstructor(constructorParams);
                final InvocationHandler1 ih = h;
                // 检测构造器是否是Public修饰,如果不是则强行转换为可以访问的。
                if (!Modifier.isPublic(cl.getModifiers())) {
                    AccessController.doPrivileged(new PrivilegedAction<Void>() {
                        public Void run() {
                            cons.setAccessible(true);
                            return null;
                        }
                    });
                }
                // 通过反射,将h作为参数,实例化代理类,返回代理类实例。2.利用反射技术实例化代理类,并返回实例化对象。传入InvocationHandler实例去
                //构造一个代理类的实例,所有代理类都继承自Proxy, 因此这里会调用Proxy的构造器将InvocationHandler引用传入,
                return cons.newInstance(new Object[] { h });
            } catch (Exception e) {
                throw new InternalError(e.toString(), e);
            } 
        }
    
        private static native Class<?> defineClass0(ClassLoader loader, String name, byte[] b, int off, int len);
    }
    final class WeakCache1<K, P, V> {
        private final BiFunction<K, P, V> valueFactory;
    
        public WeakCache1(BiFunction<K, P, V> valueFactory) {//构造方法,,,
            this.valueFactory = Objects.requireNonNull(valueFactory);//new ProxyClassFactory()
        }
    
        public V get(K key, P parameter) { 
            Supplier<V> supplier = null; 
            Factory factory = null;
    
            while (true) {
                if (supplier != null) {
                    V value = supplier.get();
                    if (value != null) {
                        return value; 
                    }
                }
                if (factory == null) {
                    factory = new Factory(key, parameter );
                }
                if (supplier == null) {
                    if (supplier == null) {
                        supplier = factory;
                    }
                } 
            }
        }
    
        private final class Factory implements Supplier<V> {
            private final K key;
            private final P parameter;
    
            Factory(K key, P parameter) {
                this.key = key;
                this.parameter = parameter;
            }
    
            @Override
            public synchronized V get() {  
                V value = null;
                // valueFactory就是WeakCache的valueFactory属性,因为Factory是WeakCache的内部类,所以可以直接访问WeakCache的valueFactory属性
                value = valueFactory.apply(key, parameter);
                return value;
            }
        }
    
    }
  • 相关阅读:
    [BJOI2019] 光线
    C# 从零开始写 SharpDx 应用 笔刷
    BAT 脚本判断当前系统是 x86 还是 x64 系统
    BAT 脚本判断当前系统是 x86 还是 x64 系统
    win2d 通过 CanvasActiveLayer 画出透明度和裁剪
    win2d 通过 CanvasActiveLayer 画出透明度和裁剪
    PowerShell 拿到显卡信息
    PowerShell 拿到显卡信息
    win10 uwp 如何使用DataTemplate
    win10 uwp 如何使用DataTemplate
  • 原文地址:https://www.cnblogs.com/yaowen/p/11750311.html
Copyright © 2011-2022 走看看