代理的概念与作用
最终的主体业务目标是一样的
通过代理比较方便
程序中的代理
有一个类已经开发好了,想为这个类增加一些功能,例:异常处理、日志、计算方式
想在类中增加功能,类的源代码没有
写一个代理程序,创建一个方法,在目标方法的前后增加了辅助功能,以后客户直接使用代理的方法即可。
编写一个与目标类具有相同接口的代理类,代理类的每个方法调用目标类的相同方法,并在调用方法时加上系统功能的代码
如果采用工厂模式和配置文件的方式进行管理,则不需要修改客户端程序,在配置文件中配置是使用目标类,还是代理类,这样以后很容易切换,譬如,想要日志功能时就配置代理类,否则配置目标类,这样,增加系统功能很容易,以后运行一段时间后,又想去掉系统功能也很容易
客户端不直接使用目标类,使用代理类
代理类和目标类实现了接口
代理类中会增加一些功能代码
在配置文件中配置要使用代理类还是目标类
AOP
系统中存在交叉业务,一个交叉业务就是要切入到系统中的一个方面
面向方面的面呈 aspect oriented program
各种事里面都有安全都要事物管理,都要有日志,这些东西贯穿在好几个模块中
着就是模块的交叉业务
每个方法都被这一个功能切断
是一个切面
Aop的目标就是要使交叉业务模块化
切面中只写一份就够了,用代理的方法来实现
动态代理技术
要为系统中的各种借口的类增加代理功能,要给许多个代理类,太麻烦
JVM可以在运行期动态生成出类的字节码,这种动态生成的类往往被用作代理类,即动态代理类,动态生成的类不是代理,但是我们把他用作代理
JVM生成的动态类必须实现一个或多个接口,所以,jvm生成的动态类智能用作具有相同接口的目标类的代理
如果目标类没有实现接口怎么办
用到了CGLB
CGLB库可以动态生成一个类的子类,一个类的子类也可以用作该类的代理,所以,如果要为一个没有实现接口的类生成动态代理类,那么可以使用CGLIB库
代理类的各个方法中通常除了要调用目标的相应方法和对外返回目标返回的结果外,还可以在代理方法中的如下四个位置加上系统功能代码:
1,在调用目标方法之前
2,在调用目标方法之后
3,在调用目标方法前后
4,在处理目标方法异常的catch块中
分析JVM动态生成的类
创建实现了Collection接口的动态类和查看其名称,分期Proxy.getProxyClass方法的各个参数。
编码列出动态类中的所有构造方法和参数签名
编码列出动态类中的所有方法和参数签名
Proxy 反射包中
静态的返回的是 Class字节码 getProxyClass 传入参数实现哪些接口
每一个字节码都可以得到字节的类加载器,一定要指定一个类加载器,虽然是内存中创建出来的
Proxy.getProxyClass(Collection.class.getClassLoader(),Collection.class)
通常用接口相同的类加载器
ClassclazzProxy1
clazzProxy1.getName()
类的名字$Proxy0
获取类的构造方法,
生成了一个构造方法参数是 InvocationHandler
方法都是collection的方法和object的方法
得到了Class之后,创建他的实例对象
Constructorconstructor = clazzProxy1.getConstructro(InvocationHandler.class)
Constructor.newInstance()
InvocationHandler
ClassMyInvocationHandler1 implemnts InvocationHandler{
Returnnull;
}
用代理创建的对象肯定是Collection对象
打印Collection对象,为null
要么对象没有创建成功,要么toString返回的是null
调用toString()
打印了null,说明对象创建成功了,因为对象是null的话就不能调用toString()方法了
p.clear();
1,必须明确实现哪些接口
2,产生的类字节码必须有一个关联的类加载器对象
3,要传递一个InvocationHandler.class进去
创建对象和创建实例对象,合在一起
Proxy提供了newProxyInstance方法
接口,类加载,handler()
Collectionsc= (Collection)Proxy.newProxyInstatncec(
Collection.class.getClassloader(),
NewClass[](Collectioin.class),
NewInvocationHandler(){
PublicObject invoke(ojfjowe)
Returnnull;
}
)
每调用一个方法,就调用了一次方法
每调用个add方法,就会找invocationihandler的invoke方法,
每次invoke都调用了一个ArrayList目标
将对象放入到成员变量中,那长度就会发生改变了,就操作同一个对象
动态类有个构造方法,接受一个invocationHandler对象
IntSize(){return handler.invoke(
this.this.getclass().getMethod(“size”),null)
调用其中的方法,就执行了一次invoke方法
客户端程序,调用代理的方法是,涉及三个方法
调用哪个对象,这个对象的什么方法,传入什么参数
Return method.linvoke(proxy,args)调用哪个对象的方法,传入什么参数
在自身的invoke方法中调用本代理对象,传入args就会无限循环
调用目标
代理对象中有目标的所有方法,调用代理的方法,就是调用了代理中invoke的方法,invoke有指向了目标的方法
代理记录这个值并返回
Objectobj = proxy3.add(“fewf”)
代理返回获得的值
在调用目标之前对参数进行健壮性判断
代理可以修改传入的参数和返回的数值
如果invoke方法返回的类型和目标的返回类型不同,那么就会报错
因为有些类型转换不行
如果返回的类型是目标的子类会怎么样???
调用代理的getClass,getName是代理的类型
按照前面将的如果调用getClass方法,那么应该会调用代理的invoke方法,会调用目标的getClass方法,与现象不符
hasCode,equals,toString 将这三个方法委托给了handler
invocationHandler是proxy代理的接口
覆盖其中的invoke方法实现proxy子类
Invoke中的log()
将代码用参数的形式表现,为了让以后可能方便的调用
将传递进来字符串,把字符串当语言来执行
将日志功能封装成对象,传入对象就可以调用对应的代码
将目标类传禁区
直接在InvocationHandler实现类中创建目标类的实例对象,可以看运行效果和加入日志代码,没有意义
为InvocationHandler实现类注入目标类的实例对象,不能采用匿名内部类的形式了
让匿名的invocationHandler实现类王文外面方法中的目标实例对象的final类型的引用变量
写入系统内部不能修改的叫做硬编码
还要传递系统功能的对象
传入一个目标,实现目标的共同抽象接口
实现AOP功能的封装与配置
工厂类BeanFactory负责创建目标类或代理类的实例对象,并通过配置文件实现切换,其getBean方法根据参数字符串返回一个享誉的护理对象,如果参数字符串在配置文件中对应的类名不是ProxyFactoryBean,则直接返回该类的实例对象,否则,返回该类实例对象getProxy方法返回的对象
如果是ProxyFactoryBean 那么就用它的getProxy()
---------------------- android培训、 java培训、期待与您交流! ----------------------详细请查看: http://edu.csdn.net/heima