其实生活中代理模式很常见,比如房产中介,明星经纪,就连追女孩都体现了代理模式。
下面引用《大话设计模式》中的一张图
上图最后一句也说明了为什么代理类和被代理类都要实现同一个接口,利用了接口可以引用不同子类的特性,从而可以在任何使用目标对象(被代理的那个)的地方使用代理对象来增强方法。
代码实例
假如现在这样一个场景,男孩(追求者)喜欢一个女孩,想送个礼物给女孩,但是男孩不好意思去,所以得找个中间人帮忙送一下。
追求者送礼物的动作接口
public interface Action {
/**
* 送女生礼物
*/
public void givePresent();
}
追求者类
/**
* 追求者类
* @author 阳光大男孩!!!
*/
public class Seeker implements Action {
@Override
public void givePresent() {
System.out.println("追求者送礼物");
}
}
中间人-代理对象类
/**
* @author 阳光大男孩!!!
* Seeker类的代理对象类
*/
public class Proxy implements Action{
Seeker seeker = null;
@Override
public void givePresent() {
if(seeker==null)
{
seeker = new Seeker();
}
seeker.givePresent();
}
}
中间人拥有追求者对象,从而可以在不修改追求者类代码的基础上增强方法。
被追求的女孩类
/**
* 被追求者类
* @author 阳光大男孩!!!
*/
public class Girl {
}
主函数测试类
/**
* @author 阳光大男孩!!!
*/
public class Main {
public static void main(String[] args) {
Proxy proxy = new Proxy();
proxy.givePresent();
}
}
执行结果
追求者送礼物
前面讲的叫做静态代理
,缺点就是,假如在项目中需要代理模式,那每增强一个对象,都要写一个代理类,所以很麻烦,下面引入一个动态代理的概念,从而能够动态的创建代理类,不需要我们自己写了。
动态代理
使用动态代理的话,需要写一个工厂类来给我们自动创建代理类。在java中,有两种方式来实现动态代理,分别是JDK方式和Cglib方式。
区别在于:JDK的Proxy方式实现的动态代理 目标对象必须有接口 没有接口不能实现jdk版动态代理
1 JDK方式
/**
* @author 阳光大男孩!!!
*/
public class ProxyFactory {
public static <T> Object getProxy(T t){
//返回一个代理对象
Object object = Proxy.newProxyInstance(t.getClass().getClassLoader(), t.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("执行"+method.getName()+"方法前...");
Object invoke = method.invoke(t, args);
System.out.println("执行"+method.getName()+"方法后...");
return invoke;
}
});
return object;
}
}
实现代理工厂类后,就不需要专门为某个对象写代理类了,其他类不变
/**
* @author 阳光大男孩!!!
*/
public class Main {
public static void main(String[] args) {
Seeker seeker = new Seeker();
Action action = (Action) ProxyFactory.getProxy(seeker);
action.givePresent();
}
}
执行结果:
执行givePresent方法前...
追求者送礼物
执行givePresent方法后...
2.CGLIB方式
使用CGLIB方式,需要引入CGLIB包,这里我选择使用maven帮我们引入,所以要将我们之前的普通项目转换为maven项目
在pom.xml中加入依赖
<dependencies>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>
</dependencies>
再进行import changes操作
如果是在spring boot 项目中使用,CGLIB包已经被集成,直接使用即可。
实现代理工厂类
/**
* @author 阳光大男孩!!!
*/
public class CglibFactory {
public static <T> Object getProxy(T t){
//帮我们生成代理对象
Enhancer en = new Enhancer();
//设置要代理的目标类
en.setSuperclass(t.getClass());
//代理要做什么
en.setCallback(new MethodInterceptor() {
public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("Cglib:执行方法前。。。");
//调用原有方法
Object invoke = methodProxy.invokeSuper(object, args);
// Object invoke = method.invoke(t,args); 作用等同与上面。
System.out.println("Cglib:执行方法后。。。");
return invoke;
}
});
//生成代理对象
Object proxyObj = en.create();
return proxyObj;
}
}
在main类中测试
/**
* @author 阳光大男孩!!!
*/
public class Main {
public static void main(String[] args) {
Seeker seeker = new Seeker();
Action action = (Action) CglibFactory.getProxy(seeker);
action.givePresent();
}
}
执行结果
Cglib:执行方法前。。。
追求者送礼物
Cglib:执行方法后。。。
总结
代理模式能够让我们在不修改类代码的情况下,对方法进行增强。
这也是spring aop 的一部分思想,更像是一种约定编程。
代理模式分为静态代理和动态代理。
动态代理模式能够动态创建代理对象,从而让我们免去创建代理类的麻烦。
参考
https://blog.csdn.net/qq_34178598/article/details/78630934#comments