Java开发之反射与动态代理

#来自ゾフィー(佐菲)

1 反射(Reflect)

运行期间,获取类的信息,进行一些操作。

  • 运行时构造类的对象。
  • 运行时获取类的成员变量和方法。
  • 运行时调用对象的方法(属性)。

2 Class 类

Class 类封装了类的所有信息。

//1.类名.class -> Person.class
//2.对象.getClass() -> person.getClass()
//3.Class.forName(类全名) -> Class.forName("com.yoyiyi.test.Person")

3 Class 常用方法

Person.java

public class Person {
    String name;
    private int age;

    public Person(String name, int age) {
        super();
        this.name = name;
        this.age = age;
        System.out.println("有参数构造器");
    }

    public Person() {
        super();
        System.out.println("无参数构造器");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    private void privateMethod() {
        System.out.println("私有方法");
    }
}
public class TestReflec {
    public static void main(String[] args) throws Exception {
        Class<Person> clazz = (Class<Person>) Class.forName("demo02.Person");

        /***1.构造器**/
        //获取所有的构造器
        Constructor<Person>[] constructors = 
            (Constructor<Person>[]) clazz.getConstructors();
        for (Constructor<Person> c : constructors) {
            System.out.println(c);
        }

        //获取某一个构造器
        Constructor<Person> constructor = clazz.getConstructor(String.class, int.class);

        //创建对象
        constructor.newInstance("Jack", 89);

        /**2.方法**/
        //获取类所有方法,包括父类,私有方法不能获取到
        Method[] methods = clazz.getMethods();
        for (Method method : methods) {
            System.out.println(method.getName());
        }

        //获取当前类所有方法,包括私有方法
        Method[] methods1 = clazz.getDeclaredMethods();
        for (Method method : methods1) {
            System.out.println(method.getName());
        }

        //获取指定方法
        Method setName = clazz.getDeclaredMethod("setName", String.class);
        Method setAge = clazz.getDeclaredMethod("setAge", int.class);
        System.out.println(setName.getName());
        System.out.println(setAge.getName());

        //调用某一个方法
        Person person = clazz.newInstance();
        setAge.invoke(person, 89);
        System.out.println(person.getAge());


        /**3.属性**/
        //获取当前类的属性,不包括父类
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            System.out.println(field.getName());
        }

        //获取当前类的指定属性
        Field name = clazz.getDeclaredField("name");
        System.out.println(name.getName());


        //获取属性的值
        Person person1 = new Person("Maria", 7);
        String s = (String) name.get(person1);
        System.out.println(s);

        //设置对象的值
        Person person2 = new Person();
        Field age = clazz.getDeclaredField("age");
        age.setAccessible(true); //私有属性,设置 setAccessible(true)
        age.set(person2, 5);
        System.out.println(person2.getAge());


        //获取当前类的指定私有属性
        Field age2 = clazz.getDeclaredField("age");
        age2.setAccessible(true);
        System.out.println(age2.getName());
    }
}

4 代理模式

为其他对象提供一种代理以控制对这个对象的访问(代理类相当于一个中介)。

img

4.1 静态代理

//ISeller.java
public interface ISeller {
    void sell();
}

//Factory.java
public class Factory implements ISeller {

    @Override
    public void sell() {
        System.out.println("厂家直销");
    }
}

//Daigou.java
public class Daigou implements ISeller {

    private ISeller seller;

    public Daigou(ISeller seller) {
       this.seller = seller;
    }

    @Override
    public void buy() {
        doBefore();
        //真正调用的持有的类的方法
        mSeller.sell();
        doAfter();
    }

    private void doBefore() {
        System.out.println("加价899");
    }

    private void doAfter() {
        System.out.println("提供售后");
    }
}

//TestProxy.java
public class TestProxy {
    public static void main(String[] args) {
        Factory factory = new Factory();
        Daigou daigou = new Daigou(factory);
        daigou.buy();
    }
}

//假如我们买一个面膜,找到代购,代购其实也是别处买的,代购加价 899 元卖给你,我们不直接和厂家发生关系,这种就是一个代理模型

代理模式可以在不修改被代理对象的基础上,通过扩展代理类,进行一些功能的附加与增强。值得注意的是,代理类和被代理类应该共同实现一个接口,或者是共同继承某个类。

但是有弊端,假如这人不仅不仅要面膜,还要核导弹、航空母舰等等,就创建了许多代理类。

4.2 动态代理

//ISeller.java
public interface ISeller {
    void sell();
}

//SuperDaigou.java
public class SuperDaigou implements ISeller {
    @Override
    public void sell() {
        System.out.println("超级代购");
    }
}

//ProxyHandler.java
public class ProxyHandler implements InvocationHandler {

    //声明目标对象
    private ISeller target;

    public ProxyHandler(ISeller target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        doBefore();
        Object invoke = method.invoke(target, args);
        doAfter();
        return invoke;
    }

    //得到代理对象
    public Object getProxyInstance() {
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }

    private void doBefore() {
        System.out.println("加价899");
    }

    private void doAfter() {
        System.out.println("提供售后");
    }
}

public class TestProxy {

    public static void main(String[] args) {
        SuperDaigou superDaigou = new SuperDaigou();
        ProxyHandler handler = new ProxyHandler(superDaigou);
        //增强原来的方法
        ISeller seller = (ISeller) handler.getProxyInstance();
        seller.sell();
    }
}

由于使用了反射,效率比较低。

5 动态代理原理解析

//Proxy.java
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);
        }

        //1.动态生成 class 文件字节流,然后通过 loader 加载此字节流创建代理类 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;
                    }
                });
            }
            //2.获取代理类的类构造对象
            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);
        }
    }
    

