代理模式 – 动态代理
目录
动态代理
在代理模式中,使用的是静态代理的方式,那如何进行动态代理?
动态代理是什么?
在程序运行时由Java反射机制动态生成。
如何实现呢?
在Java中要想实现动态代理机制,需要java.lang.reflect.InvocationHandler接口和 java.lang.reflect.Proxy 类的支持
例子-常规
代码:
问候 Greet
public interface Greet {
void say(String name);
}
问候实现 GreetIml
public class GreetImpl implements Greet {
@Override
public void say(String name) {
System.out.println("Hi! " + name);
}
}
商店 Shop
public interface Shop {
void sell(String wares);
}
商店实现 ShopImpl
public class ShopImpl implements Shop {
@Override
public void sell(String foodName) {
System.out.println("sell the " + foodName);
}
}
动态代理 DynamicProxy
public class DynamicProxy implements InvocationHandler {
private Object target;
public DynamicProxy(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
Object result = method.invoke(target, args);
after();
return result;
}
private void before() {
System.out.println("Before");
}
private void after() {
System.out.println("After");
}
}
在动态代理类中,实现InvocationHandler的接口,调用 method.invoke(target, args)
测试:
public class ProxyDynamicTest {
public static void main(String[] args) {
System.out.println("========== greet proxy ==========");
Greet greet = new GreetImpl();
DynamicProxy dynamicProxy = new DynamicProxy(greet);
Greet greetProxy = (Greet) Proxy.newProxyInstance(greet.getClass().getClassLoader(),
greet.getClass().getInterfaces(), dynamicProxy);
greetProxy.say("lang");
System.out.println("========== shop proxy ==========");
Shop shop = new ShopImpl();
dynamicProxy = new DynamicProxy(shop);
Shop shopProxy = (Shop) Proxy.newProxyInstance(shop.getClass().getClassLoader(),
shop.getClass().getInterfaces(), dynamicProxy);
shopProxy.sell("coffe");
}
}
结果:
========== greet proxy ==========
Before
Hi! lang
After
========== shop proxy ==========
Before
sell the coffe
After
分析
在实现中,每次要Proxy.newProxyInstance(greet.getClass().getClassLoader(), greet.getClass().getInterfaces(), dynamicProxy); 不同的类都要那样处理,略显麻烦,可以进行优化下。该如何做的?
例子-优化
代码:
动态代理 ProxyDynamicSingle
public class ProxyDynamicSingle implements InvocationHandler {
private Object target;
public ProxyDynamicSingle(Object target) {
this.target = target;
}
public <T> T getProxy() {
return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
Object result = method.invoke(target, args);
after();
return result;
}
private void before() {
System.out.println("Before");
}
private void after() {
System.out.println("After");
}
}
使用getProxy()的方式获取到代理类,在调动的时候就不用一一那个处理
测试:,
public class ProxyDynamicSingleTest {
public static void main(String[] args) {
System.out.println("========== greet proxy ==========");
ProxyDynamicSingle proxyDynamicSingle = new ProxyDynamicSingle(new GreetImpl());
Greet greetProxy = proxyDynamicSingle.getProxy();
greetProxy.say("yan");
System.out.println("========== shop proxy ==========");
proxyDynamicSingle = new ProxyDynamicSingle(new ShopImpl());
Shop shop = proxyDynamicSingle.getProxy();
shop.sell("milk");
}
}
结果:
========== greet proxy ==========
Before
Hi! yan
After
========== shop proxy ==========
Before
sell the milk
After
分析
这样实现起来就简单多了。为什么代理类中有before,after的方法呢?联想到什么?spring的AOP实现,AOP的实现原理是基于动态代理。
总结:
动态代理对象不需要实现目标对象接口,但是目标对象一定要实现接口,否则不能使用动态代理,需要使用cglib代理。动态代理的应用使我们的类职责更加单一,复用性更强。
动态代理和cgli代理进行比较:
1,对象不同:
Java动态代理只能够对接口进行代理,不能对普通的类进行代理(因为所有生成的代理类的父类为Proxy,Java类继承机制不允许多重继承);
CGLIB能够代理普通类;
2,实现方式不同:
Java动态代理使用Java原生的反射API进行操作,在生成类上比较高效;
CGLIB使用ASM框架直接对字节码进行操作,在类的执行过程中比较高效