黑马程序员——浅谈java中的高新技术(三)
来源:互联网 发布:织梦qq客服插件 编辑:程序博客网 时间:2024/05/09 13:43
---------------------- <a href="http://edu.csdn.net"target="blank">ASP.Net+Android+IOS开发</a>、<a href="http://edu.csdn.net"target="blank">.Net培训</a>、期待与您交流! ----------------------
代理
一、概念及作用
1、生活中的代理:就是常说的代理商,从厂商将商品卖给消费者,消费者不用很麻烦的跑到厂商那里去购买。
2、程序中的代理:要为已经存在的多个具有相同接口的目标类的各个方法增加一些系统功能,如异常处理、日志、计算方法的运行时间、事物管理等等。
3、简单示例:编写一个与目标类具有相同接口的代理类,代理类的每个方法调用目标类的相同方法,并在调用方法时加上系统功能的代码,如:
代理架构图
代码体现:
相同接口:interfaceA{void sayHello();}
目标类: 代理类:
class X implements A{ class Xproxy implements A{
void sayHello(){ void sayHello(){
System.out.println(“Hello”); startTime;
} X. sayHello();
} endTime;}}
目标类和代理类通常实现同一个或多个接口,一般用该接口来引用其子类(代理类),如:
Collection coll = new ArrayList();
4、代理类的优点:
如果采用工厂模式和配置文件的方式进行管理,则不需要修改客户端程序,在配置文件中配置是使用目标类还是代理类。这样以后很容易切换,如果想要日志功能时,就配置代理类,否则配置目标类,这样,增加系统功能很容易,以后运行一段时间后,又想换掉系统功能也很容易。
二、AOP
1、简述:AOP(AspectOriented Program)即面向方面的编程。
2、示意图
系统中存在交叉业务,一个交叉业务就是要切入到系统中的一个方面,如下所示:
安全 事务 日志
StudentService ------|----------|------------|-------------
CourseService ------|----------|------------|-------------
MiscService -------|----------|------------|-------------
安全、事务、日志等功能要贯穿于好多个模块中,所以他们就是交叉业务。
3、用具体的程序代码描述交叉业务:
1)交叉业务的代码实现
method1 method2 method3
{ { {
------------------------------------------------------切面
.... .... ......
------------------------------------------------------切面
} } }
2)交叉业务的编程问题即为面向方面的编程(Aspect orientedprogram ,简称AOP),AOP的目标就是要使交叉业务模块化。可以采用将切面代码移动到原始方法的周围,这与直接在方法中编写切面代码的运行效果是一样的,如下所示:
------------------------------------------------------切面
func1 func2 func3
{ { {
.... .... ......
} } }
------------------------------------------------------切面
因此使用代理技术正好可以解决这种问题,代理是实现AOP功能的核心和关键技术,只要是用到面向方面的编程,就涉及到代理。
第二讲 动态代理技术
一、概述
1、要为系统中的各种接口的类增加代理功能,那将需要太多的代理类,这时就不能全部采用静态代理的方式,因为要写成百上千个代理类是非常麻烦的,这时就需用动态代理技术。
2、动态代理类:JVM可以在运行期,动态生成类的字节码,这种动态生成的类(不是代理,只是拿来用作代理类)往往被用作代理类,即动态代理类。
注:JVM生成的动态类必须实现一或多个接口,所以JVM生成的动态代理类只能用作具有相同接口的目标类代理。
3、CGLIB库可以动态生成一个类的子类,一个类的子类也可以用作该类的代理。所以,如果要为一个没有实现接口的类生成动态代理类,那么可以使用CGLIB库。
4、代理类各个方法通常除了调用目标相应方法和对外返回目标返回的结果外,还可以在代理方法中的如下位置上加上系统功能代码:
1)在调用目标方法之前
2)在调用目标方法之后
3)在调用目标方法前后
4)在处理目标方法异常的catch块中。
二、分析JVM动态生成的类
以创建实现了Collection接口的代理类为例:
1、用Proxy.getProxyClass方法创建实现了Collection接口的动态类和查看其名称,分析getProxyClass方法的各个参数。
1)编码列出动态类中的所有构造方法和参数签名
2)编码列出动态类中的所有方法和参数签名
2、创建动态类的实例对象
1)用反射获得构造方法
2)编写一个最简单的InvocationHandler类(代理类构造方法接收的参数)
3)调用构造方法创建动态类的实例对象,并将编写的InvocationHandler类的实例对象传进去
4)打印创建的对象和调用对象的没有返回值的方法和getClass方法,演示调用其他有返回值的方法报告了异常。
5)将创建动态类的实例对象的代理改成匿名内部类的形式编写,锻炼匿名内部类的使用。
3、也可以直接用Proxy.newInstance方法直接一步就创建出代理对象。
示例:
4、让JVM创建动态类及其实例对象,需要提供的信息:
1)生成类中的哪些方法,通过让其实现哪些接口的方式进行告知。
2)产生的类字节码必须有一个关联的类加载器对象
3)生成的类中的方法的代码是怎么样的,也得由我们自己提供。把我们的代码写在一个约定好的子接口对象的方法中,把对象传给它,它调用我们的方法,即相当于插入了我们自己的代码。提供执行代码的对象就是InvocationHandler对象,它是在创建动态类的实例对象的构造方法时传递进去的,在上面的InvocationHandler对象的invoke方法中,加一点代码就可以看到这些代码被调用运行了。
三、分析动态生成的类的内部代码
1、如上示例中,动态生成的类实现了Collection接口(可以实现若干接口),生成的类有Collection接口中的所有方法和一个接收InvocationHandler参数的构造方法。接受此对象的用处:在类中定义这个对象的引用,以便在需要时应用它。
2、实现Collection接口的动态类中的各个方法的代码的解析:
InvocationHandler接口中定义的invoke方法接受三个参数的含义:
第一、Client(客户端)程序调用objProxy.add(“avc”)方法时,涉及到了三个要素,分别为:objProxy对象,add方法,”avc”参数。代码如下:
第二、其中的Object proxy即为objProxy对象,Method method对应add方法,Object[] args就是”avc”参数。在使用newProxyInstance的方式创建代理对象实现时,当前正在调用的代理对象(Object proxy),调用当前对象的哪个方法(Method method),调用此对象方法时传入的参数(Object[] args)。
4、对于上面代码中的Object retVal = method.invoke(target,args)的分析:
目标对象target执行完返回一个值为retVal,接着将值作为结果return回去,则代理方法就会收到一个返回值。其中还可以定义一个过滤器,对参数args(即当前对象的方法传入的参数)进行过滤(修改)。
5、对于上面代码中的proxy3.add(“sdfd”)的分析:
1)代理对象调用add方法,传递了sdfd参数。
2)add方法内部会找到InvocationHandler中的invoke方法,将代理对象proxy传进去,把add方法传入,将“sdfd”参数传入代理对象中的handler参数,返回了一个结果给了add方法,add方法继续向外返回给调用的对象proxy3,即最终结果。
四、问题
1、在上面的方式一的代码中,调用无返回值的方法返回的是null,而调用有返回值方法的时候会报NullPointException异常的原因:
在proxy1.size()方法中,size()会调用Object invoke()方法,而对其覆写时的返回值是null,而size()本身会返回int类型,两者返回的类型不相等,所以就会报错。
而对于proxy3.size()不报错,是因为size()返回值与invoke()方法返回值是一致的,当前目标返回什么,代理就返回什么,所以不会报错。
注意:目标返回值和代理返回值必须是同一类型。
2、为何动态类的实例对象的getClass()方法返回了正确结果:
因为只有调用代理对象从Object类继承的hashCode,equals,或toString这几个方法时,代理对象会将调用请求转发给InvocationHandler对象,对于其他方法,则不转发调用请求。所以对于getClass()方法,还是Object实例的原方法。即proxy3.getClass(),该是什么结果还是什么结果,并不会交给invoke方法处理。
实现代码如下:
五、总结分析动态代理类的统计原理和结构
1、怎样将目标传进去:
1)直接在InvocationHandler实现类中创建目标类的实例对象,可看运行效果和加入日志代码,但是没有实际意义。
2)为InvocationHandler实现类注入目标的实例对象,不能采用匿名内部类的形式了。
3)让匿名内部类的InvocationHandler实现类访问外面的方法中的目标类实例对象的final类型的引用变量。
2、动态代理的工作原理:
1)Client(客户端)调用代理,代理的构造方法接收一个InvocationHandler,client调用代理的各个方法,代理的各个方法请求转发给刚才通过构造方法传入的handler对象,又把各请求分发给目标的相应的方法。
示意图:
2)将创建代理的过程改为一种更优雅的方式,eclipse重构出一个getProxy方法绑定接收目标,同时返回代理对象,让调用者更懒惰,更方便,调用者甚至不用接触任何代理的API。
在这里将InvocationHandler加入到Proxy的构造方法中,因此,在创建出来的对象,就会存有构造方法中InvocationHandler的一些功能和信息,因为我们把想要运行的代码封装在InvocationHandler对象,把它传入到构造函数中,那么就实现了代理对象每次调用与目标方法相同方法(因为实现了同一接口)时,都会调用我们加入到InvocationHandler对象中的代码。这就保证了每次调用代理时,可以在目标上加入我们自己加入的功能。
3、把系统功能代理模块化,即切面代码也改为通过参数形式提供,怎么把要执行的系统功能代码以参数的形式提供:
1)把要执行的代码装到一个对象的某个方法中,然后把此对象作为参数传递,接收者只要调用这个对象的方法,即等于执行了外接提供的代码。
2)为getProxy方法增加一个Advice参数。
示例:
第三讲 实现AOP功能的封装与配置
一、工厂类BeanFactory
1、工厂类BeanFactory负责创建目标类或代理类的实例对象,并通过配置文件实现切换。
2、getBean方法根据参数字符串返回一个相应的实例对象,如果参数字符串在配置文件中对应的类名不是ProxyFactoryBean,则直接返回该类的实例对象,否则返回该类示例对象的getProxy方法返回的对象。
3、BeanFactory的构造方法接收代表配置文件的输入流对象的配置文件格式如下:
#xxx=java.util.ArrayList
xxx=cn.itcast.test3.aopframework.ProxyFactoryBean
xxx.advice=cn.itcast.test3.MyAdvice
xxx.target=java.util. ArrayList
注意:其中的#代表注释当前行。
4、ProxyFactoryBean充当封装成动态的工厂,需为工厂提供的配置参数信息包括:
目标(target)
通知(advice)
5、BeanFactory和ProxyFactoryBean:
1)BeanFactory是一个纯粹的bean工程,就是创建bean即相应的对象的工厂。
2)ProxyfactoryBean是BeanFactory中的一个特殊的Bean,是创建代理的工厂。
二、实现类似spring的可配置的AOP框架的思路
1、创建BeanFactory类:
1)构造方法:接受一个配置文件,通过Properties对象加载InputStream流对象获得。
2)创建getBean(String name)方法,接收Bean的名字,从上面加载后的对象获得。
3)通过其字节码对象创建实例对象bean。
4)判断bean是否是特殊的Bean即ProxyFactoryBean,如果是,就要创建代理类,并设置目标和通告,分别得到各自的实例对象,并返回代理类实例对象。如果不是在返回普通类的实例对象。
2、创建ProxyFactoryBean(接口),此处直接定义为类做测试,其中有一个getProxy方法,用于获得代理类对象。
3、编写实现Advice接口的类和在配置文件中进行配置。
4、定义一个测试类:AopFrameworkTest,也称客户端,调用BeanFactory获取对象。
示例:
配置文件信息:
xxx=java.util.ArrayList
xxx=cn.itheima.demo.aopframework.ProxyFactoryBean
xxx.target=java.util.ArrayList
xxx.advice=cn.itheima.demo.MyAdvice
- 黑马程序员——浅谈java中的高新技术(三)
- 黑马程序员——浅谈java中的高新技术(一)
- 黑马程序员——浅谈java中的高新技术(二)
- 黑马程序员——高新技术(三)
- 黑马程序员—java高新技术(一)
- 黑马程序员—java高新技术(1)
- 黑马程序员—java高新技术(2)
- 黑马程序员—java高新技术
- 黑马程序员---Java高新技术(三)--反射
- 黑马程序员——浅谈java中的内部类<三>
- 黑马程序员-Java高新技术(三)
- 黑马程序员 Java高新技术 三
- 黑马程序员-Java高新技术(三)
- 黑马程序员——黑马学习日志之二十一 Java高新技术(三)
- 黑马程序员——Java高新技术
- 黑马程序员——【Java】【高新技术】反射
- 黑马程序员java高新技术——反射
- 黑马程序员java高新技术——注解
- 关于nmap的几个技巧
- 黑马程序员——浅谈java中的高新技术(二)
- 你的底线,决定你的拥有
- 笔记《unsupervised subpixelic clasificationg using coarse-resolution time series》
- Java常量池--详细介绍(百度百科)
- 黑马程序员——浅谈java中的高新技术(三)
- hdu 2501 Tiling_easy version (水题)
- hadoop安装lzo-出现Could not load native gpl library问题解决
- Oracle用户的管理
- 如何对Exadata的I/O进行性能校准测试
- 最大连续子向量和的计算
- An Easy Problem for Elfness
- 黑马程序员——浅谈java中的面试题(交通灯管理系统)
- 分享3个未注册微博类域名