代理
-
代理:充当中介,当A不能直接访问C时,需找一个中介,A->B->C,B就是代理。
-
代理模式:通过代理方来操作目标对象,而不是自己直接调用。
-
使用代理模式的作用:
- 功能增强:在已有的功能上增加其他的功能。
- 控制访问:代理类不让调用方直接访问被调用方。
-
实现代理的方式:
-
静态代理static-proxy:代理类是自己创建一个java类手工实现,表示代理类,明确要代理的目标。
- 优点:实现简单、容易理解。
- 缺点:当目标类增加,代理类可能需成倍增加。当接口中的功能修改时,会影响实现类。不符合开闭(OCP)原则。目标类越多影响范围越大。
-
动态代理:在静态代理中目标类很多时,可采用动态代理。动态代理中的目标类及时很多,代理类也可以很少,,修改接口中的方法时,不会影响代理类
-
动态代理使用JDK的反射机制,创建代理类对象,并动态的指定要代理的目标类,代理类是活动的,可设置的。
Class.forNAme(String);
-
动态:在程序执行时,通过JDK创建代理类对象。
-
特点:不用创建代理类,可以给不同的目标随时创建代理
-
动态代理
-
实现方式有两种:
-
JDK动态代理:使用java反射包中的类和接口实现动态代理的功能。要求目标类中必须有接口。
//全限定名 java.lang.reflect.InvocationHandler java.lang.reflect.Method java.lang.reflect.Proxy
-
cglib动态代理:cglib是第三方工具库,创建代理对象,Cglib的原理是继承,通过继承目标类,创建它的子类,在子类中重写父类中的同名方法,实现功能修改。
-
因为Cglib是通过继承重写实现,要求目标类不能为Final的,方法也不能为Final的。
JDK动态代理
反射,通过Method类,表示方法,类中的某个方法,通过Method可以执行某方法。
//伪代码 //代理类 A a = new A(); //通过反射调用代理类的方法 Method method = A.class.getMethod(方法名,方法参数类型); //执行方法,返回方法返回对象 Object obj = method.invoke(a,方法参数)
JDk动态代理的实现
1)InvocationHandler(调用处理器)接口:只有一个方法invoke()
invoke():表示代理对象要执行的功能代码,代理类功能写在invoke()中。
代理类完成的功能:1、调用目标方法,执行目标方法的功能。2、功能增强,在目标方法调用时,增加功能。
//方法原型 //参数 Object proxy:JDK创建的代理对象,无需赋值 //参数 Method method: 目标类的方法,JDK提供Method对象。 //参数 Object... args:method方法中的执行参数。JDK提供的 public Object invoke(Object proxy, Method method, Object[] args)
怎么用?
1、创建类实现接口InvocationHandler,实际上InvocationHandler接口表示你的代理要干什么。
2、重写invoke()方法,把原来静态代理中代理要完成的功能写在该方法中。
2)Method类,表示方法的,确切的说就是目标类中的方法,通过Methed可以执行某个目标类的方法。
method.invoke(目标对象,方法的参数); Object obj = method.invoke(目标对象,方法的参数);
3)Proxy类:核心的对象,创建的代理对象。
方法:静态方法 newProxyInstance()
作用是:创建代理对象,等同与静态代理中的new一个对象。
//参数 ClassLoader 类加载器,负责向内存中加载对象的,使用反射获取对象的ClassLoader 类a,a.getClass().getClassLoader(),目对象的类加载器 //参数 Class<?>[] interfaces 接口,目标对象实现的接口,也是反射获取的 //参数 InvocationHandler h 自己写的 代理类要完成的功能 //返回值:代理对象 public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
实现动态代理的步骤:
1、创建接口,定义目标类要完成的功能。
2、创建目标类实现接口。
3、创建InvocationHandler接口实现类,在Invoke()方法中完成代理类的功能。
1)调用目标方法。
2)实现增强方法。
4、使用Proxy类的静态方法,创建代理对象,并把返回值转为接口类型。
动态代理的使用场景:
1、可以在不改变原来的目标方法功能前提下,在代理中增强自己的功能代码。
//示例代码 public class testProxy { public static void main(String[] args) { //声明被代理对象 SayHelloPlus sayHelloPlus = new SayHelloPlus(); //调用发掉用处理器 InvocationHandler invo = new Myhandler(sayHelloPlus) {}; HelloServic proxyInstance = (HelloServic) Proxy.newProxyInstance(sayHelloPlus.getClass().getClassLoader(), sayHelloPlus.getClass().getInterfaces(), invo); //调用动态代理对象对象方法 proxyInstance.sayHello("helloKitty"); }
//被代理接口 public interface HelloServic { public void sayHello(String name); }
//被代理功能 public class SayHelloPlus implements HelloServic { @Override public void sayHello(String name) { System.out.println("Hello " + name); } }
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; //实现代理功能 与增强功能 public class Myhandler implements InvocationHandler { Object target; public Myhandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("Plus+++++"); return method.invoke(target, args); } }
-