代理模式

来源:互联网 发布:自干五 小粉红 知乎 编辑:程序博客网 时间: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!





0 0