网站首页 > java教程 正文
当一个对象不适合或者不能被其他对象直接引用时,可以给该对象生成一个代理对象。代理对象具有被代理对象的所有功能,这样其他对象使用代理对象时一样可以达到自己的需求。
静态代理
静态代理在使用时,需要定义接口或者父类,被代理对象与代理对象一起实现相同的接口或者是继承相同父类。
首先定义接口
public interface BaseDao { public void add(); }
被代理对象
public class UserDao implements BaseDao { @Override public void add() { System.out.println("add User"); } }
静态代理对象
public class UserDaoStaticProxy implements BaseDao { private UserDao userDao; public UserDaoStaticProxy() { userDao = new UserDao(); } @Override public void add() { System.out.println("执行前准备..."); userDao.add(); System.out.println("执行后处理..."); } }
使用方式
public class Run { public static void main(String[] args) { UserDaoStaticProxy userDaoStaticProxy = new UserDaoStaticProxy(); userDaoStaticProxy.add(); } }
直接使用代理对象UserDaoStaticProxy来代替UserDao来使用,因为代理对象和被代理对象有着相同的父类,所以他们有着相同的功能。
静态代理的缺点是必须为每个被代理对象生成一个代理对象,如果有几十个被代理对象的话,明显不适合用这种方式。此时我们必须使用动态代理来解决这个问题。
动态代理
动态代理有两种实现方式,一种是使用jdk自带的方式,一种是使用cglib的方式。下面我们具体演示下两种方式具体如何实现。
jdk方式实现动态代理
代理工厂类
public class DynamicProxyFactory_java { private Object object; //被代理对象 public DynamicProxyFactory_java(Object object) { this.object = object; } public Object getProxyInstance() { return Proxy.newProxyInstance( object.getClass().getClassLoader(), object.getClass().getInterfaces(),//所以这种模式必须实现接口 new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("执行前准备..."); Object invoke = method.invoke(object, args); //执行被代理对象的方法 System.out.println("执行后处理..."); return invoke; } } ); } }
在代理工厂的构造方法中我们传入需要被代理的对象,再通过调用getProxyInstance()方法即可获取代理对象,使用方式如下
public class Run { public static void main(String[] args) { BaseDao baseDao = new UserDao(); BaseDao userDao = (BaseDao) new DynamicProxyFactory_java(baseDao).getProxyInstance(); userDao.add(); System.out.println("代理前对象:" + baseDao.getClass().getName()); System.out.println("代理后对象:" + userDao.getClass().getName()); } }
执行后结果
执行前准备... add User 执行后处理... 代理前对象:proxy.UserDao 代理后对象:com.sun.proxy.$Proxy0
我们使用代理工厂,就可以生产出所有符合需求的代理对象,不需要为每个被代理对象创建一个代理对象。
但是这种动态代理不足之处在于被代理对象必须要实现一个接口。如果有一个需要被代理的对象没有实现接口,怎么办呢?往下看!
cglib动态代理
cglib动态代理并不是jdk自带的方式,因此我们必须引入第三方jar包(比如:cglib-3.0.12.jar)。
cglib动态代理工厂
public class DynamicProxyFactory_cglib implements MethodInterceptor { private Object object; //被代理对象 public DynamicProxyFactory_cglib(Object object) { this.object = object; } /** * 创建代理对象 * * @return */ public Object getProxyInstance() { //工具类 Enhancer enhancer = new Enhancer(); //设置父类 enhancer.setSuperclass(object.getClass()); //设置回调函数 enhancer.setCallback(this); //创建对象并返回 return enhancer.create(); } @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("执行前准备..."); Object invoke = method.invoke(object, args); System.out.println("执行后处理..."); return invoke; } }
假设我们有一个需要被代理的对象,但是没有实现任何的接口
//没有实现任何的接口 public class MenuDao { public void add() { System.out.println("add Menu"); } }
cglib动态代理使用方式
public class Run { public static void main(String[] args) { MenuDao dao = new MenuDao(); MenuDao menuDao = (MenuDao) new DynamicProxyFactory_cglib(dao).getProxyInstance(); System.out.println("代理前对象:" + dao.getClass().getName()); System.out.println("代理后对象:" + menuDao.getClass().getName()); menuDao.add(); } }
执行后结果如下
代理前对象:proxy.MenuDao 代理后对象:proxy.MenuDao$EnhancerByCGLIB$bbcb6715 执行前准备... add Menu 执行后处理...
Cglib代理,也叫作子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能的扩展。
既然有两种动态代理模式,那么到底使用哪种方式呢?这里我们看下springAop中是如何实现的
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable { @Override public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) { Class<?> targetClass = config.getTargetClass(); if (targetClass == null) { throw new AopConfigException("TargetSource cannot determine target class: " + "Either an interface or a target is required for proxy creation."); } if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) { return new JdkDynamicAopProxy(config); } return new ObjenesisCglibAopProxy(config); } else { return new JdkDynamicAopProxy(config); } } }
上述代码中,我们只需要关注判断条件:targetClass.isInterface(),看方法名字就知道判断这个类是不是接口。如果是接口,那么就使用jdk动态代理来实现,否则就使用Cglib动态代理来实现。
Java肖先生:专注于Java开发技术的研究与知识分享!
————END————
- 点赞(感谢)
- ...
- 转发(感谢)
- ...
- 关注(感谢)
- ...
猜你喜欢
- 2024-10-24 Java动态代理与静态代理以及它能为我们做什么
- 2024-10-24 Java 设计模式 之 代理模式 (1)(java设计模式之代理模式)
- 2024-10-24 Java设计模式:代理模式 vs. 装饰模式
- 2024-10-24 设计模式篇——代理模式详解(面试再问你代理模式,这么回答他)
- 2024-10-24 动态代理大揭秘,带你彻底弄清楚动态代理
- 2024-10-24 面试:Java的代理模式动态代理和静态代理区别,aop用的什么代理
- 2024-10-24 Java设计模式之代理模式(java代理类是什么)
- 2024-10-24 JAVA设计模式——代理模式(java编写代理服务)
- 2024-10-24 23种java设计模式之:门面模式、享元模式、代理模式
- 2024-10-24 Java 17中的动态代理:实现灵活的代理模式
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)