java动态代理
动态代理需要注意的:
一、静态代理和动态代理对比:
1、静态代理书写要求:
1)被装饰者和装饰者需要实现同一接口或者实现同一个类。
2)装饰者要有被装饰者的引用。
3)需要加强的方法进行加强。
4)不需要加强的方法,执行原方法。
2、动态代理方法
在项目运行的时候,生成一个代理的对象,对方法进行增强。
2种方式:
1)jdk中方法proxy类,前提是实现接口。
2)spring中cglib,前提:继承类。
动态的在内存中创一个代理对象。
其中jdk中的实现:
static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
参数说明:
1)ClassLoader loader:是代理对象加载内存的类加载器。一般使用的是被代理对象的类加载器。
2)Class<?>[] interfaces:是代理对象需要实现的接口集合,一般是被代理对象的所实现接口的集合。可以通过Class类的public Type[] getGenericInterfaces() 来获取所有的接口集合在进行强转。
3)InvocationHandler:执行处理类,在这里对需要加强的方法,进行加强。
InvocationHandler:Interface InvocationHandler。他是接口,我们可以通过匿名类来实现该接口。
方法:Object invoke(Object proxy, Method method, Object[] args)
参数说明:
proxy:代理对象。这个参数不需要传入,否则的话自己调用自己会处于死循环!
Method:当前执行的方法。
Object[] args:当前执行的方法需要的参数。
动态代理例子:
接口:
1 package jd.com.proxyDemo; 2 3 public interface Car { 4 void run(); 5 void stop(); 6 }
被代理对象类
1 package jd.com.proxyDemo; 2 3 4 5 public class ford implements Car { 6 @Override 7 public void run() { 8 System.out.println("福特车在跑!"); 9 } 10 11 @Override 12 public void stop() { 13 System.out.println("福特刹车了。"); 14 } 15 }
代理对象:
1 package jd.com.proxyDemo; 2 3 import java.lang.reflect.InvocationHandler; 4 import java.lang.reflect.Method; 5 import java.lang.reflect.Proxy; 6 7 public class TT { 8 public static void main(String ... args){ 9 ford ft=new ford(); 10 11 12 Car carproxy= (Car) Proxy.newProxyInstance(ford.class.getClassLoader(), new Class[]{Car.class}, new InvocationHandler() { 13 @Override 14 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 15 //对需要加强的方法进行加强。 16 //其中invoke需要传入被代理的对象,args是执行方法需要的参数。 17 if(method.getName().equalsIgnoreCase("run")){ 18 System.out.println("配置上最牛的发动机"); 19 Object obj=method.invoke(ft,args); 20 System.out.println("1秒加速到 400"); 21 return obj; 22 } 23 return method.invoke(ft,args); 24 } 25 } 26 ); 27 carproxy.run(); 28 carproxy.stop(); 29 } 30 }
静态代理的例子:
接口:
1 package jd.com.staticproxy; 2 3 public interface Car { 4 void run(); 5 void stop(); 6 }
被装饰者代码:
1 package jd.com.staticproxy; 2 3 4 5 6 public class ford implements Car { 7 8 @Override 9 public void run() { 10 System.out.println("福特车在跑!"); 11 } 12 13 @Override 14 public void stop() { 15 System.out.println("福特刹车了。"); 16 } 17 }
装饰者代码:
1 package jd.com.staticproxy; 2 3 import jd.com.staticproxy.Car; 4 5 6 public class TT { 7 public static void main(String ...args){ 8 Tesla tesla=new Tesla(new ford()); 9 tesla.run(); 10 tesla.stop(); 11 } 12 } 13 14 15 class Tesla implements Car{ 16 private Car tesla ; 17 Tesla(ford ft){ 18 this.tesla= ft; 19 } 20 21 @Override 22 public void run() { 23 System.out.println("配置上最牛的发动机"); 24 this.tesla.run(); 25 System.out.println("1秒加速到 400"); 26 27 } 28 29 @Override 30 public void stop() { 31 this.tesla.stop(); 32 } 33 }
二、静态代理和动态代理相同点和不同点:
1、相同点:
1)2个代理都是对方法的增强。
2)2个代理,都是对需要增强的方法进行增强。
3)
2、不同点:
触发机制:
1)静态代理需要在编译前把所有代码(接口、被装饰者),都需要写出来。
2)动态代理只需要实现代理对象,实现处理类InvocationHandler即可。而且是在程序运行的时候,才会创建代理对象。
代码量:
1)静态代理,需要增强的方法增强,不需要增强的方法需要执行原先方法,但是如果方法和增强多的话,代码量较多。
2)动态代理,需要增强方法增强,不需要增加的方法,直接执行原先方法即可,而不需一一书写。直接由InvocationHandler的invoke方法执行即可大大缩短代码量。
总结:
其实代理的一般模式就是静态代理的实现模式:首先创建一个接口(JDK代理都是面向接口的),然后创建具体实现类来实现这个接口,在创建一个代理类同样实现这个接口,不同指出在于,具体实现类的方法中需要将接口中定义的方法的业务逻辑功能实现,而代理类中的方法只要调用具体类中的对应方法即可,这样我们在需要使用接口中的某个方法的功能时直接调用代理类的方法即可,将具体的实现类隐藏在底层。