Java中的静态代理和动态代理
静态代理
电影是电影公司委托给影院进行播放的,但是影院可以在播放电影的时候,产生一些自己的经济收益,比如卖爆米花、可乐等,然后在影片开始结束时播放一些广告。
现在用代码来进行模拟。
首先写一个接口,有播放电影的功能
public interface Movie {
void play(); }
然后,创建一个真正实现Movie接口的类
public class RealMovie implements Movie { @Override public void play() { // TODO Auto-generated method stub System.out.println("您正在观看电影 《肖申克的救赎》"); } }
写一个代理类(电影院),除了有播放电影的功能外,还有其他附加功能
Cinema 就是 Proxy 代理对象,它有一个 play() 方法。不过调用 play() 方法时,它进行了一些相关利益的处理,那就是广告。
public class Cinema implements Movie { 4 5 RealMovie movie; 6 7 public Cinema(RealMovie movie) { 8 super(); 9 this.movie = movie; 10 } 11 12 13 @Override 14 public void play() { 15 16 guanggao(true); 17 18 movie.play(); 19 20 guanggao(false); 21 } 22 23 public void guanggao(boolean isStart){ 24 if ( isStart ) { 25 System.out.println("电影马上开始了,爆米花、可乐、口香糖9.8折,快来买啊!"); 26 } else { 27 System.out.println("电影马上结束了,爆米花、可乐、口香糖9.8折,买回家吃吧!"); 28 } 29 } 30 31 }
测试代码
public class ProxyTest { public static void main(String[] args) { RealMovie realmovie = new RealMovie(); Movie movie = new Cinema(realmovie); movie.play(); } }
动态代理
与静态代理的功能与目的是没有区别的,区别在于:
上一节代码中 Cinema 类是代理,我们需要手动编写代码让 Cinema 实现 Movie 接口,而在动态代理中,我们可以让程序在运行的时候自动在内存中创建一个实现 Movie 接口的代理,而不需要去定义 Cinema 这个类。这就是它被称为动态的原因。
动态代理的例子:
1.
定义一个电影接口
/**
* 定义一个电影接口
*/
public interface Movie {
void play();
}
2.定义一个实际的电影类,实现Movie接口
package 动态代理;
/**
* 定义一个实际的电影类,实现Movie接口
*/
public class RealMovie implements Movie{
@Override
public void play() {
System.out.println("正在播放电影");
}
}
3.定义一个类,实现InvocationHandler接口,并实现其invoke方法
/**
* 定义一个类,实现InvocationHandler接口,并实现其invoke方法
*/
public class Cinema implements InvocationHandler {
private Object movie; //使用构造方法将new时传入的参数作为实际对象
public Cinema(Object movie) {
this.movie = movie;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("电影开始");
method.invoke(movie,args);
System.out.println("电影结束");
return null;
}
}
4.测试
public class MovieTest {
public static void main(String[] args) {
RealMovie realMovie = new RealMovie();//定义一个实际电影对象
Cinema cinema = new Cinema(realMovie); //创建一个InvocationHandler对象
Movie movieProxy = (Movie)Proxy.newProxyInstance(RealMovie.class.getClassLoader(),RealMovie.class.getInterfaces(),cinema);//生成代理类
movieProxy.play();//通过代理对象调用播放电影的方法
}
}
动态代理语法
Proxy
通过 Proxy 的静态方法 newProxyInstance 可以动态创建代理。
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
- loader 自然是类加载器
- interfaces 代码要用来代理的接口
- h 一个 InvocationHandler 对象
InvocationHandler
InvocationHandler 是一个接口,官方文档解释说,每个代理的实例都有一个与之关联的 InvocationHandler 实现类,如果代理的方法被调用,那么代理便会通知和转发给内部的 InvocationHandler 实现类,由它决定处理。
public interface InvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable; }
InvocationHandler 内部只是一个 invoke() 方法,正是这个方法决定了怎么样处理代理传递过来的方法调用。
- proxy 代理对象
- method 代理对象调用的方法
- args 调用的方法中的参数
因为,Proxy 动态产生的代理会调用 InvocationHandler 实现类,所以 InvocationHandler 是实际执行者。
具体实现可参考源码
代理的作用
在不修改被代理对象的源码上,进行功能的增强,这在 AOP 面向切面编程领域经常见。
在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。
AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,
从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
主要功能
日志记录,性能统计,安全控制,事务处理,异常处理等等。
总结
- 代理分为静态代理和动态代理两种。
- 静态代理,代理类需要自己编写代码写成。
- 动态代理,代理类通过 Proxy.newInstance() 方法生成。
- 不管是静态代理还是动态代理,代理与被代理者都要实现两样接口,它们的实质是面向接口编程。
- 静态代理和动态代理的区别是在于要不要开发者自己定义 Proxy 类。
- 动态代理通过 Proxy 动态生成 proxy class,但是它也指定了一个 InvocationHandler 的实现类。
- 代理模式本质上的目的是为了增强现有代码的功能。
转载来自:https://blog.csdn.net/briblue/article/details/73928350

浙公网安备 33010602011771号