普通代理(最简单的代理)

需要有两个实现同一个接口的类,一个是被代理的类,一个是代理类

被代理类中我们按照自己想实现的功能重写接口中的方法

代理类中因为需要代理被代理类,所以在代理类中需要有个被代理类的实例,这样在重写接口中的方法的时候,直接调用代理类中的实例中对应的方法直接实现代理功能

具体代码的实现

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中代理的更多相关文章

  1. Java中代理对象的使用小结

    在某些情况下,一个客户不想或不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到了中介作用,这不仅仅使用代理模式,还可以实现适配器模式.装饰模式等. 代理对象内部含有对真实对象的引用,从而 ...

  2. JAVA中代理模式

    代理模式 在某些情况下,一个客户不想或者不能直接引用一个对象,此时可以通过一个称之为“代理”的第三者来实现间接引用.代理对象可以在客户端和目标对象之间起到 中介的作用,并且可以通过代理对象去掉客户不能 ...

  3. java中代理,静态代理,动态代理以及spring aop代理方式,实现原理统一汇总

    若代理类在程序运行前就已经存在,那么这种代理方式被成为 静态代理 ,这种情况下的代理类通常都是我们在Java代码中定义的. 通常情况下, 静态代理中的代理类和委托类会实现同一接口或是派生自相同的父类. ...

  4. 所有和Java中代理有关的知识点都在这了。

    对于每一个Java开发来说,代理这个词或多或少都会听说过.你可能听到过的有代理模式.动态代理.反向代理等.那么,到底什么是代理,这么多代理又有什么区别呢.本文就来简要分析一下. 代理技术,其实不只是J ...

  5. Java中代理和装饰者模式的区别

    装饰模式:以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案: 代理模式:给一个对象提供一个代理对象,并有代理对象来控制对原有对象的引用: 装饰模式为所装饰的对象增强功能:代理模式对代理的对 ...

  6. 谈谈Java中的代理模式

    首先来看一下代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问.在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用, 其特征是代理类与 ...

  7. Java中jdk代理和cglib代理

    代理模式 给某一个对象提供一个代理,并由代理对象控制对原对象的引用.在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用. 在Java中代理模式从实 ...

  8. java 动态代理—— Mybaties 拦截器链基本原理实现

    1.摘要 Mybaties 中有个分页插件,之前有特意的去了解了一下原理 :https://www.cnblogs.com/jonrain0625/p/11168247.html,从了解中得知分页插件 ...

  9. Java中的JDK动态代理

    所谓代理,其实就是相当于一个中间人,当客户端需要服务端的服务时,不是客户直接去找服务,而是客户先去找代理,告诉代理需要什么服务,然后代理再去服务端找服务,最后将结果返回给客户. 在日常生活中,就拿买火 ...

随机推荐

  1. 如何限制指定textFiled第三方输入法切换

    在有些项目中需要用到输入纯数字的键盘,并且还不能切换到第三方输入法! textFiled.secureTextEntry = YES; [textFiled addTarget:self action ...

  2. Mono的CustomConditionAttribute使用

    1.Mono的CustomConditionAttribute使用有诸多的限制,没有在XML中定义来的灵活 2.CustomConditionAttribute定义的子类必须和ExtensionAtt ...

  3. java 调用c# web api 代码

    上次我们写的.net  web api 给对方公司的java团队调用,他们觉得说java无法调用.net 写的api ,靠居然有这事,索性自己写一个java的demo给他们 使用apache的Http ...

  4. Kafka安装及开启SASL_PLAINTEXT认证(用户名和密码认证)

    前些日子要封装一个kafka的客户端驱动,配置了下kafka环境,发现配置复杂度完爆rabbitmq很多倍啊,而且发布订阅模式使用起来也很麻烦,可能就胜在分布式了吧. kafka需要java环境,自行 ...

  5. jmeter向ActiveMQ发送消息_广播/订阅(Topics 队列)

    问题描述:测试中需要模拟大量设备的消息上报到平台,但是实际测试中没有那么多设备,所以采取用jmeter直接往ActiveMQ模拟发送设备消息 解决思路:获取平台采取的是Queues还是Topics : ...

  6. [python爬虫] Selenium常见元素定位方法和操作的学习介绍

    这篇文章主要Selenium+Python自动测试或爬虫中的常见定位方法.鼠标操作.键盘操作介绍,希望该篇基础性文章对你有所帮助,如果有错误或不足之处,请海涵~同时CSDN总是屏蔽这篇文章,再加上最近 ...

  7. Python第8天

    zip() 拉链方法 max(字典) 默认比较字典的key,不同类型的数据不能比较,只要可以被for迭代即可 利用zip与max(字典)共同使用 ord() — chr()    ascii码表数字与 ...

  8. vmvare使用桥接和NAT方式连接网络

    一.背景:本着学以致用的心态,试着最小化安装Centos7.4.安装centos主要目的有两个:共享文件(samba).安装postgresql数据库 本打算使用内网(不联网)的方式安装samba和p ...

  9. scala 读取保存文件 去除字符特殊

    /** * 读取文件 * @param filename * @return */ def readFormFile(filename: String) = { var ooop = "&q ...

  10. Programming Series 1.0 — C Programming

    In the growing world of technology, C programming has kind of lost its way. Today, we have a million ...