所谓代理设计模式,简单的是说,就是不改变源代码的情况下,对目标对象进行功能扩展
静态代理
下面以一个简单的案例说明:
需求:有个歌手对象Singer,该对象有个唱歌方法sing(),用代理设计模式实现唱歌前后向观众问好和致谢(功能扩展)
步骤:定义SingerImp接口;定义Singer类,并实现SingerImp接口;定义ProxySinger类,并实现SingerImp接口。
public interface SingerImp {
void sing();
}
public class Singer implements SingerImp {
@Override
public void sing() {
System.out.println("唱一首歌");
}
}
public class SingerProxy implements SingerImp {
private Singer target;
public SingerProxy(Singer target) {
this.target = target;
}
@Override
public void sing() {
System.out.println("向观众问好");
target.sing();
System.out.println("谢谢大家");
}
}
测试类
class SingerProxyTest {
public static void main(String[] args) {
Singer singer = new Singer();
SingerProxy singerProxy = new SingerProxy(singer);
singerProxy.sing();
}
}
总结:这种实现方式很直观也很简单,但是缺点是代理对象必须提前写出。如果接口层发生了变化,代理对象的代码也要进行维护。
动态代理
定义一个接口,JDk自动给这个接口生成一个实现类,在这个实现类中,方法的执行逻辑是java.lang.reflect.InvocationHandler # invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[]),关于这三个参数的说明,请看注解。
public interface SingerImp {
void sing();
}
public class Singer implements SingerImp {
@Override
public void sing() {
System.out.println("唱一首歌");
}
}
测试类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
class SingerTest {
public static void main(String[] args) {
Singer singer = new Singer();
//当前目标对象使用的类加载器
ClassLoader loader = singer.getClass().getClassLoader();
//目标对象实现的接口类型
Class<?>[] interfaces = singer.getClass().getInterfaces();
//功能扩展,核心部分
InvocationHandler handler = new InvocationHandler() {
/**
* @param o 代理对象本身
* @param method 被代理对象的所有方法,对于目前这个案例来说,就是sing()
* @param objects 方法的参数
* @return JDk自动生成的实现类
*/
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
System.out.println("向观众问好");
Object invoke = method.invoke(singer, objects);
System.out.println("谢谢大家");
return invoke;
}
};
SingerImp singerImp = (SingerImp) Proxy.newProxyInstance(loader, interfaces, handler);
singerImp.sing();
}
}
总结:静态代理和动态代理都需要定义一个接口
Cglib代理
前提条件:
- 需要引入cglib和asmjar文件,如果你创建的是maven工程,则添加cglib依赖即可 proxyjar.zip-Java文档类资源-CSDN文库
https://download.csdn.net/download/m0_66918076/85197918
- 目标类不能为final
- 目标对象的方法如果为final/static,那么就不会被拦截,即不会执行目标对象扩展功能
步骤:定义Singer类;定义代理 工厂类ProxyFactory;测试
public class Singer {
public void sing() {
System.out.println("唱一首歌");
}
}
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 ProxyFactory implements MethodInterceptor {
//目标对象
private Object singer;
public ProxyFactory(Object singer) {
this.singer = singer;
}
//给目标对象创建一个代理对象
public Object getProxyInstance() {
//工具类
Enhancer enhancer = new Enhancer();
//设置父类
enhancer.setSuperclass(singer.getClass());
//设置回调函数
enhancer.setCallback(this);
//创建代理对象
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("向观众问好");
Object invoke = method.invoke(singer, objects);
System.out.println("谢谢大家");
return invoke;
}
}
测试类
public class Test01 {
public static void main(String[] args) {
//目标对象
Singer singer = new Singer();
//代理对象
Singer proxy = (Singer) new ProxyFactory(singer).getProxyInstance();
//执行代理对象的方法
proxy.sing();
}
}
总结:
JDK动态代理:(优势)官方提供的,剋直接使用,不需要添加依赖,效率高;(劣势)只支持有接口的类;
CGLIB动态代理:(优势)无论类是否有接口,都支持通过cglib创建代理对象;(劣势)第三方的工具,使用时需要添加第三方依赖,效率低。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/14616.html