Java代理模式
来源:互联网 发布:易语言砍价源码 编辑:程序博客网 时间:2024/06/03 17:44
1. 代理模式
代理是一种设计模式,提供了通过代理对象访问目标对象的方式。这样做的好处是可以在目标对象的基础上增加额外的功能,扩展目标对象的功能。
这里使用到编程中的一个思想:不要随意去修改别人已经写好的代码或者方法,如果需要修改,可以通过代理或者其他方式来扩展该方法。
举个现实中的例子来说明代理模式:假如我们需要邀请一位明星唱歌,那么我们不会直接联系明星,而是直接联系明星的经纪人,由明星的经济负责接待洽谈等琐碎的工作,而明星只需要负责唱歌就行了。
在实际开发中,我们之所以需要产生代理对象,主要是用于拦截对真实业务对象的直接访问。
所以代理模式需要明确两个概念:
1. 代理对象存在的主要价值在于拦截对真实业务对象的直接访问。
2. 代理对象必须拥有和真实业务对象一样的方法。例如前面所举的例子,经纪人必须具有和明星相同的方法,会唱歌,但是不是真的懂得唱歌,真正懂得唱歌的是明星。所以我们联系明星的经纪人,把钱交给经纪人,然后由经纪人让明星去唱歌。
所以说,代理对象是目标对象的扩展,代理对象会调用目标对象的方法。
1.1 静态代理
静态代理在使用的时候,需要定义接口或者父类,被代理对象和代理对象需要实现相同的接口或者继承相同的父类。
下面示例:
定义一个接口IStar,该接口用于模拟明星唱歌。目标对象Star实现了IStar接口,而代理对象StarProxy则同样实现了IStar,通过调用了代理对象的方法来实际调用目标对象Star的方法。
IStar源代码如下:
public interface IStar { public void sing();}
Star类代码如下:
public class Star implements IStar{ public void sing(){ System.out.println("Star is Singing!"); }}
StarProxy类源代码如下:
public class StarProxy implements IStar{ private IStar star; public StarProxy(IStar star){ this.star=star; } public void sing(){ System.out.println("Get money!"); star.sing(); System.out.println("Sing finish"); }}
静态代理总结:
1. 可以做到在不修改目标对象的前提下,对目标对象功能进行拓展;
2. 因为代理对象和目标对象需要实现同样的接口,所以一旦接口添加方法,那么目标对象和代理对象都需要进行维护;
1.2 动态代理
动态代理有如下特点:
1. 代理对象不需要实现接口;
2. 代理对象的生成,是利用JDK API动态地在内存中构建代理对象;
3. 动态代理也叫做JDK代理、接口代理;
代理类所在的包为:java.lang.reflect.Proxy;
JDK实现动态代理只需要调用newProxyInstance方法,该方法在Proxy类中的定义如下:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
由上可见,newProxyInstance方法是一个静态方法,该方法接收三个参数,参数的作用如下:
ClassLoader loader:用来指明生成代理对象应该使用哪个类加载器;
Class
public interface InvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;}
下面来讲解invoke方法中的参数:
Object proxy:被调用的方法所在的代理实例;
Method method:代理实例所引用的接口方法相应的Method实例;
Object[] args:代理实例引用方法参数作为对象对象传递,或者为null当代理实例所引用的方法没有参数时;原生类型的参数如int等将会被自动装箱为Integer等;
代码示例:
在前面静态代理中例子的基础上,增加一个代理工厂类ProxyFactory, 该类的源代码如下:
public class ProxyFactory { //维护一个目标对象 private Object target; public ProxyFactory(Object target){ this.target=target; } public Object getProxyFactory(){ return Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler(){ public Object invoke(Object proxy, Method method, Object[] args)throws Throwable{ System.out.println("Get money!"); Object returnValue=method.invoke(target, args); System.out.println("Sing finish!"); return returnValue; } } ); }}
对例子进行测试,测试类App的源代码如下:
public class App { public static void main(String args[]){ IStar star=new Star(); IStar proxy=(IStar) new ProxyFactory(star).getProxyFactory(); System.out.println(proxy.getClass()); proxy.sing(); }}
输出结果为:
总结:
代理对象不需要实现接口,但是目标对象一定要实现接口,否则不能用动态代理;
1.3 Cglib代理
在前面提到的动态代理或者静态代理中,目标对象都必须是一个实现接口的对象。但是,有时候目标对象并没有实现接口,这时候就需要采用目标对象的子类来实现代理,这种方式叫做:Cglib代理;
Cglib代理也叫做子类代理,通过在内存中构建一个目标对象的子类来扩展目标对象的功能;
Cglib是一个高性能的代理生成包,它能够在运行期动态地扩展目标对象或者实现接口,因此被许多AOP框架所使用,例如Spring AOP;为它们提供方法的拦截;
Cglib子类代理实现的方法:
1. 需要引入Cglib的jar包,但是spring的核心包已经包含了Cglib的功能,所以直接引入spring-core-xxx.jar包即可
2. 引入功能包之后,就可以在内存中动态地构建子类;
3. 代理的类不能为final类;
4. 如果目标对象的方法为final/static,那么目标对象的方法将不会被执行;
示例如下:
目标类UserDao:
public class UserDao { public void save(){ System.out.println("save data successfully!"); }}
代理类工厂ProxyFactory:
import org.springframework.cglib.proxy.Enhancer;import org.springframework.cglib.proxy.MethodInterceptor;import org.springframework.cglib.proxy.MethodProxy;import java.lang.reflect.Method;public class ProxyFactory implements MethodInterceptor{ private Object target; public ProxyFactory(Object target){ this.target=target; } public Object getProxyInstance(){ Enhancer en=new Enhancer(); en.setSuperclass(target.getClass()); en.setCallback(this); return en.create(); } public Object intercept(Object obj,Method method,Object[] args,MethodProxy proxy) throws Throwable{ System.out.println("start transaction!"); Object returnValue=method.invoke(target, args); System.out.println("submit transaction!"); return returnValue; }}
测试类App:
public class App { public static void main(String args[]){ UserDao user=new UserDao(); UserDao userP=(UserDao) new ProxyFactory(user).getProxyInstance(); userP.save(); }}
在Spring AOP编程中:
如果加入容器的目标对象实现了接口,那么采用JDK代理;
如果加入容器的目标对象没有实现接口,那么将会采用Cglib代理;
参考博文:http://www.cnblogs.com/cenyu/p/6289209.html
- Java代理之代理模式
- java代理模式---静态代理
- java代理模式--动态代理
- 代理模式&java动态代理
- JAVA代理模式--静态代理
- JAVA代理模式--动态代理
- JAVA动态代理 代理模式
- Java代理模式-静态代理
- java代理模式-动态代理
- Java代理模式 静态代理 动态代理
- JAVA代理模式与动态代理模式
- JAVA代理模式与动态代理模式
- JAVA代理模式与动态代理模式
- JAVA代理模式与动态代理模式
- JAVA代理模式与动态代理模式
- JAVA代理模式与动态代理模式
- Java代理模式和kotlin代理模式
- Java中的代理模式
- 2011年NOIP提高组 铺地毯
- [BZOJ1029][JSOI2007]建筑抢修-堆-贪心
- Java教程
- 西安网络赛 xor
- 排序算法入门学习笔记
- Java代理模式
- Unity学习之输入与控制
- Android 自定义控件 ---DecorativeListView
- maven项目开发环境搭建之一环境变量
- 理解for循环,到底循环了什么?
- Hibernate学习---第一节:hibernate配置和入门程序
- Jenkins自动化测试
- Hibernate学习---第二节:hibernate 增、删、改、查
- for循环写法进阶