黑马程序员-代理类的作用与原理及AOP
------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
代理的概念与作用
程序中的代理
要为已存在的多个具有相同接口的目标类的各个方法增加一些系统功能,例如,异常处理、日志、计算方法的运行时间、事务管理、等等,如何做?
编写一个与目标类具有相同接口的代理类,代理类的每个方法调用目标类的相同方法,并在调用方法时加上系统功能的代码。
如果采用工厂模式和配置文件的方式进行管理,则不需要修改客户端程序,在配置文件中配置是使用目标类、还是代理类,这样以后很容易切换,譬如,想要日志功能时就配置代理类,否则配置目标类,这样,增加系统功能很容易,以后运行一段时间后,又想去掉系统功能也很容易。
AOP
系统中存在交叉业务,一个交叉业务就是要切入到系统中的一个方面。
交叉业务的编程问题即为面向对象的编程(Aspect oriented program,简称AOP),AOP的目标就是要使交叉业务模块化。可以采用将切面代码移动到原始方法的周围,这与直接在方法中编写切面代码的运行效果是一样的。
使用代理技术正好可以解决这种问题,代理是实现AOP功能的核心和关键技术。
注意:安全,事务,日志等功能要贯穿到好多个模块中,所以,它们就是交叉业务。不要把供货商暴露给你的客户。
动态代理技术
要为系统中的各种接口的类增加代理功能,那将需要太多的代理类,全部采用静态代理方式,将是一件非常麻烦的事情!
1. JVM可以在运行期动态生成出类的字节码,这种动态生成的类往往被用作代理类,即动态代理类。
2. JVM生成的动态类必须实现一个或多个接口,所以,JVM生成的动态类只能用作
3. CGLIB库可以动态生成一个类的子类,一个类的子类也可以用作该类的代理,所以,如果要为一个没有实现接口的类生成动态代理类,那么可以使用CGLIB库。
4. 代理类的各个方法中通常除了要调用目标的相应方法和对外返回目标返回的结果外,还可以在代理方法中的如下四个位置加上系统功能代码:
- 在调用目标方法之前
- 在调用目标方法之后
- 在调用目标方法前后
- 在处理目标方法异常的catch块中
示例:
Class proxy{void sayHello(){……….try{target.sayHello();}catch(Exception e){………..}………….}
}
创建动态类及查看其方法列表信息
创建实现了Collection接口的动态类和查看其名称,分析Proxy.getProxyClass方法的各个参数。
public class ProxyTest {public static void main(String[] args) {Class clazzProxy = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class );System. out.println(clazzProxy.getName());System. out.println("--------begin constructors list-------");Constructor[] constructors = clazzProxy.getConstructors();for(Constructor constructor : constructors){String name = constructor.getName();StringBuilder sBuilder = new StringBuilder(name);sBuilder.append( "(");Class[] clazzParams = constructor.getParameterTypes();for(Class clazzParam : clazzParams){sBuilder.append(clazzParam.getName()).append( ",");}if(clazzParams != null && clazzParams.length != 0){sBuilder.deleteCharAt(sBuilder.length() - 1);}sBuilder.append( ")");System. out.println(sBuilder);}System. out.println("--------begin methods list-------" );Method[] methods = clazzProxy.getMethods();for(Method method : methods){String name = method.getName();StringBuilder sBuilder = new StringBuilder(name);sBuilder.append( "(");Class[] clazzParams = method.getParameterTypes();for(Class clazzParam : clazzParams){sBuilder.append(clazzParam.getName()).append( ",");}if(clazzParams != null && clazzParams.length != 0){sBuilder.deleteCharAt(sBuilder.length() - 1);}sBuilder.append( ")");System. out.println(sBuilder);}}
}
运行结果:
$Proxy0
--------begin constructors list-------
$Proxy0(java.lang.reflect.InvocationHandler)
--------begin methods list-------
hashCode()
add(java.lang.Object)
clear()
equals(java.lang.Object)
toString()
contains(java.lang.Object)
isEmpty()
addAll(java.util.Collection)
iterator()
size()
toArray()
toArray([Ljava.lang.Object;)
remove(java.lang.Object)
containsAll(java.util.Collection)
removeAll(java.util.Collection)
retainAll(java.util.Collection)
isProxyClass(java.lang.Class)
getProxyClass(java.lang.ClassLoader,[Ljava.lang.Class;)
getInvocationHandler(java.lang.Object)
newProxyInstance(java.lang.ClassLoader,[Ljava.lang.Class;,java.lang.reflect.InvocationHandler)
getClass()
wait(long,int)
wait()
wait(long)
notify()
notifyAll()
创建动态类的实例对象及调用其方法
编写一个最简单的InvocationHandler类。
调用构造方法创建动态类的实例对象,并将编写的InvocationHandler类的实例对象传进去。将创建动态类的实例对象的代理改为匿名内部类的形式。
思考总结:
让JVM创建动态类及其实例对象,需要给它提供哪些信息?
三个方面:
- 生成的类中有哪些方法,通过让其实现哪些接口的方式进行告知。
- 产生的类字节码必须有一个关联的类加载器对象。
- 生成的类中的方法的代码是怎样的,也得由我们提供。把我们的代码写在一个约定好了接口对象的方法中,把对象传给它,它调用我的方法,即相当于插入了我的代码。提供执行代码的对象就是那个InvocationHandler对象,它是在创建动态类的实例对象的构造方法时传递进去的。在上面的InvocationHandler对象的invoke方法中加一点代码,就可以看到这些代码被调用运行了。
public static void main(String[] args) throws Exception {Class clazzProxy = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class );System. out.println("--------begin create instance object-------");Constructor constructor = clazzProxy.getConstructor(InvocationHandler.class) ;Collection proxy = (Collection)constructor.newInstance(new InvocationHandler(){public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {return null ;}});System. out.println(proxy);//结果:nullproxy.clear();//执行没有返回值的方法,不会报告异常proxy.size();//执行有返回值的方法,会报告异常}
转载于:https://www.cnblogs.com/troy-sxj/p/4543748.html
黑马程序员-代理类的作用与原理及AOP相关推荐
- JAVA基础加强(张孝祥)_类加载器、分析代理类的作用与原理及AOP概念、分析JVM动态生成的类、实现类似Spring的可配置的AOP框架...
1.类加载器 ·简要介绍什么是类加载器,和类加载器的作用 ·Java虚拟机中可以安装多个类加载器,系统默认三个主要类加载器,每个类负责加载特定位置的类:BootStrap,ExtClassLoader ...
- 黑马程序员——常用类
------<a href="http://www.itheima.com" target="blank">Java培训.Android培训.iOS ...
- 黑马程序员—String类常用方法
---------------------- Windows Phone 7手机开发. .Net培训.期待与您交流! ---------------------- 字符串(String): 注意字符串 ...
- 黑马程序员_Java高新技术--代理
一.生活中的代理更多的用于黑客上面: 武汉人从武汉的代理商手中买联想电脑和直接跑到北京传智播客旁边来找联想总部买电脑,你觉得最终的主体业务目标有什么区别吗?基本上一样吧,都解决了核心问题,但是,一点区 ...
- 黑马程序员——总集篇
-----------android培训.java培训.java学习型技术博客.期待与您交流!------------ 本人编写技术博客的时候只是针对章节的一些比较重要的知识点来编写的: 个人感觉质量 ...
- 【黑马程序员 C++教程从0到1入门编程】【笔记4】C++核心编程(类和对象——封装、权限、对象的初始化和清理、构造函数、析构函数、深拷贝、浅拷贝、初始化列表、友元friend、运算符重载)
黑马程序员C++教程 文章目录 4 类和对象(类属性[成员属性],类函数[成员函数]) 4.1 封装 4.1.1 封装的意义(三种权限:public公共.protected保护.private私有)( ...
- 黑马程序员-----集合框架类(四) 高级for循环、方法的可变参数及静态导入
------- android培训.java培训.期待与您交流! ---------- 黑马程序员-----集合框架类(四) 高级for循环.方法的可变参数及静态导入 1.1 高级for循环(示例1) ...
- [黑马程序员C++笔记]P99-P104类和对象-封装
视频地址:黑马程序员匠心之作|C++教程从0到1入门编程,学习编程不再难_哔哩哔哩_bilibili 目录 P99类和对象-封装-属性和行为作为整体 P100类和对象-封装-案例-设计学生类 P101 ...
- 黑马程序员——Java的代理模式
------- android培训.java培训.期待与您交流! ---------- Java中代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问.在某些情况下,一个客户不想或者不能直接 ...
最新文章
- AsyncQueryHandler了解
- 瑞星2007正版序列号
- python程序将其重复M个字符N次
- 基因注释神器UCSC Genome Browser使用教程
- English sentences
- 涨跌因子计算器下载哪里下载_微信爱情指数计算器整蛊app下载_爱情指数计算器整蛊测试下载...
- dual mysql 获取序列_MySQL JDBC客户端反序列化漏洞
- C#序列化与反序列化详解
- freebsd mysql删_FreeBSD增加、删除以及管理用户(适用Linux)
- 今天看到了和我男朋友不一样的程序员!好帅哦!
- 开源软件 Cachet 被曝RCE漏洞
- ubuntu下mysql无法启动_升级Ubuntu到10.04后MySQL无法启动
- 大数据项目实战数仓4——总纲
- 55)函数指针和其意义
- OpenGL ES 中的模板测试
- sql like N#39;%%#39;,N 是代表什么意思 及Like语句详解
- 命令与征服3 凯恩之怒
- php中composer require和composer require --dev的区别
- Go调试工具Delve
- Swing 写的日期时间组件