**
JAVA动态代理【理解分析】
**
- 动态代理模式,讲到这里之前必须先讲讲代理模式。java的设计模式的设计思想都来源于生活,代理模式也不例外,用通俗的语言来讲,比如:我们去交电费,交水费,我们没有时间或者实际的水费公司,电费公司太远,或者网点太少,这时候,我们会考虑引入代理商,代理商的职责就是代替我们实际的客户,去代理客户拿着客户的钱,去充值到水费公司,电费公司。这样的一种解决实际问题的设计思想。
采用专业的术语来描述呢,就是我们参考这样的一个设计图:
实际的委托类提供实际的操作实现,也就是提供钱。代理类即代理商,电费公司通过代理商获取到客户的钱,这样就实现了代理商代理缴费的业务设计。
举例:比亚迪代工苹果手机芯片生产(当然不是特别贴切)
代码示例:
/****
*
- 手机接口
*/
public interface IMobile {
/**
* 芯片配件
* @param number
* @return
*/
public boolean chip(int number);
}
public class AppleMobile implements IMobile {
/**
* 芯片设计
* @param number
* @return
*/
public boolean chip(int number) {
System.out.println("芯片代工数量:"+number);
return false;
}
}
/**
* BYD代理手机组装,代理人
*/
public class BYDProxy implements IMobile {
//实际手机厂商-被代理人
private static AppleMobile appleMobile;
public BYDProxy(AppleMobile appleMobile){
this.appleMobile = appleMobile;
}
//代理人调用实际厂商的芯片
public boolean chip(int number) {
return appleMobile.chip(number);
}
}
/**
*
* 代理模式测试-静态代理
*/
public class ProxyTest {
public static void main(String[] args) {
//苹果手机芯片实际设计
AppleMobile appleMobile = new AppleMobile();
//BYD进行苹果芯片设计的代理
BYDProxy proxy = new BYDProxy(appleMobile);
//芯片生产,这里代理传入对象必须是苹果手机,也就是代理商只做苹果手机的芯片
proxy.chip(10);
}
}
BYDProxy代理商,通过代理实例化苹果手机对象,进行芯片代工
处理结果:
芯片代工数量:10
- 缺点:
- 该实现也叫静态代理,即每个代理商都是固定的代理一种具体的业务代理,这样不能实现委托类的变化。
- 该实现也带来,只能做委托人的固定方法,不能做其他的业务增值或者副业,导致能力相对固定。
- 静态代理,在程序实例化的时候,对象其实就已经创建了,没有实现延迟加载或者叫动态的加载。
这时候就需要动态代理
**
动态代理
**
动态代理是在程序运行时通过反射机制动态创建的。我们只需要写一个代理类,具体的不同委托人,我们可以实现动态的创建,这样我们就可以实现一个代理商代理多种委托业务的这个能力,同时可以做到能力的增强,实现一些委托业务的处理前加强功能,处理后加强功能。
具体实现方式有2种,JDK原生的动态代理,即invocationHandler对象的实现。第二种为CGlib的动态代理,CGlib是基于net.sf.cglib.proxy包API的开源第三方实现API方式。CGlib相对于JDK原生的动态代理方式呢,JDK原生动态代理对于是实现了接口的对象,可以实现很好的动态实例化,但是对于没有实现接口的对象,如果要实现动态代理,就必须采用CGLib的方式更好一些。
- JDK动态代理
/**
*
* JDK原生动态代理实现,必须实现InvocationHandler,实现方法invoke,在方法内可以实现代码的方法增强
* @param <T>
*/
public class JDKDynamicProxy<T> implements InvocationHandler {
T target;
public JDKDynamicProxy(T target){
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//实际方法执行前可以做预处理
System.out.println("代理执行" +method.getName() + "方法");
//代理过程中插入监测方法,计算该方法耗时
Long start = System.currentTimeMillis();
Object result = method.invoke(target, args);
Long end = System.currentTimeMillis();
//实际方法执行后可以做后续处理
System.out.println("代理执行方法时间:" + (end-start) + "");
return result;
}
}
/**
* JDK 原生的动态代理 测试
*/
public class JdkDynamicProxyTest {
public static void main(String[] args) {
//创建苹果手机对象,该对象为实际的对象
AppleMobile appleMobile = new AppleMobile();
//创建小米手机对象,该对象为实际的对象
XiaomiMobile xiaomiMobile = new XiaomiMobile();
//创建与实际类关联的handler代理类,这里代理商可以生产多种手机的芯片
InvocationHandler proxy = new JDKDynamicProxy<IMobile>(appleMobile);
InvocationHandler xiaomiProxy = new JDKDynamicProxy<IMobile>(xiaomiMobile);
//创建一个代理对象来代理appMobile类,代理对象的每个执行方法都会替换invoke方法
IMobile mobile = (IMobile) Proxy.newProxyInstance(IMobile.class.getClassLoader(),new Class<?>[]{IMobile.class},proxy);
IMobile xmMobile = (IMobile) Proxy.newProxyInstance(IMobile.class.getClassLoader(),new Class<?>[]{IMobile.class},xiaomiProxy);
//动态代理执行芯片
mobile.chip(10);
//代理小米手机芯片生产
xmMobile.chip(30);
}
}
- CGLib动态代理
引入cglib的第三方库:
<dependencies>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>
</dependencies>
/****
*
* CGlib动态代理实现方式
* CGlib为第三方动态代理API,必须实现MethodInterceptor
*/
public class CglibDynamicProxy<T> implements MethodInterceptor {
public Object getInstance(Class<T> clazz){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("代码增强,CGlib动态代理执行前.....");
return methodProxy.invokeSuper(o,objects);
}
}
/**
* CGlib的动态代理 测试
*/
public class CGlibDynamicProxyTest {
public static void main(String[] args) {
//创建苹果手机对象,该对象为实际的对象
AppleMobile appleMobile = new AppleMobile();
//创建小米手机对象,该对象为实际的对象
XiaomiMobile xiaomiMobile = new XiaomiMobile();
CglibDynamicProxy proxy = new CglibDynamicProxy();
IMobile appMobile = (IMobile) proxy.getInstance(appleMobile.getClass());
IMobile xiaoMobile = (IMobile) proxy.getInstance(xiaomiMobile.getClass());
appMobile.chip(100);
xiaoMobile.chip(50);
}
}