为什么我们使用动态代理
静态代理会让类变多了,多了代理类,工作量变大了,且不易扩展。比如我们上节课的例子,要实现不同的扩展方法就要编写不同的代理类,非常麻烦。
Proxy类的使用规则
Proxy提供了用于创建动态代理类和代理对象的静态方法,它也是所有动态代理类的父类。如果在程序中为一个或多个接口动态生成实现类,就可以使用 Proxy 来创建动态代理类。如果需要为一个或多个接口动态地创建实例,也可以使 Proxy 来创建动态代理实例。
Proxy提供了如下两个方法来创建动态代理类和动态代理实例:
- static Class getProxyClass(ClassLoader loader, Class... interfaces): 创建一个动态代理类所对应的 Class对象,该代理类将实现interfaces 所指定的多个接口。第一个 ClassLoader 参数指定生成动态代理类的类加载器。(已过时)
- static Object newProxyInstance(ClassLoader loader,Class[] interfaces, InvocationHandler h): 直接创建一个动态代理对象,代理对象的实现类实现了 interfaces 指定的系列接口 ,执行代理对象的每一个方法时都会被替换执行InvocationHandler 对象的 invoke 方法。
用实例来说明一下:
1,我们先定义一个接口:
package com.zmd.dynamicProxy; /** * @ClassName Person * @projectName: object1 * @author: Zhangmingda * @description: XXX * date: 2021/5/16. */ public interface Person { void walk(); void sayHello(String name); }
2,定义自定义的InvocationHandler 继承InvocationHandler:
package com.zmd.dynamicProxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; /** * @ClassName MyInvocationHandler * @projectName: object1 * @author: Zhangmingda * @description: XXX * date: 2021/5/16. */ public class MyInvocationHandler implements InvocationHandler { @Override public Object invoke(Object o, Method method, Object[] objects) throws Throwable { System.out.println("=======正在执行方法:"+ method.getName()); if (objects != null) { System.out.println("下面为传入的参数:"); for (Object arg : objects) { System.out.println(arg); } } else { System.out.println("没有传入任何的参数"); } return null; } }
3,调用测试:
package com.zmd.dynamicProxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; /** * @ClassName MyInvocationTest * @projectName: object1 * @author: Zhangmingda * @description: XXX * date: 2021/5/16. */ public class MyInvocationTest { public static void main(String[] args) { InvocationHandler invocationHandler = new MyInvocationHandler(); Person person = (Person) Proxy.newProxyInstance(Person.class.getClassLoader(),new Class[]{Person.class},invocationHandler); person.walk(); person.sayHello("美女"); } }
动态代理和AOP
根据前面介绍的 Proxy和InvocationHandler,实在很难看出这种动态代理的优势 下面介绍一种更实用的动态代理机制。
开发实际应用的软件系统时,通常会存在相同代码段重复出现的情况,在这种情况下,对于许多刚开始从事软件开发的人而言,他们的做法是:选中那些代码,Ctrl+C、Ctrl+V,如果仅仅从软件功能上来看,他们确实已经完成了软件开发。但是万一这段相同的逻辑需要改动呢?是不是要改很多地方呢?
用看电影举例:
1,首先创建电影功能接口:
package com.zmd.dynamicProxy.movieExample; public interface Movie { void play(); }
2,创建Movie的实现类(电影):
package com.zmd.dynamicProxy.movieExample; public class ZhanlangMovie implements Movie { @Override public void play() { System.out.println("战狼,播放中..."); } }
3,创建代理用的工具类,比如放电影之前和之后要干的事儿
package com.zmd.dynamicProxy.movieExample; public class MovieUtil { //play之前的方法 public static void before(){ System.out.println("PLAY 之前...."); } //play之前的方法 public static void after(){ System.out.println("PLAY 之后...."); } }
4,创建自定义代理类继承InvocationHandler,使用工具类为要代理接口实现类增加效果
package com.zmd.dynamicProxy.movieExample; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class MyInvocationHandler implements InvocationHandler { private Movie movie; public MyInvocationHandler(Movie movie) { this.movie = movie; } @Override public Object invoke(Object o, Method method, Object[] args) throws Throwable { //先调用工具类的方法(加广告) MovieUtil.before(); //执行被包装的类的方法 Object result = method.invoke(movie, args); //再调用工具类的方法(还是广告) MovieUtil.after(); return result; //被包装的类的方法返回什么,这里也返回什么 } }
5,利用代理类封装功能类,传入被代理的接口实现类(电影),返回真正给用户的电影
package com.zmd.dynamicProxy.movieExample; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; public class MovieFactory { public static Movie getFactoryMovie(Movie movie){ InvocationHandler movieInvocationHandler = new MyInvocationHandler(movie); Movie movie1 = (Movie) Proxy.newProxyInstance(movie.getClass().getClassLoader(),movie.getClass().getInterfaces(),movieInvocationHandler); return movie1; } }
6、使用代理类
package com.zmd.dynamicProxy.movieExample; public class FactoryMovieTest { public static void main(String[] args) { Movie zhanlang = MovieFactory.getFactoryMovie(new ZhanlangMovie()); zhanlang.play(); } }
PLAY 之前....
战狼,播放中...
PLAY 之后....
带泛型的代理,代理一切...
代理类 MyInvocationHandler.java
package com.zmd.dynamicProxy.movieExample; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; /** * @ClassName MyInvocationHandler * @projectName: object1 * @author: Zhangmingda * @description: XXX * date: 2021/5/17. */ public class MyInvocationHandler <T> implements InvocationHandler { private T movie; public MyInvocationHandler(T movie) { this.movie = movie; } @Override public Object invoke(Object o, Method method, Object[] args) throws Throwable { //先调用工具类的方法(加广告) MovieUtil.before(); //执行被包装的类的方法 Object result = method.invoke(movie, args); //再调用工具类的方法(还是广告) MovieUtil.after(); return result; } }
使用代理做的包装工具类 MovieFactory.java
package com.zmd.dynamicProxy.movieExample; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; /** * @ClassName MovieFactory * @projectName: object1 * @author: Zhangmingda * @description: XXX * date: 2021/5/17. */ public class MovieFactory<T> { public static <T> T getFactoryMovie(T movie){ InvocationHandler movieInvocationHandler = new MyInvocationHandler(movie); T movie1 = (T) Proxy.newProxyInstance(movie.getClass().getClassLoader(),movie.getClass().getInterfaces(),movieInvocationHandler); return movie1; } }
测试使用
音乐接口和实现类
package com.zmd.dynamicProxy.movieExample; public interface Music { void play(); }
package com.zmd.dynamicProxy.movieExample; public class YueLiangZhiShang implements Music { @Override public void play() { System.out.println("我在遥望,月亮之上..."); } }
测试类
package com.zmd.dynamicProxy.movieExample; /** * @ClassName FactoryMovieTest * @projectName: object1 * @author: Zhangmingda * @description: XXX * date: 2021/5/17. */ public class FactoryMovieTest { public static void main(String[] args) { Movie zhanlang = MovieFactory.getFactoryMovie(new ZhanlangMovie()); zhanlang.play(); Music yueliangzhishang = MovieFactory.getFactoryMovie(new YueLiangZhiShang()); yueliangzhishang.play(); } }
PLAY 之前....
战狼,播放中...
PLAY 之后....
PLAY 之前....
我在遥望,月亮之上...
PLAY 之后....