Java中代理
普通代理(最简单的代理)
需要有两个实现同一个接口的类,一个是被代理的类,一个是代理类
被代理类中我们按照自己想实现的功能重写接口中的方法
代理类中因为需要代理被代理类,所以在代理类中需要有个被代理类的实例,这样在重写接口中的方法的时候,直接调用代理类中的实例中对应的方法直接实现代理功能
具体代码的实现
- interface Interface{
- void dosomething();
- void dosomethingelse(String args);
- }
- class RealObject implements Interface{ //被代理的类
- @Override
- public void dosomething() {
- System.out.println("do something!!!");
- }
- @Override
- public void dosomethingelse(String args) {
- System.out.println("do something else:"+args);
- }
- }
- class CommonProxy implements Interface{ //代理类
- private Interface proxied; //这个接口应该是指向被代理对象的实例
- public CommonProxy(Interface proxied) {
- this.proxied = proxied;
- }
- @Override
- public void dosomething() {
- proxied.dosomething(); //直接调用被代理对象中的方法实现代理功能
- }
- @Override
- public void dosomethingelse(String args) {
- proxied.dosomethingelse(args);
- }
- }
- public class SimpleProxyDemo{
- public static void consumer(Interface inter){
- inter.dosomethingelse("booo");
- inter.dosomething();
- }
- public static void main(String[] args) {
- consumer(new CommonProxy(new RealObject()));
- }
- }
动态代理技术
上面的代理对象都是我们手动写的,Java动态代理技术可以实现动态的创建代理对象,并且动态的处理对代理方法的调用
简单的代码实现(有一部分使用的是上面的接口和实现类)
- class DynamicProxyHandler implements InvocationHandler {
Object proxied;- public DynamicProxyHandler(Object proxied) {
this.proxied = proxied;
}- @Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke(proxied,args);
}
}- public class DynamicProxyDemo{
public static void main(String[] args) {
RealObject realObject=new RealObject();
Interface proxy = (Interface) Proxy
.newProxyInstance(Interface.class.getClassLoader(), new Class[]{Interface.class}, new DynamicProxyHandler(new RealObject()));
proxy.dosomethingelse("shei");
proxy.dosomething();
}
}
使用步骤:
定义一个实现InvocationHandler接口的调用处理器,重写里面的invoke方法
直接使用Proxy中的静态方法创建代理类,创建的过程中需要一个类加载器,一个被代理的接口,还有一个上面定义的调用处理器。
注意最后将生成的代理对象转换成我们需要的被代理类实现的接口,在上面就是Interface接口,注意这里的Interface是首字母大写,不是Java中的关键字。
动态代理的原理
Proxy.newProxyInstance()函数
- public static Object newProxyInstance(ClassLoader loader,
- Class<?>[] interfaces,
- InvocationHandler h)
- throws IllegalArgumentException
- {
- Objects.requireNonNull(h); //首先判断传递的调用处理器是不是空,否则就抛出空指针异常
- final Class<?>[] intfs = interfaces.clone(); //使用clone()函数实现初始化接口的Class对象数组。
- 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); //生成代理对象的Class对象实例。
- /*
- * 借助调用处理器生成对应的代理类
- */
- 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}); //使用代理类的构造函数和InvocationHandler实例化一个代理对象,最后返回代理对象
- } 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);
- }
- }
下面函数是二级缓存类WeakCache类中的get()函数,其实例对象就是cacheProxyClass,下面函数中如果根据提供的类加载器和接口数组能在缓存中找到代理类就直接返回该代理类,否则会调用ProxyClassFactory工厂去生成代理类。这里用到的缓存是二级缓存,它的一级缓存key是根据类加载器生成的,二级缓存key是根据接口数组生成的。
代理类Class对象的生成(上面黄色的部分)最终会定位到WeakCache类的实例proxyClassCache中的get()函数。ProxyClassCache对象有两个变量,KeyFactory和ProxyClassFactory,前者实现生成二级缓存的subkey,根据subkey在Concurrentmap中取出对应的factory(代码中使用父接口Supplier引用supplier指向),由supplier的get()函数得到对应的value(代理类class对象)。
- public V get(K key, P parameter) {
- Objects.requireNonNull(parameter);
- expungeStaleEntries();
- Object cacheKey = CacheKey.valueOf(key, refQueue);
- // 根据由类加载器生成的一级缓存的key向缓存中取对应的concurrentmap值
- ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
- if (valuesMap == null) { //如果没有valuesmap就创建一对放进去,
//只不过里面的concurrentmap还没有什么东西(二次缓存的key和工厂)- ConcurrentMap<Object, Supplier<V>> oldValuesMap
- = map.putIfAbsent(cacheKey,
- valuesMap = new ConcurrentHashMap<>());
- if (oldValuesMap != null) {
- valuesMap = oldValuesMap;
- }
- }
- // 运行到这里,生成二次缓存的key(使用classloader和interface生成),
- // 取出里面对应的代理类supplier
- Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
- Supplier<V> supplier = valuesMap.get(subKey);//注意缓存的只是Supplier指向的工厂,没有缓存代理类Class对象
- Factory factory = null;
- while (true) {
- if (supplier != null) {
- // supplier可能是个工厂也可能是缓存,由他提供对应的代理类Class对象
- V value = supplier.get(); //注意这一步是生成代理Class对象的关键,
//由缓存或者新建的supplier创建代理的Class对象- if (value != null) {
- return value;
- }
- }
- // 否则没有supplier,由下面的语句生成对应的supplier
- // or a supplier that returned null (could be a cleared CacheValue
- // or a Factory that wasn't successful in installing the CacheValue)
- // lazily construct a Factory
- if (factory == null) {
- factory = new Factory(key, parameter, subKey, valuesMap); //这就是supplier
- }
- if (supplier == null) {
- supplier = valuesMap.putIfAbsent(subKey, factory); //将生成的factory放进缓存,方便下次使用。
- if (supplier == null) {
- // successfully installed Factory
- supplier = factory;
- }
- // else retry with winning supplier
- } else { //supplier只是Factory的父接口
- if (valuesMap.replace(subKey, supplier, factory)) { //有supplier但是经过get()方法得到的是空,
//及所以这里使用新的factory替换之前的supplier- // successfully replaced
- // cleared CacheEntry / unsuccessful Factory
- // with our Factory
- supplier = factory;
- } else {
- // 否则就使用现在的supplier重试
- supplier = valuesMap.get(subKey);
- }
- }
- }
- }
Factory类中的get()函数(上面的黄色部分),其实现了supplier接口重写了里面的get()方法
- public synchronized V get() { // serialize access
- // 根据二级的key查询得到factory对象,检查拿到的和现在的相比是否一致,
//factory中有点像循环引用,因为factory对象中的ConCurrentMap中含有当前对象的引用- Supplier<V> supplier = valuesMap.get(subKey);
- if (supplier != this) {
- // 检查缓存是否一致,不一致就设为null,返回上一个函数继续生成对应的Factory对象
- return null;
- }
- // else still us (supplier == this)
- // create new value
- V value = null;
- try {
- value = Objects.requireNonNull(valueFactory.apply(key, parameter)); //生成对应的代理class对象,
//valueFactory就是上面ProxyClassCache的实现类- } finally {
- if (value == null) { // remove us on failure
- valuesMap.remove(subKey, this);
- }
- }
- // the only path to reach here is with non-null value
- assert value != null;
- // wrap value with CacheValue (WeakReference)
- CacheValue<V> cacheValue = new CacheValue<>(value); //CacheValue继承自Supplier,
//同样也含有get()(是父类reference中的函数)函数返回对应的值。- // put into reverseMap
- reverseMap.put(cacheValue, Boolean.TRUE);
- // try replacing us with CacheValue (this should always succeed)
- if (!valuesMap.replace(subKey, this, cacheValue)) {
- throw new AssertionError("Should not reach here");
- }
- // successfully replaced us with new CacheValue -> return the value
- // wrapped by it
- return value;
- }
- }
上面黄色部分最终会执行下面proxyclassfactory中的apply()函数
- private static final class ProxyClassFactory
- implements BiFunction<ClassLoader, Class<?>[], Class<?>>
- {
- // 代理类的名字前缀
- private static final String proxyClassNamePrefix = "$Proxy";
- // 为下一个代理类产生独一无二的标志数,放在类的名字中
- 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");
- }
- /*
- * 判断是不是代表一个接口
- */
- if (!interfaceClass.isInterface()) {
- throw new IllegalArgumentException(
- interfaceClass.getName() + " is not an interface");
- }
- /*
- * 判断是不是重复.
- */
- if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
- throw new IllegalArgumentException(
- "repeated interface: " + interfaceClass.getName());
- }
- }
- String proxyPkg = null; //
- int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
- /*
- * 判断是不是所有的非公有接口是不是在同一个包下,如果没有就会抛出异常
- */
- 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) {
- // 如果没有非公有的interface就使用sun公司自己默认的包
- proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
- }
- /*
- * 为代理类生成名字 类似 $proxy0
- */
- long num = nextUniqueNumber.getAndIncrement();
- String proxyName = proxyPkg + proxyClassNamePrefix + num;
- /*
- * 由proxygenerator生成对应的Class类的字节形式,使用我们给的类加载器加载对应的类。
- */
- byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
- proxyName, interfaces, accessFlags);
- try {
- return defineClass0(loader, proxyName, //native 方法
- 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());
- }
- }
- }
最后我们看看上面的红色部分,ProxyGenerator类的generatorProxyClass()函数
- public static byte[] generateProxyClass(final String var0, Class<?>[] var1, int var2) {
- ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2);
- final byte[] var4 = var3.generateClassFile();
- if (saveGeneratedFiles) {
- AccessController.doPrivileged(new PrivilegedAction<Void>() {
- public Void run() {
- try {
- int var1 = var0.lastIndexOf(46);//46在ASCII码中就是 “.”
- Path var2;
- if (var1 > 0) {
- Path var3 = Paths.get(var0.substring(0, var1).replace('.', File.separatorChar));
- Files.createDirectories(var3); //和上面一起用来创建代理类的存放目录
- var2 = var3.resolve(var0.substring(var1 + 1, var0.length()) + ".class");//这个就是代理类的名字 $proxy0.class
- } else {
- var2 = Paths.get(var0 + ".class");//var2是代理类的全路径名
- }
- Files.write(var2, var4, new OpenOption[0]);//最后写进对应的文件。
- return null;
- } catch (IOException var4x) {
- throw new InternalError("I/O exception saving generated file: " + var4x);
- }
- }
- });
- }
- return var4;
- }
上面的黄色部分里面使用了很多反射生成对应的byte数组,里面写的就应该是class文件的内容,
动态代理中最重要的就是Proxy类,里面含有大量的静态变量和静态函数
静态变量:WeakCache类型的实例 proxyClassCache
InnovationHandler实例h
所含的内部类:
内部类keyFactory(在二级缓存中用于生成二级缓存的subkey)
内部类ProxyClassFactory(和上面一个内部类一起实例化上面的代理Class类的二级缓存WeakCache,在缓存中这个用于获得或者生成代理类Class对象)
Factory(实例存储在二级缓存中,最终调用它的get()函数返回对应的代理类Class文件)
静态函数:
newProxyInstance(classloader,classes[],InvocationHandler),(这个函数的会调用下面的函数,返回代理类Class对象实例,最终使用反射生成代理类实例)
getproxyclass0(classloader,classes)(这个函数会直接调用WeakCache的get()函数查询proxyClassCache缓存)
根据classloader生成一级缓存的key,取出concurrentmap,在根据classloader和interfaces使用keyFactory中apply函数生成subkey,根据subkey取出对应的supplier,有下面两 种情况,
一种:supplier是一个缓存,这时候supplier指向的是一个CacheValue的对象,调用get()函数是其父类weakreference的父类reference中的get()函数,函数返回缓存中的值
另一种:当前supplier中没有值,这时候使用ProxyClassFactory中的apply()函数生成对应的代理类的Class对象,并且存进CacheValue中。
Java中代理的更多相关文章
- Java中代理对象的使用小结
在某些情况下,一个客户不想或不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到了中介作用,这不仅仅使用代理模式,还可以实现适配器模式.装饰模式等. 代理对象内部含有对真实对象的引用,从而 ...
- JAVA中代理模式
代理模式 在某些情况下,一个客户不想或者不能直接引用一个对象,此时可以通过一个称之为“代理”的第三者来实现间接引用.代理对象可以在客户端和目标对象之间起到 中介的作用,并且可以通过代理对象去掉客户不能 ...
- java中代理,静态代理,动态代理以及spring aop代理方式,实现原理统一汇总
若代理类在程序运行前就已经存在,那么这种代理方式被成为 静态代理 ,这种情况下的代理类通常都是我们在Java代码中定义的. 通常情况下, 静态代理中的代理类和委托类会实现同一接口或是派生自相同的父类. ...
- 所有和Java中代理有关的知识点都在这了。
对于每一个Java开发来说,代理这个词或多或少都会听说过.你可能听到过的有代理模式.动态代理.反向代理等.那么,到底什么是代理,这么多代理又有什么区别呢.本文就来简要分析一下. 代理技术,其实不只是J ...
- Java中代理和装饰者模式的区别
装饰模式:以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案: 代理模式:给一个对象提供一个代理对象,并有代理对象来控制对原有对象的引用: 装饰模式为所装饰的对象增强功能:代理模式对代理的对 ...
- 谈谈Java中的代理模式
首先来看一下代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问.在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用, 其特征是代理类与 ...
- Java中jdk代理和cglib代理
代理模式 给某一个对象提供一个代理,并由代理对象控制对原对象的引用.在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用. 在Java中代理模式从实 ...
- java 动态代理—— Mybaties 拦截器链基本原理实现
1.摘要 Mybaties 中有个分页插件,之前有特意的去了解了一下原理 :https://www.cnblogs.com/jonrain0625/p/11168247.html,从了解中得知分页插件 ...
- Java中的JDK动态代理
所谓代理,其实就是相当于一个中间人,当客户端需要服务端的服务时,不是客户直接去找服务,而是客户先去找代理,告诉代理需要什么服务,然后代理再去服务端找服务,最后将结果返回给客户. 在日常生活中,就拿买火 ...
随机推荐
- pyexecjs模块
1,找到断点事件 2,浏览call stack 下面的代码,找到需要的值 3,F11进入方法内部 对于网站自己定义的方法,可以用py复制下来进行执行js N = function (a, b, c) ...
- FuzzScanner 信息收集小工具
前言: 该工具集成了各种大牛的工具,比如子域名发现,目录扫描,nmap端口扫描,c段地址查询,端口指纹,以及waf查询 00X1: 安装不推荐git安装,首先直接githup脱下来:git clone ...
- centos7搭建GitLab
1.安装依赖 yum -y install policycoreutils openssh-server openssh-clients postfix policycoreutils-python ...
- quartz.properties完整版
我们通常是通过quartz.properties属性配置文件(默认情况下均使用该文件)结合StdSchedulerFactory 来使用Quartz的.StdSchedulerFactory 会加载属 ...
- Vue 编程式导航(通过js跳转页面)以及路由hash模式和history模式
第一种方法: this.$router.push({path:'shopcontent?aid=3'} 第二种方法 this.$router.push({name:'news'}} 通过在ma ...
- Linq to SQL -- Select、Distinct和Count、Sum、Min、Max、Avg
Select/Distinct操作符 适用场景:o(∩_∩)o… 查询呗. 说明:和SQL命令中的select作用相似但位置不同,查询表达式中的select及所接子句是放在表达式最后并把子句中的变量也 ...
- Java学习笔记——鸵鸟学习记(一)
1. 变量 1.1 使用变量 a, 变量三要素:名字 值 类型 b, 变量命名 英文字母,数字,下划线,但不能数字开头 并不是英文单词,用拼音也可以 随便写也可以,但可读性差 区分大小写(Y与y是不同 ...
- 六、Python-字符串编码
最早的编码为ASCII码(包含0-9.A-Z.a-z.符号(空格.制表符等)),最多支持256个符号(每个符号占1字节) GBK/GB2312:我国制定的中文编码标准,一个字节表示因为字母,两个字 ...
- OO第二单元(电梯)单元总结
OO第一单元(求导)单元总结 这是我们OO课程的第二个单元,这个单元的主要目的是让我们熟悉理解和掌握多线程的思想和方法.这个单元以电梯为主题,从一开始的最简单的单部傻瓜调度(FAFS)电梯到最后的多部 ...
- 70.纯 CSS 创作一只徘徊的果冻怪兽
原文地址:https://segmentfault.com/a/1190000015484852 感想:monster中边框角.上下动画.旋转动画.左右动画,眼睛中transform:scaleY(n ...