代理是一种常用的设计模式,其目的是为其他对象提供一种代理以控制(外部对象)对这个被被代理对象的的访问。由代理类负责为委托类(即被代理类)对象做一些用户处理的操作(如权限限制)或执行完之后的后续操作。
代理模式的特征是:代理类与委托类(即被代理类)有同样的接口,代理类主要负责为委托类(即被代理类)预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。
线面我们来看一下代理模式的类图:
我们这里主要学习以下动态代理模式,动态代理是在运行时,运用反射机制动态创建代理类。
常用的动态代理分为JDK动态代理和CGLIB动态代理。对于这两种动态代理,
JDK的动态代理需要依靠接口实现,如果有些类并没有实现接口,则不能使用JDK动态代理;而CGLIB是针对类来实现代理的,其原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,故不能对final修饰的类进行代理。
就我们熟知的Spring框架中的AOP默认就是使用JDK动态代理的,如果想强制使用CGLIB实现代理,那就需要添加CGLIB库,并在Spring配置中加入:
<aop:aspectj-autoproxy proxy-target-class="true"/>
就性能而言,CGLIB动态代理要较JDK的K动态代理高一些。
JDK动态代理
在JDK的动态代理中,除了要实现的接口外,外特别关注java.lang.reflect包下的一个类Proxy和动态代理要实现的接口InvocationHandler。
Proxy是Java动态代理的主类,它提供了一些静态方法,用于为一组儿接口动态地生成代理类及其对象:
//获取指定的代理对象关联的调用处理器
static InvocationHandler getInvocationHandler(Object proxy)
//获取关联于指定类加载器和一组儿接口的动态代理类的对象
static Class getProxyClass(ClassLoader loader,Class[] interfaces)
//判断指定的类是否是一个动态代理类
static boolan isProxyClass(Class cl)
/**
* 非常重要的接口:用于为指定的类加载器、一组儿接口和嗲用处理器生成
* 动态代理累的实例
*/
static Object newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h)
再来看一下InvocationHandler接口,它主要定义了一个invoke方法,用于处理动态代理类对象上的方法调用。通常开发者需要实现该接口并在其方法内实现对委托类(被代理类)对象的代理访问:
/**
* 该方法负责处理动态代理类上的方法调用。
* @Param proxy: 代理类的实例
* @Param method: 被调用的方法对象
* @Param args: 调用参数
*/
Object invoke(Object proxy,Method method,Object[] args)
具体代码如下:
package org.pattern;
/**
* 卖货接口
* @author Jacky.Chen
*
*/
public interface ISell {
/**
* 卖货
*/
void sell();
}
package org.pattern;
/**
* 销售商,实现了ISell接口
* @author JackyChen
*
*/
public class Vendor implements ISell{
@Override
public void sell(){
System.out.println("今天,俺又卖了一件货品!");
}
}
package org.pattern;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* 销售商代理,比如说淘宝上的一个代理商,现有该代理商
* 在网上接到客户的订单,然后他(她)再向销售商Vendor
* 下单赚区差价
* @author JackyChen
*
*/
public class VendorProxyHandler implements InvocationHandler {
private Object objOriginal;
public VendorProxyHandler(Object obj){
this.objOriginal = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//可以在这里添加一些预处理操作,如权限控制等...
Object result = method.invoke(this.objOriginal, args);
//也可以在此处添加一些后置处理操作...
return result;
}
}
package org.pattern;
import java.lang.reflect.Proxy;
public class JDKDynamicProxyExample{
public static void main(String[] args){
//创建销售商
Vendor vendor = new Vendor();
//创建动态代理的处理器
VendorProxyHandler handler = new VendorProxyHandler(vendor);
//创建动态代理类
ISell proxyObj = (ISell) Proxy.newProxyInstance(vendor.getClass().getClassLoader(),
Vendor.class.getInterfaces(), handler);
//卖货
proxyObj.sell();
}
}
CGLIB动态代理
CGLib采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。
下面我们来看一下CGLIB动态代理中涉及的几个类:
net.sf.cglib.proxy.Enhancer – 主要的增强类
net.sf.cglib.proxy.MethodInterceptor – 主要的方法拦截类,它是Callback接口的子接口,需要用户实现
net.sf.cglib.proxy.MethodProxy – JDK的java.lang.reflect.Method类的代理类,可以方便的实现对源对象方法的调用,如使用:
Object o = methodProxy.invokeSuper(proxy, args);
我们在这里简单举例,首先要有一个被代理的类,该类不能是final类:
package org.pattern;
/**
* 需要被代理的类(也就是父类),通过字节码技术创建这个类的子类,实现动态代理
* @author JackyChen
*
*/
public class CglibVendor {
public void sell(){
System.out.println("今天,俺又卖了一件货品!");
}
}
接下来我们来实现代理类:
package org.pattern;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/**
* Cglib代理类
* @author JackyChen
*
*/
public class CglibVendorProxy implements MethodInterceptor{
private Enhancer enhancer = new Enhancer();
public Object getProxy(Class clazz){
/设置需要创建子类的类
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
//通过字节码技术动态创建子类实例
return enhancer.create();
}
/**
* 拦截所有目标类方法的调用
* @param obj: 目标类的实例
* @param method: 目标类方法的反射对象
* @param args: 方法的动态入参
* @param proxy: 代理类实例
*/
@Override
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
//可以在这里添加一些预处理操作,如权限控制等...
//通过代理类调用父类中的方法
Object result = proxy.invokeSuper(obj, args);
//也可以在此处添加一些后置处理操作...
return result;
}
}
调用Cglib动态代理的示例:
package org.pattern;
public class CglibDynamicProxyExample {
public static void main(String[] args){
CglibVendorProxy proxy = new CglibVendorProxy();
//通过生成子类的方式创建代理类
CglibVendor proxyImp = (CglibVendor)proxy.getProxy(CglibVendor.class);
proxyImp.sell();
}
}
从上面的代码量上来看,Cglib动态代理要少很多,并且代码较为清晰而干净。在性能上:
CGLib创建的动态代理对象性能比JDK创建的动态代理对象的性能高不少,但是CGLib在创建代理对象时所花费的时间却比JDK多得多,所以对于单例的对象,因为无需频繁创建对象,用CGLib合适,反之,使用JDK方式要更为合适一些。
- 大小: 55 KB
分享到:
相关推荐
java 代理模式实现代码及设计详解:动态代理模式、静态代理模式
“[设计模式]在实用环境下特别有用,因为它分类描述了一组设计良好,表达清楚的面向对象软件设计模式。整个设计模式领域还很新,本书的四位作者也许已占据了这个领域造诣最深的专家中的半数,因而他们定义模式的方法...
Java设计模式——代理设计模式(静态代理和动态代理) 各种情况例子源码
动态代理设计模式 日志和源码 动态代理设计模式 日志和源码
此资源为文章中《代理设计模式:静态代理和动态代理的理解、实现与区别(优缺点)》与《 AOP动态代理声明式的3种配置方式过程与区别》的案例代码,可下载参考学习。
详细而又简单的讲述了java动态代理设计模式
动态代理设计模式详解.pdf动态代理设计模式详解.pdf动态代理设计模式详解.pdf动态代理设计模式详解.pdf动态代理设计模式详解.pdf动态代理设计模式详解.pdf
动态代理设计模式-源码
Java设计模式之代理模式(结构)Java设计模式之代理模式(结构)Java设计模式之代理模式(结构)Java设计模式之代理模式(结构)Java设计模式之代理模式(结构)
设计模式之Proxy(代理) 设计模式之Adapter(适配器) 设计模式之Composite(组合) 设计模式之Decorator(油漆工) 设计模式之Bridge 设计模式之Flyweight(享元) 行为模式: 设计模式之Template 设计模式之Memento(备忘机制...
设计模式之代理模式 学习
JAVA设计模式之代理模式实例
8 代理模式 9 装饰模式 10 原型模式 11 委派模式 12 适配器模式 设计模式综合运用 1 门面+模版方法+责任链+策略 2 门面+模版方法+责任链+策略+工厂方法 3 动态代理+Spring AOP 4 责任链模式进阶 Spring Framework...
设计模式--代理模式设计模式--代理模式设计模式--代理模式设计模式--代理模式设计模式--代理模式
设计模式:简单工厂、方法工厂、抽象工厂、单例、原型、委派、模板、代理、策略
.net实现设计模式之代理模式
设计模式 代理模式 c#
java模式设计-代理模式之动态代理.ppt
设计模式主要分为三大类: 1.创建型模式:工厂模式、抽象工厂模式、单例模式、建造者模式、原型模式。 2.结构型模式:适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式。 4.行为型模式:...