动态代理

1.代理模式

代理模式作用:

屏蔽真实行为的访问,让程序更加安全。
可以对真实行为的调用进行控制。

通过一个案例:来说明代理的实现以及代理的作用

代理类和被代理类实现的同一个接口

  1. package cn.itcast.proxy;
  2. //风流的女人
  3. publicinterfaceKindWoman{
  4. publicvoid throwEye();
  5. publicvoid doSomething();
  6. }

pjl作为被代理类,实现接口

  1. //潘金莲 ---被代理
  2. publicclassPjlimplementsKindWoman{
  3. publicvoid throwEye(){
  4. System.out.println("潘金莲抛媚眼");
  5. }
  6. publicvoid doSomething(){
  7. System.out.println("潘金莲。。。。。。。。");
  8. }
  9. }

而代理类需要实现接口,同时有一个构造方法,来接受被代理类的对象

  1. //代理
  2. publicclassWpimplementsKindWoman{
  3. privateKindWoman woman;
  4. publicWp(KindWoman woman){
  5. this.woman = woman;
  6. }
  7. publicvoid throwEye(){
  8. //在这里做操作,可以控制是否调用真实行为。
  9. woman.throwEye();
  10. //在这个位置,可以在真实行为调用完成后,在做操作。
  11. }
  12. publicvoid doSomething(){
  13. woman.doSomething();
  14. }
  15. }

测试的时候,我们执行的是wp,但是调用的是pjl

  1. publicclassXmq{
  2. publicstaticvoid main(String[] args){
  3. KindWoman woman =newJs();
  4. Wp wp =newWp(woman);
  5. wp.throwEye();//真实执行的是潘金莲,但是我们看不到,所以屏蔽了真实行为。
  6. }
  7. }

代理模式实现:

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方法内的东西,这也就实现了过滤和安全性考虑。上面相同颜色代表同一个东西

  1. publicstaticvoid main(String[] args){
  2. finalKindWoman woman =newPjl();
  3. // 做一个Pjl的代理.
  4. KindWoman proxy =(KindWoman)Proxy.newProxyInstance(woman.getClass()
  5. .getClassLoader(), woman.getClass().getInterfaces(),
  6. newInvocationHandler(){
  7. publicObject invoke(Object proxy,Method method,
  8. Object[] args)throwsThrowable{
  9. return method.invoke(woman, args);//woman.方法名(参数)
  10. }
  11. });
  12. }





原文地址:https://www.cnblogs.com/oneNightStand/p/6509812.html