大纲如下:
AOP 是什么?
AOP 是一种技术,只存在web服务端么?
AOP 与OOP 的关系以及存在价值?
AOP和代理的关系,同时代理都有哪些形式?
代理形式的对比
Aspectj是什么
Aspectj的优点 缺点
Aspectj 语法详解以及使用
上一章节我们提到了 《代理形式的对比》的对比里面静态代理的用法和优劣
这里我们承接上一章的内容继续《代理形式的对比》
代理形式的对比
还记得上一章我们说过的,代理分为动和静,静态已经说完了,我们这里直接说动态的形式。
动态代理:典型实现就是jdk动态代理,通过Proxy(java.lang.reflect.Proxy)对象以及InvocationHandler(java.lang.reflect.InvocationHandler)的具体实现来动态创建代理对象。
客户端(Admin对象)的动态调用形式如下:
public class Admin {
public void dynamicProxy() {
IService realService = new ServiceImpl();
InvocHandlerImpl handler = new InvocHandlerImpl(realService);
IService proxyService = (IService)Proxy.newProxyInstance(handler.getClass().getClassLoader(),
realService.getClass().getInterfaces(), handler);
proxyService.queryUserInfo();
}
public static void main(String[] args) {
Admin admin = new Admin();
admin.dynamicProxy(); //admin.proxyQuery();
}
}
我们的InvocationHandler对象如下:
public class InvocHandlerImpl implements InvocationHandler{
Object target;
public InvocHandlerImpl(Object target){
this.target = target;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("------------动态调用前");
Object object = method.invoke(target, args);
System.out.println("------------动态调用后");
return object;
}
}
我们来说明一下,Proxy.newProxyInstance 这个动作就是在jdk在帮助我们编写上一章里面说的静态代理的那个代理对象,这一点一定要明确。之后我们详细解释一下newProxyInstance这个函数里面的三个参数。
Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h)
这个函数位于java.lang.reflect.Proxy文件里面,是一个静态函数。
第一个参数classloader:目标对象(被代理对象)的类加载器
第二参数interfaces: 目标对象实现的所有接口类( 请谨记是所有接口,接口 接口 接口)具体的实现动作在 ProxyGenerator.generateProxyClass函数里面(字节码的生成可以自己去了解)
第三个参数 handler:英语直译过来就是"乞求的处理者",这个很拗口(原谅我英语渣),其实我认为它是绑定生成的代理对象和目标对象之前的绑定者,我们稍后看newProxyInstance的具体实现
源代码如下:
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);
}
//下面这一行很重要
Class<?> cl = getProxyClass0(loader, intfs);
XXXXXX
}
上面代码斜体我已经标记出来,getProxyClass0(loader, intfs);通过传递的loader和接口去查找生成代理class(在缓存中不存在就会调用生成class逻辑) 这里有一点疑惑,class的生成????我们详细去看一下。
private static Class<?> getProxyClass0(ClassLoader loader, Class<?>... interfaces) {
return proxyClassCache.get(loader, interfaces);
}
注意这个proxyClassCache对象是一个WeakCache对象(WeakCache里面的值对象是new ProxyClassFactory()),我们直接去这个WeakCache里面get函数去看,在get函数内部调用了
// lazily construct a Factory
if (factory == null) {
factory = new Factory(key, parameter, subKey, valuesMap);
}
而这个Factory对象我们在去看里面有一个get()函数
// create new value
V value = null;
try {
value = Objects.requireNonNull(valueFactory.apply(key, parameter));
} finally{
if (value == null) {
// remove us on failure values
Map.remove(subKey, this);
}
}
还记得WeakCache对象的值保存的是什么吗??(new ProxyClassFactory()) 在看上面一段斜体代码
valueFactory.apply(key, parameter) 就是我们这个真正调用Factory apply动作的地方,那么在这个
apply的函数里面我们可以找到下面这段代码:
byte[] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, interfaces, accessFlags);
try {
return defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length);
}
好了这样我们就生成了class对象了。。。一切问题迎刃而解!!!!
经过以上的步骤我们确实也生成了代理对象,但是这个过程我们看到它只能对接口进行生成,尴尬了,对普通的类是没办法操作的(多实现单继承决定了这一点)。。。。这种设计虽然有缺憾但是必须得承认确实也很伟大(我们不能因为地心说是错误的就否定米利都学派对于整个人类的贡献),正所谓瑕不掩瑜
这个时候我们需要回顾对比一下上一章的静态代理,静态代理可以对类进行,问题是类文件多,接口修改的话维护代价比较大,动态代理解决生成代理类的问题,也解决了维护的代价,但是自身也有局限性,只能对接口进行实现代理,那么有没有更好的方式方法呢??
答案是肯定的,下一章节我们继续动态代理------编译期生成代理cglib和aspectj
网友评论