代理模式
来源:互联网 发布:自干五 小粉红 知乎 编辑:程序博客网 时间:2024/06/07 15:47
一,概述
1)代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式,即通过代理访问目标对象.
2)代理的好处:可以在目标对象实现的基础上,增加额外的功能操作,即扩展目标对象的功能.
3)分类:静态代理,动态代理,cglib代理.
4)代理模式的关键点:代理对象与目标对象.
5)举例:商家是直接联系不到明星的,一般情况下,都是商家找明星经纪人,然后明星经纪人通知明星.明星是目标对象,明星经纪人就是代理对象.
二,静态代理
1)要点:代理对象要实现与目标对象一样的接口.
2)举例:模拟保存用户
UserDao-->直接保存
UserDaoProxy-->给保存方法添加事务管理
3)接口:IUserDao.java
public interface IUserDao {void save();}4)目标对象:UserDao.java,实现了IUserDao接口
public class UserDao implements IUserDao {@Overridepublic void save() {System.out.println("***保存用户数据到数据库");}}5)代理对象:UserDaoProxy.java,与目标对象一样实现了IUserDao接口
public class UserDaoProxy implements IUserDao{private IUserDao target;public UserDaoProxy(IUserDao target) {this.target = target;}@Overridepublic void save() {System.out.println("开启事务...");//执行目标对象的方法target.save();System.out.println("提交事务...");}}6)测试:
public class App {@Testpublic void testProxy() throws Exception {IUserDao userDao=new UserDao();UserDaoProxy proxy=new UserDaoProxy(userDao);proxy.save();}}结果:
开启事务...***保存用户数据到数据库提交事务...综上,扩展了UserDao的save接口.
7)总结静态代理:
a)优点:可以做到在不修改目标对象的前提下,对目标对象的功能进行扩展.
b)缺点:因为代理对象需要与目标对象实现一样的接口,所以会造成很多代理类,类太多;一旦接口增加方法,目标对象与代理对象都要维护.(动态代理就可以避免这些问题,借助代理工厂完成)
三,动态代理
1)代理对象不需要实现接口.
2)代理对象的生成利用了JDK API,动态地在内存中构建代理对象(需要我们指定创建代理对象 目标对象 实现的接口的类型)
3)动态代理也叫JDK代理,或者接口代理.
4)接口和目标对象还是用上面代码,代理工厂代码如下:
package com.bighuan.b_dynamic;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;/** * 给所有Dao创建代理对象(动态代理) * * @author bighuan * */public class ProxyFactory {// 维护一个目标对象private Object target;public ProxyFactory(Object target) {this.target = target;}// 给目标对象生成代理对象public Object getProxyInstance() {return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),// 得到目标对象实现的接口类型// new Class[]{IUserDao.class}new InvocationHandler() {// 事件处理器@Overridepublic Object invoke(Object proxy, Method method,Object[] args) throws Throwable {// 开启事务System.out.println("***开启事务***");String name = method.getName();// 拿到方法名System.out.println(name);// 执行目标对象方法Object returnValue = method.invoke(target, args);// 提交事务System.out.println("***提交事务***");return returnValue;}});}}5)测试:
@Testpublic void testProxy() throws Exception {//目标对象IUserDao userDao=new UserDao();//原始类型:class com.bighuan.b_dynamic.UserDaoSystem.out.println(userDao.getClass());//给目标对象创建代理对象IUserDao proxy=(IUserDao) new ProxyFactory(userDao).getProxyInstance();//class $Proxy4,内存中动态生成的代理对象System.out.println(proxy.getClass());//执行方法[代理对象]proxy.save();}效果和上面的静态代理一致,但却规避了静态代理的缺点.
6)动态代理总结:代理对象不需要实现接口,但是目标对象一定要实现接口;否则不能使用动态代理!
如果一个目标对象需要实现功能扩展,但是目标对象却没有实现接口,该怎样实现功能扩展呢?
四,Cglib代理
1)Cglib代理也叫子类代理,在内存中构建一个子类对象从而实现对目标对象的功能扩展.
2)JDK的动态代理有一个限制,就是使用动态代理的对象必须实现一个或多个接口.如果想代理没有实现接口的类,就可以使用CGLIB实现.
3)CGLIB是一个强大的高性能的代码生成包,它可以在运行期扩展Java类与实现Java接口.它广泛的被许多AOP的框架使用,例如Spring AOP和dynaop,为他们提供方法的interception(拦截).
4)CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类.不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉.
5)开发准备:需要引入Cglib的相关jar文件,但是Spring的核心包中已经包括了cglib功能,所以自接导入spring-core-3.2.5.jar即可;引入功能包后,就可以在内存中动态构建子类.
6)代理类不能为final类(final类没有子类),目标对象的方法如果为final或static(final或static修饰的方法,子类不能重写),那么就不会拦截,即不会执行除目标对象之外的业务方法.
7)UserDao.java
public class UserDao {public void save() {System.out.println("***保存用户数据到数据库");}}ProxyFactory.java
package com.bighuan.c_cglib;import java.lang.reflect.Method;import org.springframework.cglib.proxy.Enhancer;import org.springframework.cglib.proxy.MethodInterceptor;import org.springframework.cglib.proxy.MethodProxy;/** * Cglib子类代理工厂 * (对UserDao,在内存中动态构建一个子类对象) * @author bighuan * */public class ProxyFactory implements MethodInterceptor{//维护目标对象private Object target;public ProxyFactory(Object target){this.target=target;}//给目标对象创建代理对象public Object getProxyInstance(){//1,工具类Enhancer hancer=new Enhancer();//2,设置父类hancer.setSuperclass(target.getClass());//3,设置回调函数hancer.setCallback(this);//4,创建子类(代理对象)return hancer.create();}@Overridepublic Object intercept(Object obj, Method method, Object[] args,MethodProxy proxy) throws Throwable {System.out.println("**********开启事务*****");//执行目标对象的方法Object returnValue = method.invoke(target, args);System.out.println("**********提交事务*****");return returnValue;}}8)测试:
@Testpublic void testProxy() throws Exception {//目标对象UserDao target=new UserDao();//class com.bighuan.c_cglib.UserDaoSystem.out.println(target.getClass());//代理对象UserDao proxy=(UserDao) new ProxyFactory(target).getProxyInstance();//class com.bighuan.c_cglib.UserDao$$EnhancerByCGLIB$$b6d37fe1System.out.println(proxy.getClass());//执行代理对象的方法proxy.save();}结果:
**********开启事务********保存用户数据到数据库**********提交事务*****
五,总结
下一篇,Spring的AOP编程,期待吧,boys!
- 代理模式--动态代理
- 代理模式-静态代理
- 代理模式-静态代理
- 代理模式 & 动态代理
- 代理模式--静态代理
- 代理模式--动态代理
- 代理模式(动态代理)
- 代理模式-动态代理
- 代理模式-动态代理
- 代理模式动态代理
- 代理模式-静态代理
- 代理模式-动态代理
- 代理模式 -动态代理
- 代理模式---动态代理
- 代理模式-动态代理
- 代理模式--静态代理
- 代理模式!
- 代理模式
- 漫谈程序员系列:群星闪耀的黄金时代
- 函数调用里的*和**
- C++之单链表
- leetcode-315. Count of Smaller Numbers After Self
- 学习云计算从哪里入手
- 代理模式
- 关于辛普森积分法的研究
- python知识点0
- SQL语法大全
- 有符号数和无符号数的相加和pintf的%d机制
- 倒计时制作笔记
- 2017-5-6关于Map集合的遍历一些记录
- CC3220学习笔记---点亮LED寄存器版
- JDBC