我们知道代理模式分为静态代理和动态代理,静态代理的实现有使用继承实现、使用组合实现;动态代理实现有jdk动态代理、cglib动态代理。
下面我们研究一下Java里面的代理模式的具体实现,我们为什么使用代理模式?代理模式的好处有哪些?
1.静态代理-继承实现
package test;
public class ProxyExtend {
public void run(){
System.out.println("开始执行一个任务...");
}
public static void main(String[] args) {
ExtendMethod e = new ExtendMethod();
e.run();
}
}
class ExtendMethod extends ProxyExtend{
@Override
public void run() {
System.out.println("方法之前执行...");
super.run();
System.out.println("方法之后执行...");
}
}
执行结果:
方法之前执行...
开始执行一个任务...
方法之后执行...
这个静态代理是我们经常见到的一个实现,他是将父类方法进行增强,缺点是只能代理这个类,想要代理别的类需要新的代理方法(cglib动态代理底层)
2.静态代理-通过组合实现
package test;
public class ProxyModel implements Proxy {
@Override
public void tank() {
System.out.println("proxyModel 代理。。。");
}
public static void main(String[] args) {
ProxyModel proxyModel = new ProxyModel();
proxyModel.tank();
MethodProxyFactory m = new MethodProxyFactory(proxyModel);
m.tank();
}
}
class MethodProxyFactory implements Proxy {
private Proxy p;
public MethodProxyFactory(Proxy p){
this.p = p;
}
@Override
public void tank() {
System.out.println("MethodProxy 代理开始");
p.tank();
System.out.println("MethodProxy 代理结束");
}
}
interface Proxy {
void tank();
}
使用这种代理模式的好处是通过一个代理工厂,只要实现了这个接口的都可以进行代理,缺点是被代理的类必须实现接口(jdk动态代理实现底层)
3.动态代理-JDK动态代理
package test;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JdkProxy implements ProxyV2{
@Override
public void run() {
System.out.println("实现了proxyv2的方法---->");
}
public static void main(String[] args) {
JdkProxy jdkProxy = new JdkProxy();
//newProxyInstance: 创建代理对象
// 参数一: 被代理类对象
// 参数二:接口类对象 被代理对象所实现的接口
// 参数三:调用处理器。 被调用对象的那个方法被调用后该如何处理
ProxyV2 o = (ProxyV2)Proxy.newProxyInstance(JdkProxy.class.getClassLoader(),
new Class[]{ProxyV2.class},
new JdkProxyFactory(jdkProxy));
o.run();
}
}
class JdkProxyFactory implements InvocationHandler{
private final ProxyV2 proxyV2;
public JdkProxyFactory(ProxyV2 proxyV2){
this.proxyV2 = proxyV2;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("方法:"+method.getName()+"()执行前");
Object invoke = method.invoke(proxyV2, args);
System.out.println("方法:"+method.getName()+"()执行后");
return invoke;
}
}
interface ProxyV2{
void run();
}
jdk代理模式必须面向接口实现,可以生成所有实现接口的代理对象
4.动态代理-cglib动态代理
package test;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CglibProxy {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Tank.class);
enhancer.setCallback(new TimeMethodIntercept());
Tank tank = (Tank)enhancer.create();
tank.move();
}
}
class TimeMethodIntercept implements MethodInterceptor{
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("生成的类名"+o.getClass().getName());
System.out.println("生成的类的父类"+o.getClass().getSuperclass().getName());
System.out.println("方法执行前,被代理的方法"+method.getName());
Object result = null;
result = methodProxy.invokeSuper(o, objects);
System.out.println("方法执行后,被代理的方法"+method.getName());
return result;
}
}
class Tank{
public void move(){
System.out.println("Tank moving clacla....");
}
}
CGLib(Code Generate Library) 与JDK动态代理不同的是,cglib生成代理是被代理对象的子类。因此它拥有继承方法实现静态代理的优点:不需要被代理对象实现某个接口。
5.整理
代理模式这个概念比较好理解,就拿房屋中介来理解,房东委托中介将房子出租。这里,中介就可以视为一个代理,代理房东来出租房子,并在房东租房的基础上提供一个信息渠道的功能。由此,可以看出,代理作用就是在原来功能的基础上进行一个服务增强。