静态代理设计与动态代理设计
静态代理设计模式
代理设计模式最本质的特质:一个真实业务主题只完成核心操作,而所有与之辅助的功能都由代理类来完成。
例如,在进行数据库更新的过程之中,事务处理必须起作用,所以此时就可以编写代理设计模式来完成。
范例:结合传统的代理设计模式以及以购物车CartDao为例来编写代理设计模式
package so.strong.mall.proxy; import java.util.List; public interface CartDao {boolean insert(Cart cart) throws Exception;List<Cart> findAll() throws Exception; }
以上CartDao接口定义的方法,更行插入一定需要事务控制,对于查询操作,不需要事务控制。
定义CartDao真实实现
package so.strong.mall.proxy; import java.util.List; public class CartDAOImpl implements CartDao{@Overridepublic boolean insert(Cart cart) throws Exception {System.out.println("=====执行数据增加操作=====");return false;}@Overridepublic List<Cart> findAll() throws Exception {System.out.println("=====执行数据列表操作=====");return null;} }
定义代理主题类
package so.strong.mall.proxy; import java.util.List; public class CartDAOProxy implements CartDao {private CartDao cartDao;public CartDAOProxy() {}public void setCartDao(CartDao cartDao) {this.cartDao = cartDao;}public void prepare() {System.out.println("=====取消掉jdbc的自动提交");}public void commit() {System.out.println("=====手工提交事务");}public void rollback() {System.out.println("=====出现错误,事务回滚");}@Overridepublic boolean insert(Cart cart) throws Exception {try {this.prepare();boolean flag = this.cartDao.insert(cart);this.commit();return flag;} catch (Exception e) {this.rollback();throw e;}}@Overridepublic List<Cart> findAll() throws Exception {return this.cartDao.findAll();} }
业务层现在并不关心到底是代理类还是真实主题类,它只关心一点,只要取得了CartDao接口对象就可以,那么这一操作可以通过工厂类来隐藏。
package so.strong.mall.proxy; public class DAOFactory {public static CartDao getCartDaoInstance() {CartDAOProxy proxy = new CartDAOProxy();proxy.setCartDao(new CartDAOImpl());return proxy;} }
此时业务层暂时不需要继续进行,只需要通过客户端模拟业务层调用即可。
public class TestDemo { public static void main(String[] args) throws Exception{CartDao dao = DAOFactory.getCartDaoInstance();dao.insert(new Cart());} } //=====取消掉jdbc的自动提交 //=====执行数据增加操作===== //=====手工提交事务
因为事务和处理本身与核心业务有关的功能,但是它不是核心,那么用代理解决是最合适的方式。
动态代理设计模式
上面给出的代理设计模式的确可以完成代理要求,但是有一个问题:如果说现在项目里面有200张数据表,那么至少也需要200个左右的DAO接口,如果用上面的代理设计模式,那么意味着除了编写200个的DAO接口实现,还要编写200个代理类,并且有意思的是,这些代理类实现几乎相同。
以上的代理设计模式属于静态代理设计模式,只能够作为代理模式的雏形出现,并不能购作为代码使用的设计模式,为此专门引入了动态代理设计模式的概念。
即:利用一个代理类可以实现所有被代理的操作。
如果要想实现动态设计模式,那么必须首先观察一个接口:java.lang.reflect.InvocatonHandler. 它里面有一个方法:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
这个方法就属于代理中调用真实主题类的操作方法,这个方法里面的参数意义如下:
- Object proxy:表示代理类的对象;
- Method method:表示现在正在调用的方法;
- Object[] args:表示方法里面的参数。
但是这个方法没有所对应的真实对象,所以需要在创建这个类对象的时候设置好真实代理对象。
如果要想找到代理对象则要使用java.lang.reflect.Proxy类来动态创建,此类主要使用以下方法:
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) throws IllegalArgumentException
此方法参数定义如下:
- ClassLoader loader :指的是取得对象的加载器;
- Class<?>[] interfaces: 代理设计模式的核心是围绕接口进行的,所以此处必须取出全部的接口;
- InvocationHandler h:代理的实现类。
范例:使用动态代理实现上面的代理
CartDao不变,修改CartDAOProxy代理类
package so.strong.mall.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class CartDAOProxy implements InvocationHandler {private Object obj; //这个是真实对象主题/*** 将要操作的真实主题对象绑定到代理之中,而后返回一个代理类对象* @param obj 真实对象主题* @return 代理类对象*/public Object bind(Object obj) {this.obj = obj;return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(), this);}public void prepare() {System.out.println("=====取消掉jdbc的自动提交");}public void commit() {System.out.println("=====手工提交事务");}public void rollback() {System.out.println("=====出现错误,事务回滚");}//只要执行了操作方法,那么就一定会触发invoke @Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {Object object = null;//接收返回值if (method.getName().contains("insert")) { //更新插入类操作this.prepare();try {object = method.invoke(this.obj, args); //反射调用方法this.commit();} catch (Exception e) {this.rollback();}} else {object = method.invoke(this.obj, args);//查询操作不需要事务支持 }return object;} }
//修改工厂 package so.strong.mall.proxy; public class DAOFactory {public static Object getCartDaoInstance(Object realObject) {return new CartDAOProxy().bind(realObject);} }
//修改调用 package so.strong.mall.proxy; public class TestDemo {public static void main(String[] args) throws Exception{CartDao dao =(CartDao) DAOFactory.getCartDaoInstance(new CartDAOImpl());dao.insert(new Cart());} }
CGLIB实现动态代理设计模式
动态代理模式的确好用,而且也解决了代理类重复的问题,但是不管是传统静态代理或动态代理都有个设计缺陷,以动态代理为例:
return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this); //传入真实主题类,返回代理主题类
代理设计模式有一个硬性要求,就是类必须要有接口,所以业界很多人认为应该在没有接口的环境下也能使用代理设计模式。
所以在此时在开源社区里面提供了一个组件包——CGLIB,利用此包可以在没有接口的情况下也能够使用动态代理设计模式,它是模拟的类。
如果要想使用CGLIB,那么必须首先搞清楚对应关系:
- Proxy:net.sf.cglib.proxy.Enhancer
- InvocationHandler:net.sf.cglib.proxy.MethodInterceptor
- 真实主题调用:net.sf.cglib.proxy.MethodProxy
老师课上使用的是引入CGLIB的jar包,我去mvn仓库找了一下,找到了一个cglib,放到pom里面发现也可以。
<dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>2.2.2</version> </dependency>
范例:使用CGLIB实现动态代理设计模式
package so.strong.mall.proxy; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method;class ItemDAOImpl {public void insert(Item item) {System.out.println("=====增加操作=====");} }class MyProxy implements MethodInterceptor {private Object target; //真实操作主题public MyProxy(Object target) {this.target = target;}@Overridepublic Object intercept(Object proxy, Method method, Object[] args,MethodProxy methodProxy) throws Throwable {Object object = null;this.prepare();object = method.invoke(this.target, args);this.commit();return object;}public void prepare() {System.out.println("=====取消掉jdbc的自动提交=====");}public void commit() {System.out.println("=====手工提交事务=====");} }public class TestCGLIB {public static void main(String[] args) {ItemDAOImpl itemDAO = new ItemDAOImpl(); //真实主题对象//代理设计模式之中必须要有公共的集合点,例如:接口,而CGLIB没有接口Enhancer enhancer = new Enhancer(); //创建一个代理工具类enhancer.setSuperclass(ItemDAOImpl.class); //设置一个虚拟的父类enhancer.setCallback(new MyProxy(itemDAO)); //设置代理的回调操作ItemDAOImpl proxyDao = (ItemDAOImpl) enhancer.create();proxyDao.insert(new Item());} }
可以发现此时没有了对接口的依赖,也可以实现动态代理设计,但是需要模拟代理的父类对象。
转载于:https://www.cnblogs.com/itermis/p/8940582.html
静态代理设计与动态代理设计相关推荐
- Java 静态代理、Java动态代理、CGLIB动态代理
为什么80%的码农都做不了架构师?>>> Java 的代理就是客户类不再直接和委托类打交道, 而是通过一个中间层来访问, 这个中间层就是代理.为啥要这样呢, 是因为使用代理有 ...
- Java 结合实例学会使用 静态代理、JDK动态代理、CGLIB动态代理
前言 代理 代理 代理 代理 代理 代理 代理 代理 代理 代理 代理 代理 代理 代理 代理 代理 代理 代理 代理 代理 很多人至今都是看到 代理就懵, 静态代理.动态代理.JDK动态代理.CGL ...
- 代理模式(静态代理、jdk动态代理、CGLib动态代理)
目录 1.什么是代理模式? 2.静态代理 1.案例 2.优化案例 3.静态代理瓶颈 3.动态代理 1.什么是动态代理? 2.jdk动态代理 1.动态代理的工具类 匿名内部类简介 2.jdk动态代理实现 ...
- 代理详解 静态代理+JDK/CGLIB 动态代理实战
1. 代理模式 代理模式是一种比较好理解的设计模式.简单来说就是 我们使用代理对象来代替对真实对象(real object)的访问,这样就可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对 ...
- cglib动态代理jar包_代理模式详解:静态代理+JDK/CGLIB 动态代理实战
1. 代理模式 代理模式是一种比较好的理解的设计模式.简单来说就是 我们使用代理对象来代替对真实对象(real object)的访问,这样就可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标 ...
- 一文理解JDK静态代理、JDK动态代理、Cglib动态代理
代理模式 通过代理来访问真实的对象,而不是直接去访问真正干活的对象,比如二房东租房,二房是代理者,而一房东才是真正的房东:或者说生活中的中介.Spring中的AOP就是动态代理 适用场景 需要动态修改 ...
- Java静态代理、动态代理以及CGLIB动态代理
代理模式是java中最常用的设计模式之一,尤其是在spring框架中广泛应用.对于java的代理模式,一般可分为:静态代理.动态代理.以及CGLIB实现动态代理. 对于上述三种代理模式,分别进行说明. ...
- java代理(静态代理和jdk动态代理以及cglib代理)
说到代理,脑袋中浮现一大堆代理相关的名词,代理模式,静态代理,jdk代理,cglib代理等等. 记忆特别深刻的是,一次面试中,一位面试官问我,spring的AOP核心采用的设计模式是什么什么模式,阅读 ...
- 静态代理,JDK动态代理,Cglib动态代理详解
目录 一.代理模式 二.静态代理 三.动态代理 3.1 JDK动态代理 3.2 Cglib动态代理 四.两种动态代理区别 一.代理模式 代理模式(Proxy Pattern)是程序设计中的一种设计模式 ...
- 代理模式(静态代理模式、动态代理模式、cgLib代理模式、拦截器)
目录 一.什么是代理? 二.代理的好处 三.实现代理的步骤 四.静态代理 五.动态代理
最新文章
- mysql基本语句集合
- html实现全屏效果原理,HTML5 实现全屏效果
- Unix/Linux下的/etc目录
- Node.js 在本地生成日志文件
- centos非root用户创建用户_CentOS中用户和用户组管理
- P3156 【深基15.例1】询问学号(20分)--python3实现
- python3发送邮件_Python3 SMTP发送邮件
- 不会日语也能在日本点菜 | 通用篇
- 如何监控防火墙后的流量?
- 德标螺纹规格对照表_(外)内六角螺塞标准编号-国家标准JB/德标DIN
- javaweb项目电子商城购物系统课程设计任务书及成绩评定和毕业设计与实现
- 谷歌FLASH无法添加保存网站
- 日立mCA连接服务器显示地址异常,日立电梯Mca的故障代码是什么
- SpringBoot使用LibreOffice word转换PDF
- OSChina 周五乱弹——岂能说走就能走
- android监听点击通知栏,android使用NotificationListenerService监听通知栏消息
- java复制屏幕文本内容_网页上的文字内容不给复制?电脑老司机教你输入一串代码,轻松复制...
- 游戏中随机地图的实现
- IBIS模型:利用IBIS模型研究信号完整性问题
- 基于微信小程序的高校毕业论文管理系统#毕业设计