//Proxy.java
private static Class<?> getProxyClass0(ClassLoader loader,
                                           Class<?>... interfaces) {
        if (interfaces.length > 65535) {
            throw new IllegalArgumentException("interface limit exceeded");
        }

        // If the proxy class defined by the given loader implementing
        // the given interfaces exists, this will simply return the cached copy;
        // otherwise, it will create the proxy class via the ProxyClassFactory
        return proxyClassCache.get(loader, interfaces);
    }

 // WeakCache.java
 public V get(K key, P parameter) {
        Objects.requireNonNull(parameter);

        expungeStaleEntries();

        Object cacheKey = CacheKey.valueOf(key, refQueue);

        // 根据cachekey获取键值对valuesMap, valuesMap的key是接口列表的包装类,value是动态生成代理类的包装类
        ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
        if (valuesMap == null) {
            ConcurrentMap<Object, Supplier<V>> oldValuesMap
                = map.putIfAbsent(cacheKey,
                                  valuesMap = new ConcurrentHashMap<>());
            if (oldValuesMap != null) {
                valuesMap = oldValuesMap;
            }
        }

        // create subKey and retrieve the possible Supplier<V> stored by that
        //核心:获取代理类  ProxyClassFactory#apply
        Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
        Supplier<V> supplier = valuesMap.get(subKey);
        Factory factory = null;

        while (true) {
            if (supplier != null) {
                // supplier might be a Factory or a CacheValue<V> instance
                V value = supplier.get();
                if (value != null) {
                    return value;
                }
            }
            // else no supplier in cache
            // or a supplier that returned null (could be a cleared CacheValue
            // or a Factory that wasn't successful in installing the CacheValue)

            // 如果动态生成代理类的工厂类为空,则创建新的工厂类
            if (factory == null) {
                factory = new Factory(key, parameter, subKey, valuesMap);
            }

            if (supplier == null) {
                //工厂类的包装类为空,则创建新的包装类supplier 
                supplier = valuesMap.putIfAbsent(subKey, factory);
                if (supplier == null) {
                    // successfully installed Factory
                    supplier = factory;
                }
                // else retry with winning supplier
            } else {
                if (valuesMap.replace(subKey, supplier, factory)) {
                    // successfully replaced
                    // cleared CacheEntry / unsuccessful Factory
                    // with our Factory
                    supplier = factory;
                } else {
                    // retry with current supplier
                    supplier = valuesMap.get(subKey);
                }
            }
        }
    }
//以上代码:通过 map 来存储动态生成的代理类,其中 key 是接口的包装类,value 是动态代理类的包装类

//Proxy.java#ProxyClassFactory
 private static final class ProxyClassFactory
        implements BiFunction<ClassLoader, Class<?>[], Class<?>>
    {
        // prefix for all proxy class names
        private static final String proxyClassNamePrefix = "$Proxy";

        // next number to use for generation of unique proxy class names
        private static final AtomicLong nextUniqueNumber = new AtomicLong();

        @Override
        public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {

            Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
            for (Class<?> intf : interfaces) {
                /*
                 * Verify that the class loader resolves the name of this
                 * interface to the same Class object.
                 */
                Class<?> interfaceClass = null;
                try {
                    interfaceClass = Class.forName(intf.getName(), false, loader);
                } catch (ClassNotFoundException e) {
                }
                if (interfaceClass != intf) {
                    throw new IllegalArgumentException(
                        intf + " is not visible from class loader");
                }
                /*
                 * Verify that the Class object actually represents an
                 * interface.
                 */
                if (!interfaceClass.isInterface()) {
                    throw new IllegalArgumentException(
                        interfaceClass.getName() + " is not an interface");
                }
                /*
                 * Verify that this interface is not a duplicate.
                 */
                if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
                    throw new IllegalArgumentException(
                        "repeated interface: " + interfaceClass.getName());
                }
            }

            String proxyPkg = null;     // package to define proxy class in
            int accessFlags = Modifier.PUBLIC | Modifier.FINAL;

            /*
             * Record the package of a non-public proxy interface so that the
             * proxy class will be defined in the same package.  Verify that
             * all non-public proxy interfaces are in the same package.
             */
            for (Class<?> intf : interfaces) {
                int flags = intf.getModifiers();
                if (!Modifier.isPublic(flags)) {
                    accessFlags = Modifier.FINAL;
                    String name = intf.getName();
                    int n = name.lastIndexOf('.');
                    String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
                    if (proxyPkg == null) {
                        proxyPkg = pkg;
                    } else if (!pkg.equals(proxyPkg)) {
                        throw new IllegalArgumentException(
                            "non-public interfaces from different packages");
                    }
                }
            }

            if (proxyPkg == null) {
                // if no non-public proxy interfaces, use com.sun.proxy package
                proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
            }

            /*
             * Choose a name for the proxy class to generate.
             */
            long num = nextUniqueNumber.getAndIncrement();
            
            //代理类名称
            String proxyName = proxyPkg + proxyClassNamePrefix + num;

            //代理类字节码
            byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                proxyName, interfaces, accessFlags);
            try {
                //最终生成代理类的 class 对象是本地方法 defineClass0 方法
                //原理是根据类名、接口、类加载器、方法列表、异常列表,按照 class 文件格式先生成字节流,再生成动态代理类
                return defineClass0(loader, proxyName,
                                    proxyClassFile, 0, proxyClassFile.length);
            } catch (ClassFormatError e) {
                /*
                 * A ClassFormatError here means that (barring bugs in the
                 * proxy class generation code) there was some other
                 * invalid aspect of the arguments supplied to the proxy
                 * class creation (such as virtual machine limitations
                 * exceeded).
                 */
                throw new IllegalArgumentException(e.toString());
            }
        }
    }
  • 14
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值