黑马程序员技术交流社区
标题:
求助代理类
[打印本页]
作者:
Spring up
时间:
2012-11-3 18:47
标题:
求助代理类
哪哥们能清楚的帮助我很好的理解代理类?谢谢!
作者:
王龙
时间:
2012-11-3 19:30
不清楚,嘿嘿
作者:
李靖
时间:
2012-11-3 20:23
通过张老师的视频总结了一下,希望对你有帮助
生活中的代理,济南人想买海尔的电脑,可以从济南海尔代理商那里购买,也可以直接跑到青岛来买海尔的电脑。主体的业务目标是一样的,就是买了一台电脑,从代理处购买既可以省时也省力,虽然有一些代理费,但是比自己跑到青岛买还是会便宜一些。
应用程序中的代理。编写一个和目标类具有相同接口的代理类,代理类的每个方法调用目标类的相同方法,并在调用方法是加上系统功能代码。如果采用工厂模式和配置文件的方式进行管理,在配置文件中使用目标类,还是代理类,这样很容易切换。譬如,想要日志功能是就配置代理类,否则配置目标类,这样增加系统功能很容易。张老师在这里体现了面向对象的一个很重要的思想,即面向接口的编程。
交叉业务编程问题即为面向方面编程(Aspect oriented Program AOP),AOP的目标就是要使用交叉业务模块化。可以采用将切面代码移到原始方法周围,这与直接在方法中编写切面代码的效果一样。例如学生服务,课程服务,教室服务到都用到了,安全,事务,日志的功能,这些安全、事务、日志就是交叉业务。
动态代理技术。JVM可以再运行期动态生成类的字节码,这种动态生成的类,往往被用作代理类。JVM生成的动态类必须实现一个或多个接口,所以java生成的动态类只能用作具有相同接口的目标的目标类的代理。
CGLIB库可以动态生成一个类的子类,一个类的子类也可以用作该类的代理,所以,如果要为一个没有实现接口的类动态生成代理类,那么可以使用CGLIB库。系统功能添加代码的位置:调用目标方法之前,调用目标方法之后,调用目标方法前后,处理目标方法异常模块catch中。
创建动态类及其查看方法列表信息代码如下:
//获取代理类
Class clazzProxy1=Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);
System.out.println(clazzProxy1.getName());
//创建缓冲区
StringBuilder sb = new StringBuilder();
//取得构造方法集合,并遍历该集合
Constructor[] constructors =clazzProxy1.getConstructors();
for (Constructor construtor : constructors) {
//System.out.println(constructor.getName());
//sb=new StringBuilder();
sb.append(construtor.getName());
sb.append('(');
Class[] clazzParams=construtor.getParameterTypes();
for (Class clazzParam : clazzParams) {
sb.append(clazzParam.getName()).append(',');
}
if(clazzParams.length!=0&&clazzParams!=null){
sb.deleteCharAt(sb.length()-1);
}
sb.append(')');
//System.out.println(sb.toString());
sb.append("\r\n");
}
//取得代理类的方法集合,并遍历
Method[] methods =clazzProxy1.getMethods();
for (Method method : methods) {
//System.out.println(constructor.getName());
//sb=new StringBuilder();
sb.append(method.getName());
sb.append('(');
Class[] clazzParams=method.getParameterTypes();
for (Class clazzParam : clazzParams) {
sb.append(clazzParam.getName()).append(',');
}
if(clazzParams.length!=0&&clazzParams!=null){
sb.deleteCharAt(sb.length()-1);
}
sb.append(')');
//System.out.println(sb.toString());
sb.append("\r\n");
}
System.out.println(sb.toString());
对于方法的遍历,因为代理类要有一个接口类,所以所以方法含有接口中的所有的方法。
创建动态类的实例及其调用方法
Collection foo3 = (Collection) Proxy.newProxyInstance(Collection.class
.getClassLoader(), new Class[] { Collection.class },
new InvocationHandler() {
ArrayList target = new ArrayList();
@Override
public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable {
long startTime=System.currentTimeMillis();
Object retValue = method.invoke(target, args);
long endTime=System.currentTimeMillis();
System.out.println("Runtime:"+(endTime-startTime)); return retValue;
}
});
foo3.add("zhangsan");
System.out.println(foo3.toString());
System.out.println(foo3.size());
动态生成类每次操作都会调用invocationHandler实现类的invoke方法,他会把自己的操作方法和参数传给InvocationHandler方法,真正的操作在InvocationHandler中实现,所以将target作为成员变量。 在代理实例上的java.lang.Object 中声明的hashCode、equals 或 toString 方法的调用将按照与编码和指派接口方法调用相同的方式进行编码,并被指派到调用处理程序的invoke 方法,也就是说InvocationHander实例覆盖hashCode ,equals和toString方法覆盖式有效的。这个目标类必须实现了接口的所有的方法,代理类就是很好的体现了面向接口编程。
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/)
黑马程序员IT技术论坛 X3.2