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;
}
} }

proxy 简化版本的更多相关文章

  1. 基于Java实现简化版本的布隆过滤器

    一.布隆过滤器: 布隆过滤器(Bloom Filter)是1970年由布隆提出的.它实际上是一个很长的二进制向量和一系列随机映射函数.布隆过滤器可以用于检索一个元素是否在一个集合中.它的优点是空间效率 ...

  2. Ajax jquery的库的简化版本

    Ajax jquery的库的简化版本 (function(){    //面向外界的唯一变量接口!    var myajax = window.myajax = {};    //作者.版本号等等信 ...

  3. muduo 网络库的整体架构图和一个简化版本的架构设计

    https://blog.csdn.net/adkada1/article/details/54342275 简析 https://blog.csdn.net/amoscykl/article/det ...

  4. arcgis js api proxy java 版本配置

    <?xml version="1.0" encoding="utf-8" ?> <ProxyConfig allowedReferers=&q ...

  5. 仿netty线程池简化版本

    package com.hcxy.car.threadpools; import java.io.IOException; import java.nio.channels.Selector; imp ...

  6. webpack等bundler是如何工作的-简化版本

    webpack- why and how 首先不要被webpack做的复杂花哨的工作所迷惑,到底webpack是个啥?一句话,webpack是一个module bundler(模块打包器).多一句话, ...

  7. 一致性哈希做负载均衡,基于dubbo的简化版本,超级简单容易理解!!!

    一致性哈希算法原理以及做分布式存储.一定先看:一致性哈希算法 dubbo提供了四种负载均衡实现:权重随机算法,最少活跃调用数算法,一致性哈希算法,加权轮询算法. 本文基于开源项目:guide-rpc- ...

  8. 设计模式-代理模式(Proxy)

    应用场景: 领导都有秘书,一般会代理领导的部分职能角色,处理签字.报销.开会等任务.很多新人可能都只知道秘书的存在,毕竟每天与其打交道,不知道领导的存在.但是领导的的确确是真实存在的. 场景说明: 代 ...

  9. 利用AOP与ToStringBuilder简化日志记录

    刚学spring的时候书上就强调spring的核心就是ioc和aop blablabla...... IOC到处都能看到...AOP么刚开始接触的时候使用在声明式事务上面..当时书上还提到一个用到ao ...

随机推荐

  1. 【推荐】全球最全面的Telegram组群频道的集合网站 持续收集中

    全球最全面的Telegram组群频道的集合网站 https://www.telegramgroup.org Telegram 组群频道分享 可搜索自己想找的组群频道 从小白到大神,一个 telegra ...

  2. vue 开发系列(九) VUE 动态组件的应用

    业务场景 我们在开发表单的过程中会遇到这样的问题,我们选择一个控件进行配置,控件有很多中类型,比如文本框,下来框等,这些配置都不同,因此需要不同的配置组件来实现. 较常规的方法是使用v-if 来实现, ...

  3. 【MySQL高可用架构设计】(一)-- mysql复制功能介绍

    一. 介绍 Mysql的复制功能是构建基于SQL数据库的大规模高性能应用的基础,主要用于分担主数据库的读负载,同时也为高可用.灾难恢复.备份等工作提供了更多的选择. 二.为什么要使用mysql复制功能 ...

  4. Jenkins参数化构建(七)

    一.配置参数化构建过程 主要用来区分分支,使用传参的方式,将分支名称传入脚本中进行拉取代码. 1.1 最常用的是:字符参数.文本参数.  1.2 添加字符参数和文本参数,并配置变量名称  1.3 配置 ...

  5. Transformer模型---decoder

    一.结构 1.编码器 Transformer模型---encoder - nxf_rabbit75 - 博客园 2.解码器 (1)第一个子层也是一个多头自注意力multi-head self-atte ...

  6. Go语言调度器之创建main goroutine(13)

    本文是<Go语言调度器源代码情景分析>系列的第13篇,也是第二章的第3小节. 上一节我们分析了调度器的初始化,这一节我们来看程序中的第一个goroutine是如何创建的. 创建main g ...

  7. 代码审计-ereg正则%00截断

    <?php $flag = "xxx"; if (isset ($_GET['password'])) { if (ereg ("^[a-zA-Z0-9]+$&qu ...

  8. Python查看帮助---help函数

    查看所有的关键字:help("keywords") 查看所有的modules:help("modules") 单看所有的modules中包含指定字符串的modu ...

  9. 10-numpy笔记-np.random.randint

    b_idx = np.random.randint(0, 9, 90) >>> b_idx array([0, 1, 5, 4, 7, 2, 7, 0, 0, 4, 2, 2, 3, ...

  10. 页面元素定位及操作--xpath

    简介: 在 XPath 中,有七种类型的节点:元素.属性.文本.命名空间.处理指令.注释以及文档(根)节点.XML 文档是被作为节点树来对待的.树的根被称为文档节点或者根节点. /xxx 页面输出 / ...