代理模式,类似于中生活中的中介的角色。在程序中,比如现在有一个类A,提供了一个功能x,在使用的时候,我们引入一个A的代理角色B,当有人想用A的x的功能的时候,不直接通过A来调用,而是通过它的代理B来调用。
这种场景可能是A不能直接对外提供功能,也可能事A的功能有限,需要对其进行一些拓展,为了不改变源代码,我们就可以通过代理对它进行扩展。通常来说,我们使用代理都是为了对被代理对象进行功能的扩展,比如记录日志,或者进行一些校验。
代理分两种类型:静态代理,动态代理
两者的区别在于代理类的生成时机,静态代理的代理类实在编译阶段就生成了,代理与被代理的关系是提前就确定了的,而动态代理是在运行阶段才动态生成的。
静态代理
静态代理需要有个接口,被代理类和代理类都要实现这个接口,而且被代理类需要作为代理类的一个属性,代理类在实现接口方法的时候,对被代理类的方法进行处理或扩展。
看个简单的例子吧
接口:
public interface Factory {
public void procduce();
}
被代理类:
public class CarFactory implements Factory{
@Override
public void procduce() {
System.out.println("我要造辆车");
}
}
代理类:
public class ProxyCarFactory implements Factory{
// 被代理类作为属性
private CarFactory carFactory;
public ProxyCarFactory(CarFactory carFactory) {
this.carFactory = carFactory;
}
@Override
public void procduce() {
System.out.println("造车之前借点钱");
// 调用被代理类的方法,在它前后可以进行一些其他处理,比如加日子,校验等等
carFactory.procduce();
System.out.println("打个广告看谁买");
}
}
测试:
public class Client {
public static void main(String[] args) {
CarFactory target = new CarFactory();
// 得到代理对象
ProxyCarFactory proxyCarFactory = new ProxyCarFactory(target);
// 通过代理对象来调用方法
proxyCarFactory.procduce();
}
}
动态代理
动态代理分两种:JDK代理,cglib代理
JDK代理是基于接口实现的代理方式,被代理的对象必须实现一个接口
举个例子:
接口:
public interface Worker {
// 工作
public void work();
// 领工资
public Integer salay(String name);
}
被代理类:
public class Programmer implements Worker{
@Override
public void work() {
System.out.println("996 不用说");
}
@Override
public Integer salay(String name) {
System.out.println(name+"的工资是:666");
return 666;
}
}
生成代理对象的类:(注意这里不是必须,只是为了封装创建代理对象的方法,但是这个类本身的对象不算是代理对象)
public class ProgrammerProxy {
// 实现代理逻辑的时候需要通过代理对象调用他的方法
private Worker target;
public ProgrammerProxy(Worker target) {
this.target = target;
}
public Worker getProxyInstance(){
return (Worker) Proxy.newProxyInstance( // 这个方法最终用来生成一个代理对象
ClassLoader.getSystemClassLoader(), //类加载器,目标对象或者当前对象都可以获取
target.getClass().getInterfaces(), //被代理类实现的接口
new InvocationHandler(){ // 实现代理的逻辑
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("代理开始");
// 调用被代理对象的方法
Object object = method.invoke(target, args);
System.out.println("代理结束");
return object;
}
}
);
}
}
测试使用:
public class Client {
public static void main(String[] args) {
Worker target = new Programmer();
// 这里需要注意,这里只是得到代理类的对象,但是这个其实并不是真正的代理对象
// 注意一下两者的区别,事实上代理类的对象并不必须,甚至代理类也不是必须的,得到代理对象只通过下面的方法就可以
ProgrammerProxy proxy = new ProgrammerProxy(target);
// 这个方法才是用来得到真正的代理对象(仔细看一下这个方法,完全可以不需要代理类)
Worker workerProxy = proxy.getProxyInstance();
// 通过代理对象来调用方法
workerProxy.work();
// 调用方法的时候完全和原对象一样,传参,接受返回值
Integer zhangsansanDeGongzi = workerProxy.salay("zhangsansan");
System.out.println("工资:"+zhangsansanDeGongzi);
}
}
cglib代理:cglib代理是通过继承父类实现,也就是代理对象必须继承自被代理对象。
被代理类:
public class PlayGame {
public void play(){
System.out.println("我们一起来玩游戏啊");
}
}
生成代理对象的类:(注意这里不是必须,只是为了封装创建代理对象的方法,但是这个类本身的对象不算是代理对象)
public class PlayGameProxy {
public PlayGame getPlayGameProxy(){
Enhancer enhancer = new Enhancer(); //用来创建代理对象
enhancer.setSuperclass(PlayGame.class); //设置被代理对象的类
enhancer.setCallback(new MethodInterceptor() { // 实现代理的逻辑
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("换个衣服");
// 这里的obj就是被代理的对象
Object result = methodProxy.invokeSuper(obj, args);
System.out.println("洗洗睡吧");
return result;
}
});
Object proxy = enhancer.create(); // 得到代理对象
return (PlayGame) proxy;
}
}
测试使用:
public class Client {
public static void main(String[] args) {
PlayGameProxy proxy = new PlayGameProxy();
PlayGame playGame = proxy.getPlayGameProxy();
playGame.play();
}
}
小结一下:静态代理用到比较少,它要求代理类和被代理类都实现同一个接口,不利于功能扩展。动态代理用到比较多,最典型的大概spring中的核心功能AOP了。
通过使用动态代理我们可以发现,其实对于动态代理来说,并不一定需要我们实现一个代理类,这个例子中只是为了放创建代理对象的方法,而例子中代理类的对象并不是真正的代理对象(这个希望不要误导),可以看到,其实创建代理对象只需要调用方法就可以了。这就回到刚开始说的静态代理与动态代理的区别,动态代理的真正代理类实在程序运行时产生的,我们不能直观的看到这个类存在,直接得到具体的代理类去用就可以了。