----------- android培训、java培训、期待与您交流! ------------
代理
生活中,消费者与厂商之间有代理商。代理商提供了一定的功能,如:将货物送到消费者手中,保鲜等
程序中,也有类似的中间件-代理类。
代理类:与目标类有相同的接口(方法集合),代理中的每个方法都调用目标类的方法,提供了一些附加的功能,如计算方法的运行时间,异常处理、事务管理、日志等。
具体应用:如果采用工厂模式和配置文件的方式进行管理,在配置文件中配置是使用目标类,还是代理类,很方便的进行切换。同时以后若想去掉附加的功能,也很方便。
示例代码
class A { //目标类
void method() {}
}
class XProxy { //代理类
void method() { //和目标类有相同的方法
startTime; //增加系统功能
A.method(); //调用目标类的方法
endTime; //增加系统功能
}
}
代理架构图:
AOP
代理是实现AOP功能的核心和关键技术。
那什么是AOP?
答:Aspect oriented program,面向方面编程。
什么是交叉业务?
答:安全、事务、日志等功能要贯穿到很多个模块中,它们就是交叉业务。
AOP的目标:使交叉业务模块化。
如何实现的?
答:采用将切面代码移动到原始方法的周围。这与直接在方法中编写切面面代码是一样的。(这里的切面代码:就是附加的功能代码)
实际开发中,将切面代码封装成对象,传递给InvocationHandler的invoke()方法。
动态代理技术
要为系统中的各种接口的类增加代理功能,若全部采用静态代理的方式,将需要很多的代理类。
动态代理类:JVM可以在运行时期动态的生成类的字节码,这种动态生成的类往往被用作代理类,即动态代理类。
JVM生成的动态类必须实现一个或多个接口,所以其只能代理于具有相同接口的目标类。
CGLIB库:可以动态生成一个类的子类,一个类的子类也可作为此类的代理,所以要为一个没有实现接口的类生成代理,可以用CGLIB库。(是一个插件)
系统功能代码(切面代码)存放于代理方法中的位置:1、调用的目标方法前;2、调用的目标方法后;3、代理方法的异常处理的catch块中。
JVM动态生成类的字节码:实例代码
动态生成一个实现了Collection接口的类字节码,并使用反射技术查看这个动态类的一些内部信息。
import java.util.*;
import java.lang.reflect.*;
class ProxyDemo {
public static void main(String[] args) {
Class clazzProxy = Proxy.getProxyClass(Collection.class.getClassLoader(),Collection.class); //动态生成一个类
System.out.println(clazzProxy.getName());
System.out.println("----------构造方法:-------");
Constructor[] constructors = clazzProxy.getConstructors();
for(Constructor constructor : constructors) {
System.out.println("构造方法:" + constructor);
}
System.out.println("----------普通方法:-------");
Method[] methods = clazzProxy.getMethods();
for(Method method : methods) {
System.out.println("普通方法:" + method);
Class[] clazzParams = method.getParameterTypes();
for(Class clazzParam : clazzParams) {
System.out.println("----参数为:" + clazzParam.getName());
}
Type[] types = method.getGenericExceptionTypes();
for(Type type : types) {
System.out.println("--------方法抛出的异常类型为:" + type);
}
}
}
}
创建动态代理类的实例对象,如下
Collection proxy3 = (Collection)Proxy.newProxyInstance(
Collection.class.getClassLoader(), //第一个参数:用于产生动态类的接口的类加载器
new Class[]{Collection.class}, //第二个参数:用于产生动态类的接口的类型数组
new InvocationHandler(){ //第三个参数:实现了Invocation接口的匿名类对象
ArrayList target = new ArrayList(); //目标类对象
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{ //动态代理类的方法调用函数
long startTime = System.currentTimeMillis();
Object retVal = method.invoke(target, args);//目标类方法调用函数
long endTime = System.currentTimeMillis();
System.out.println(method.getName() + "方法运行时间" + (endTime - startTime));
return retVal;
}
}
);
proxy3.add("Hello");
proxy3.add("Java");
System.out.println("集合元素个数:" + proxy3.size());
}
InvocationHandler对象运行原理:
Client程序调用proxyObj.add("AB")方法时,涉及三要素:1、哪个对象调用的,proxyObj 2、调用的是哪个方法 3、调用方法的参数
调用的过程:调用用proxyMethod.invoke(),这个方法需要目标方法的返回值,它会自动去调用targetMethod.invoke(),然后将返回值传递给proxyMethod.invoke(),再传递给调用者;传值的过程中,代理类的附加代码也相继运行。
分析代理类的方法:
class Proxy$ {
add(Object obj) {
return handler.invoke(Object proxy, Method method, Object[] args)
}
int size() {
return handler.invoke(this, this.getClass().getMethod("size"), null);
}
}
动态代理工作原理图:
----------------------- android培训、java培训、期待与您交流! ----------------------
详情请查看: