1:强制代理模式
普通代理模式和强制代理模式是代理模式的其中俩个部分。对于这俩个代理模式,我们采用一个类似事情解释下:
在网络上的代理服务器分透明代理和普通代理;对于透明代理来说,字如其意,就是这个代理服务器对用户来说是透明的,用户根本不知道这个服务器的存在。而普通代理则是用户需要自己手动去设置代理服务器的ip,很显然,对于这点上,用户必须知道代理服务器的存在。现在对号入座:代理模式中的强制代理类似网络上的代理服务器的透明代理,代理模式中的普通代理模式就类似网络上的代理服务器的普通代理。
普通代理模式比较常见,在这里就不作多说了,那么在这里就重点来看看强制代理模式。
强制代理模式在设计模式中比较怪怪的,很另类。一般的思维都是通过代理模式找到真实的角色,但是强制代理模式反其道而行之,必须强制通过真实角色去查找到到模式,否则不能访问。换句话说就是有真实角色去管理代理角色。总而言之:就是通过new或者其他方式创建一个真实角色的对象,最后却是会有真实角色返回他自己的代理角色。类似日常生活中:哥们咱想通过给点钱给某某局长,让他出面给咱们半个事情,结果他给我们一张他秘书的名片(理由很简单,这种事情当老大的不会出面),让他们本想通过局长要做的事情,直接通过秘书去做。其实:秘书能做这些,也就是此局长的权势;说白了秘书就是该局长的替身,代理。上图:
在接口上设置一个getProxy()方法,真实角色就能可以指定一个自己的代理。除了代理,谁也不能访问。很显然,当官的人都是会让指定的亲信做事,其他人信不过,当然不能胜任此事。上代码:局长抑或秘书至少都是官员
/**
*当官的必须收钱才做事
*/
public void receiveMoney();
/**
*当官的也要送钱,为了升官发财
* @param userName 行贿人名
* @param amount 行贿数量
*/
public void sendMoney();
/**
* 返回替身代理,这里是局长返回他的秘书;如果秘书权势也大,仍然可以找自己的代理替身去做
* @return
*/
public IOfficer getProxy();
}
真实角色和代理角色都应该实现上面的基类。
真实角色,增加一个私有方法,检查是否为自己的代理,如果是自己的代理,才能执行自己的方法。接下来看看代替实现:
//该代理为官员的秘书,这里秘书只能返回自己了;
@Override
public IOfficer getProxy() {
return this;
}
@Override
public void receiveMoney() {
officer.receiveMoney();
}
@Override
public void sendMoney() {
officer.sendMoney
下面将演示3中场景:
//场景2
public static void main(String[] args) {
IOfficer player = new Officer("张局长");
OfficerProxy proxy =new OfficerProxy(player);
proxy.receiveMoney();
proxy.sendMoney();
}
//场景3
public static void main(String[] args) {
IOfficer player = new Officer("张局长");
IOfficer proxy = player.getProxy();
proxy.receiveMoney();
proxy.sendMoney();
}
}
运行结果:
场景1:
please user pointed proxy receiveMoney
please user pointed proxy sendMoney
场景2:
please user pointed proxy receiveMoney
please user pointed proxy sendMoney
场景3:
张局长 are starting to receiveMoney
张局长 are starting to sendMoney
所以从上面的实例中可以得出:强制代理的概念就是必须从真实角色中查找返回其代理角色,不允许直接通过调用真实角色的方法,因为在每次调用真实角色从基类继承的方法时候,该方法都会先去判断是否为代理调用。高层模块只需访问真实角色的getProxy(),就可以完成访问真实角色的所有方法,它根本就不需要产生一个代理处理,代理的管理已经由真实角色自己完成。强制代理模式使得高层模块与真实角色的业务场景耦合度极地;真实角色的修改,在高层模块中完全不用修改。俩者只通过真实角色提供的一个getProxy()接口来交互。在整个实现过程,采用回调思想,在真实角色中调用代理对象的方法,代理对象通过回调来调用真实角色的方法。
2:动态代理模式
先解释下何为动态代理模式,所谓动态代理模式就是在实现阶段毋须关心代理谁,只有在运行阶段才指定代理哪一个对象。通俗点讲就是:自己动手写代理类的方式就是静态代理模式。采用动态代理模式比较为大家所熟知的比如AOP(切面编程),其核心机制就是采用动态代理机制。我们继续使用上面的官员行贿和受贿的例子来解析动态代理模式原理:上图
在类图中增加一个InvocationHandler接口;其中InvocationHandler是JDK提供的动态代理接口,对被代理的类(即是真实角色的对象,譬如上例中的局长角色)的方法进行代理。看代码:
}
}
其中invoke方法是InvocationHandler派生类必须实现的方法,它完成对真实角色(秘书调用局长的方法)的方法的调用。动态代理就是根据被代理的真实角色所属的接口生成所有方法,换而言之:代理对象已经实现接口下(IOfficer)的所有方法。类似静态代理模式:public class OfficerProxy implements IOfficer 也要实现该接口下所有方法。
运行结果:
张局长 are starting to receiveMoney
张局长 are starting to sendMoney
粗看很不解,IOfficer proxy是生成的代理类,但是没有看到代理类实现接口的方法。(IOfficer) Proxy.newProxyInstance来生成代理对象,里面到底是如何处理的,我们进去看看Proxy.newProxyInstance这个方法:
可见关键之处在于Class cl = getProxyClass(loader, interfaces);Proxy利用类装载器和代理类的接口来生成一个实现了接口各个方法的代理类的class对象。我们分析下代码getProxyClass(loader, interfaces)代码
//for语句作用:
//1:interfaceSet 存放各个接口的class对象 2:interfaceNames 数组中存放各个接口的名字
for (int i = 0; i < interfaces.length; i++) {
/*
* Verify that the class loader resolves the name of this
* interface to the same Class object.
*/
String interfaceName = interfaces[i].getName();
Class interfaceClass = null;
try {
interfaceClass = Class.forName(interfaceName, false, loader);
} catch (ClassNotFoundException e) {
}
if (interfaceClass != interfaces[i]) {
throw new IllegalArgumentException(
interfaces[i] + " 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.contains(interfaceClass)) {
throw new IllegalArgumentException(
"repeated interface: " + interfaceClass.getName());
}
interfaceSet.add(interfaceClass);
interfaceNames[i] = interfaceName;
}
//将数组转化程list对象
Object key = Arrays.asList(interfaceNames);
/*
* Find or create the proxy class cache for the class loader.
*/
为类装载期查找或者创建一个代理的class对象的cache
Map cache;
synchronized (loaderToCache) {
cache = (Map) loaderToCache.get(loader);
if (cache == null) {
cache = new HashMap();
loaderToCache.put(loader, cache);///该Cache以类装载器为key,value也为一个Cache
}
}
synchronized (cache) {
do {
Object value = cache.get(key);
if (value instanceof Reference) {
proxyClass = (Class) ((Reference) value).get();
}
if (proxyClass != null) {
// proxy class already generated: return it
return proxyClass;
} else if (value == pendingGenerationMarker) {
// proxy class being generated: wait for it
try {
cache.wait();
} catch (InterruptedException e) {
/*
* The class generation that we are waiting for should
* take a small, bounded time, so we can safely ignore
* thread interrupts here.
*/
}
continue;
} else {
/*
* No proxy class for this list of interfaces has been
* generated or is being generated, so we will go and
* generate it now. Mark it as pending generation.
*/
cache.put(key, pendingGenerationMarker); //以接口名的list为key,存放正在生成的proxy对象
break;
}
} while (true);
}
try {
String proxyPkg = null; // package to define proxy class in
/*
* 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 (int i = 0; i < interfaces.length; i++) {
int flags = interfaces[i].getModifiers();
if (!Modifier.isPublic(flags)) {
String name = interfaces[i].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,
proxyPkg = ""; // use the unnamed package
}
{
/*
* Choose a name for the proxy class to generate.
*/
long num;
synchronized (nextUniqueNumberLock) {
num = nextUniqueNumber++;
}
String proxyName = proxyPkg + proxyClassNamePrefix + num; //生成对象名字
/*
* Verify that the class loader hasn't already
* defined a class with the chosen name.
*/
/*
* Generate the specified proxy class.
*/
//重点:generateProxyClass方法为代理类实现了接口的所有方法,返回字节流
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces);
try {
//解析,装载字节流,返回class对象
proxyClass = 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());
}
}
// add to set of all generated proxy classes, for isProxyClass
proxyClasses.put(proxyClass, null);
} finally {
/*
* We must clean up the "pending generation" state of the proxy
* class cache entry somehow. If a proxy class was successfully
* generated, store it in the cache (with a weak reference);
* otherwise, remove the reserved entry. In all cases, notify
* all waiters on reserved entries in this cache.
*/
synchronized (cache) {
if (proxyClass != null) {
cache.put(key, new WeakReference(proxyClass));
} else {
cache.remove(key);
}
cache.notifyAll();
}
}
return proxyClass;
}
所以:Proxy.newProxyInstance内部机制为:
1:实现接口
2:装载字节流文件到虚拟机
3:实例化,并返回对象
类推:代理对象调用方法:Proxy.sendMoney(),他的实现应该类似如何:
通过InvocationHandler的invoke方法类来调用真实角色对应方法