代理模式含义
即通过一个代理对象来扩展目标对象,实现在不改变目标对象的基础上,为目标对象添加新的功能。同时,还防止了修改原有代码造成的不必要的bug。
假如我们现在有一个接口(MyInterface)
public interface MyInterface {
void doSomeThing();
void saySomeThing();
String eatSomeThing();
String buy(String something);
}
和他的一个实现类(MyInterfaceImpl)
public class MyInterfaceImpl implements MyInterface {
@Override
public void doSomeThing() {
System.out.println("做了XXXXXX事");
}
@Override
public void saySomeThing() {
System.out.println("说了========话");
}
@Override
public String eatSomeThing() {
return "吃了好多东西";
}
@Override
public String buy(String something) {
return "买了"+something;
}
}
静态代理
我们先做一个静态代理实现,所谓静态代理就是使代理实现要代理的接口,并在内部定义一个私有的接口变量,使必须要实现的方法,再添加了代理逻辑之后,继续调用接口的真实实现的一种方式。说起来可能表达不清。直接看代码吧。
静态代理类(Proxy)
注意这个的Proxy类不是JDK提供的,是我自己写的只不过命名相同。下面会说到JDK自带的Proxy类进行动态代理。
import com.wm.demo.proxy.interfaces.MyInterface;
/**
* 静态代理
* 代理优点:再不更改原方法的情况下,对功能进行扩展。
* 静态代理缺点:随着接口功能的增加,代理类也需要维护。
* @ClassName: com.wm.demo.proxy.staticproxy.Proxy
* @author: wm
* @date: 2019年2月12日 上午9:09:48
* @version : 1.0
*/
public class Proxy implements MyInterface {
private MyInterface myInterface;
private Proxy(MyInterface myInterface) {
this.myInterface = myInterface;
}
public static Proxy instance(MyInterface myInterface) {
return new Proxy(myInterface);
}
@Override
public void doSomeThing() {
System.out.println("====proxy代理doSomeThing前");
myInterface.doSomeThing();
}
@Override
public void saySomeThing() {
System.out.println("proxy代理saySomeThing前====");
myInterface.doSomeThing();
}
@Override
public String eatSomeThing() {
System.out.println("proxy代理:吃饭前洗手");
return myInterface.eatSomeThing();
}
@Override
public String buy(String something) {
System.out.println("proxy代理:先挣钱");
return myInterface.buy(something);
}
}
我们让Proxy类实现了我们上面的MyInterface接口,并且实现了他的4个方法。再Proxy中又定义了一个私有的MyInterface变量,并且通过构造器注入。
然后实现的4个方法就是我们代理模式实现代理功能的地方。
然后我们编写一个测试类:
import com.wm.demo.proxy.interfaces.MyInterface;
import com.wm.demo.proxy.interfaces.impl.MyInterfaceImpl;
public class TestStaticProxy {
public static void main(String[] args) {
MyInterface mi = Proxy.instance(new MyInterfaceImpl());
mi.doSomeThing();
mi.saySomeThing();
String eatSomeThing = mi.eatSomeThing();
System.out.println(eatSomeThing);
String buy = mi.buy("球鞋");
System.out.println(buy);
}
}
测试结果:
====proxy代理doSomeThing前
做了XXXXXX事
proxy代理saySomeThing前====
做了XXXXXX事
proxy代理:吃饭前洗手
吃了好多东西
proxy代理:先挣钱
买了球鞋
这样一来就一目了然了。通过proxy实现了对myinterface的功能扩展还没有动到他实现中的代码。符合我们的设计模式。但是有一个问题就是静态代理因为要实现被代理的接口,所以如果该接口增加了新的功能。整个静态代理都要跟着变更。这不是我们希望的。其实JDK已经帮我们想好了。
JDK动态代理
我们的接口和接口实现还是上面的类保持不变。
我们下面写一个JDK的动态代理工厂。
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 动态代理工厂
* @ClassName: com.wm.demo.proxy.dynamicproxy.ProxyFactory
* @author: wm
* @date: 2019年2月12日 上午9:16:02
* @version : 1.0
*/
public class ProxyFactory<T> {
private T target;
public ProxyFactory(T target) {
this.target = target;
}
public Object getProxyInstance() {
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), (Object proxy, Method method, Object[] args)->{
System.out.println("==========JDK动态代理==========前");
Object invoke = method.invoke(target, args);
System.out.println("==========JDK动态代理==========后");
return invoke;
});
}
}
我们给类一个成员变量,并且使用了泛型注入,进行类型校验。
然后我们写一个方法,方法内调用JDK的动态代理类Proxy,我们看一下这个类
他一共只暴露了4个方法:
从名字上来看,只有newProxyInstance是构建代理的。
看一下这个方法的参数列表
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
第一个是要代理的对象的类加载器。
第二个是要代理的对象的接口类型数组。
第三个是调用程序,就是说我们的代理功能在这实现。
再看一下InvocationHandler接口,内部,只有一个抽象方法等待实现:
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
我们可以使用lambda进行书写。
调用method的invoke方法,使用它的类加载器,并传入的他参数列表,执行该方法。并返回值。
然后我们写一个测试类:
import com.wm.demo.proxy.interfaces.MyInterface;
import com.wm.demo.proxy.interfaces.impl.MyInterfaceImpl;
public class TestProxyFactory {
public static void main(String[] args) {
ProxyFactory<MyInterface> pf = new ProxyFactory<MyInterface>(new MyInterfaceImpl());
MyInterface proxyInstance = (MyInterface)pf.getProxyInstance();
proxyInstance.doSomeThing();
proxyInstance.saySomeThing();
String eatSomeThing = proxyInstance.eatSomeThing();
System.out.println(eatSomeThing);
String buy = proxyInstance.buy("电脑");
System.out.println(buy);
}
}
输入结果:
==========JDK动态代理==========前
做了XXXXXX事
==========JDK动态代理==========后
==========JDK动态代理==========前
说了========话
==========JDK动态代理==========后
==========JDK动态代理==========前
==========JDK动态代理==========后
吃了好多东西
==========JDK动态代理==========前
==========JDK动态代理==========后
买了电脑
这样我们就实现了JDK的动态代理。没有实现接口,当接口出现变更时我们的代理工厂也无需变更。
但总有一些情况,我们要代理的目标并没有实现任何接口。那么该如何进行代理呢
CGLIB代理
当我们的目标没有实现任何接口的时候,我们无法使用JDK动态代理,那么可以使用cglib进行代理。
public class MyClass {
public void doSomeThing(String msg) {
System.out.println("myclass做了"+msg);
}
}
import java.lang.reflect.Method;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
public class CglibProxyFactory<T> implements MethodInterceptor {
private T target;
private CglibProxyFactory(T target){
this.target = target;
}
public static <T> CglibProxyFactory<T> instance(T target){
return new CglibProxyFactory<>(target);
}
//给目标对象创建一个代理对象
@SuppressWarnings("unchecked")
public T getProxy(){
//1.工具类
Enhancer en = new Enhancer();
//2.设置父类
en.setSuperclass(target.getClass());
//3.设置回调函数
en.setCallback(this);
//4.创建子类(代理对象)
return (T) en.create();
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy mp) throws Throwable {
System.out.println("==========cglib代理前");
Object invoke = method.invoke(target, args);
System.out.println("cglib代理后==========");
return invoke;
}
}
测试类
public class TestCglib {
public static void main(String[] args) {
MyClass m = CglibProxyFactory.instance(new MyClass()).getProxy();
m.doSomeThing("打篮球");
}
}
==========cglib代理前
myclass做了打篮球
cglib代理后==========