1.代理模式
代理模式作用:
屏蔽真实行为的访问,让程序更加安全。
可以对真实行为的调用进行控制。
通过一个案例:来说明代理的实现以及代理的作用
代理类和被代理类实现的同一个接口
package cn.itcast.proxy;
//风流的女人
publicinterfaceKindWoman{
publicvoid throwEye();
publicvoid doSomething();
}
pjl作为被代理类,实现接口
//潘金莲 ---被代理
publicclassPjlimplementsKindWoman{
publicvoid throwEye(){
System.out.println("潘金莲抛媚眼");
}
publicvoid doSomething(){
System.out.println("潘金莲。。。。。。。。");
}
}
而代理类需要实现接口,同时有一个构造方法,来接受被代理类的对象
//代理
publicclassWpimplementsKindWoman{
privateKindWoman woman;
publicWp(KindWoman woman){
this.woman = woman;
}
publicvoid throwEye(){
//在这里做操作,可以控制是否调用真实行为。
woman.throwEye();
//在这个位置,可以在真实行为调用完成后,在做操作。
}
publicvoid doSomething(){
woman.doSomething();
}
}
测试的时候,我们执行的是wp,但是调用的是pjl
publicclassXmq{
publicstaticvoid main(String[] args){
KindWoman woman =newJs();
Wp wp =newWp(woman);
wp.throwEye();//真实执行的是潘金莲,但是我们看不到,所以屏蔽了真实行为。
}
}
代理模式实现:
1.代理类与被代理类要实现同一个接口.
2.在代理类中持有被代理对象.
3.在代理类中调用被代理的行为。
AOP:面向方面的编程。
AOP的底层实现就是通过动态代理来做到的。
2.动态代理
它就是在代理模式基础上发展的,它不在是对单一的类型进行代理,
而是可以对任意的一个实现了接口的类的对象做代理。
3.动态代理实现
有两种方式:
1.通过jdk中提供的Proxy类来实现
这种方式要求,被代理类必须实现接口。
简单说,只能为接口做代理.
2.通过cglib来实现。
它不要求,实现接口。主要是通过修改字节码实现的。
4 Proxy代码实现:
Proxy类中有一个方法newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h);
参数:
(1)loader:
要求,传递的是被代理类的类加载器ClassLoader.
类加载器怎样获取:
得到其Class对象。在Class类中提供一个方法 getClassLoader();
(2)interfaces:
要求:得到被代理对象所实现的接口的所有Class对象。
怎样获取所有实现接口的Class对象?
得到其Class对象,在Class类中提供一个方法 getInterfaces();
它返回的是Class[],就代表所实现接口的所有Class对象。
(3)h:
它的类型是InvocationHandler,这是一个接口。
InvocationHandler 是代理实例的调用处理程序 实现的接口。
InvocationHandler接口中有一个方法invoke;
// 参数 proxy就是代理对象
// 参数method就是调用方法
// 参数args就是调用的方法的参数
// 返回值,就是真实行为执行后返回的结果,会传递给代理对象调用的方法.
public Object invoke(Object proxy, Method method, Object[] args);
代码
注意下面代码Proxy.newProxyInstance返回的对象类型应该是接口,此时要注意代理和被代理对象之间是一个兄弟的关系,也就是说他们的父辈是接口,所以一个兄弟不能等于另一个兄弟,而应该等于它的接口,是接口产生的它,而如何去代理你的兄弟呢,在newProxyInstance参数中有需要传递被代理对象的类加载器,还有接口等,这些其实都是说明这个代理类是在那个接口下实现的类,也就是说明他是接口的儿子(被代理类的兄弟),接着要说明我代理哪一个兄弟,需要在InvocationHandler(接口)这个实现类中去说明。
InvocationHandler这是一个接口,我们才用匿名内部类(用的时候直接穿件了他的对象),他里面有三个参数,第一个就说明了我们需要去代理哪一个兄弟,剩下的 是代理哪一个方法和方法中的参数,具体返回时method.invoke,需要两个参数第一个是具体哪个兄弟。
我们分析一下到底是怎么代理的,当sproxy.say执行的时候,会实例化InvocationHandler对象,并且执行其中的invoke方法,那么此时第二个参数method就是调用的方法say,第三个参数args就是“james",然后会返回被代理对象执行该方法的结果,得到message,所以代理对象执行的时候是要走invoke方法内的东西,这也就实现了过滤和安全性考虑。上面相同颜色代表同一个东西
publicstaticvoid main(String[] args){
finalKindWoman woman =newPjl();
// 做一个Pjl的代理.
KindWoman proxy =(KindWoman)Proxy.newProxyInstance(woman.getClass()
.getClassLoader(), woman.getClass().getInterfaces(),
newInvocationHandler(){
publicObject invoke(Object proxy,Method method,
Object[] args)throwsThrowable{
return method.invoke(woman, args);//woman.方法名(参数)
}
});
}