代理模式

来源:互联网 发布:周春芽绿狗 知乎 编辑:程序博客网 时间:2024/06/06 03:48

代理模式

1、代理模式

1.1、应用场景

当程序涉及修改数据库中数据操作时,此时的一般操作流程是:
- 1、开启事务
- 2、修改操作
- 3、提交事务或者回滚事务

随着时间的推移,代码中开启事务、提交事务及回滚事务的代码将变得冗余。记录日志在程序中也是推荐使用,那么记录日志也将变得冗余,同时设计具体业务操作的时候,往往还得考虑事务、日志等方面的操作,不能专注于业务操作。

为了解决代码冗余以及业务对象专注于业务操作,产生了代理模式。

1.2、组成部分

代理模式有以下5部分组成:
- 1、target(目标对象/业务对象)
- 2、proxy(代理对象)
- 2、function(功能对象/事务对象、日志对象)
- 3、interceptor(拦截器对象)
- 4、client(客户端)

2、静态代理模式

通过代理类去完成目标类的目标方面,并且在该目标的类特定的代理类中附加上额外的功能

静态代理模式代码实例:

目标类接口

/*** @ClassName: PersonDao* @Description: PersonDao接口* @author Yue Chang * @date 2017年3月23日 上午10:42:46 * @since 1.0*/public interface PersonDao {    public void deletePerson();    public void updatePerson();}

目标类实现类

/*** @ClassName: PersonDaoImpl* @Description: PersonDao接口实现类* @author Yue Chang * @date 2017年3月23日 上午10:42:05 * @since 1.0*/public class PersonDaoImpl implements PersonDao {    @Override    public void deletePerson() {        System.out.println("delete Person !~");    }    @Override    public void updatePerson() {        System.out.println("update Person !~");    }}

事务类

/*** @ClassName: Transaction* @Description: 事务类* @author Yue Chang * @date 2017年3月23日 上午10:45:19 * @since 1.0*/public class Transaction {    public void beginTransaction(){        System.out.println("begin transaction !~");    }    public void commit(){        System.out.println("transaction commit !~");    }    public void rollback(){        System.out.println("transaction rollback !~");    }}

拦截器类

/*** @ClassName: MyHandler* @Description: 拦截器类* @author Yue Chang * @date 2017年3月23日 上午11:54:30 * @since 1.0*/public class MyHandler implements PersonDao {    private Transaction transaction;    private PersonDao personDaoTarget;    /**     * @param transaction     * @param personDao     */    public MyHandler(Transaction transaction, PersonDao personDao) {        super();        this.transaction = transaction;        this.personDaoTarget = personDao;    }    @Override    public void deletePerson() {        try {            // 开启事务            transaction.beginTransaction();            // 目标类对象调用目标方法            personDaoTarget.deletePerson();            // 提交事务            transaction.commit();        } catch (Exception e) {            // 回滚事务            transaction.rollback();        }    }    @Override    public void updatePerson() {        try {            // 开启事务            transaction.beginTransaction();            // 目标类对象调用目标方法            personDaoTarget.updatePerson();            // 提交事务            transaction.commit();        } catch (Exception e) {            // 回滚事务            transaction.rollback();        }    }    public Transaction getTransaction() {        return transaction;    }    public void setTransaction(Transaction transaction) {        this.transaction = transaction;    }    public PersonDao getPersonDaoTarget() {        return personDaoTarget;    }    public void setPersonDaoTarget(PersonDao personDaoTarget) {        this.personDaoTarget = personDaoTarget;    }}

客户端对象

/*** @ClassName: StaticProxyTest* @Description: 静态代理模式测试类* @author Yue Chang * @date 2017年3月23日 下午12:01:49 * @since 1.0*/public class StaticProxyTest {    @Test    public void testStaticProxy(){        PersonDao personDao = new PersonDaoImpl();        Transaction transaction = new Transaction();        MyHandler myHandler = new MyHandler(transaction, personDao);        myHandler.deletePerson();        System.out.println();        myHandler.updatePerson();    }}

程序执行结果:

begin transaction !~delete Person !~transaction commit !~begin transaction !~update Person !~transaction commit !~

优点:。
1、可以在不改变目标类的基础上,增加额外的功能,耦合度低;
2、让目标类专注于业务开发,无需关注业务之外的功能;
缺点:
1、对于每一个目标类都需要编写一个handler,代码冗余,增加代码维护成本;

3、动态代理

为了解决静态代理模式的代码冗余的缺点,以及继续保持低耦合的优点,也就有了动态代理模式。其中包括cglib动态代理模式和jdk动态代理模式。

3.1 jdk动态代理模式

jdk动态代理模式代码实例:

PersonDao接口

/*** @ClassName: PersonDao* @Description: PersonDao接口* @author Yue Chang * @date 2017年3月23日 上午10:42:46 * @since 1.0*/public interface PersonDao {    public void deletePerson();    public void updatePerson();}

PersonDao接口实现类

/*** @ClassName: PersonDaoImpl* @Description: PersonDao接口实现类* @author Yue Chang * @date 2017年3月23日 上午10:42:05 * @since 1.0*/public class PersonDaoImpl implements PersonDao {    @Override    public void deletePerson() {        System.out.println("delete Person !~");    }    @Override    public void updatePerson() {        System.out.println("update Person !~");    }}

功能类(事务类)

/*** @ClassName: Transaction* @Description: 事务类* @author Yue Chang * @date 2017年3月23日 上午10:45:19 * @since 1.0*/public class Transaction {    public void beginTransaction(){        System.out.println("begin transaction !~");    }    public void commit(){        System.out.println("transaction commit !~");    }    public void rollback(){        System.out.println("transaction rollback !~");    }}

拦截器

/** * @ClassName: MyHandler * @Description: 拦截器 * @author Yue Chang * @date 2017年3月23日 上午10:49:05 * @since 1.0 */public class MyHandler implements InvocationHandler {    private Object target;    private Transaction transaction;    /**     * @param target 目标对象     * @param tansaction 事务对象     */    public MyHandler(Object target, Transaction transaction) {        super();        this.target = target;        this.transaction = transaction;    }    // invoke方法    @Override    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {        try {            // 开启事务            transaction.beginTransaction();            // 调用目标类的目标方法,            method.invoke(target, args);            // 提交事务            transaction.commit();        } catch (Exception e) {            // 回滚事务            transaction.rollback();        }        return null;    }    // getter/setter方法}

客户端测试类

/*** @ClassName: JdkProxyTest* @Description: jdk动态代理客户端* @author Yue Chang * @date 2017年3月23日 上午10:56:36 * @since 1.0*/public class JdkProxyTest {    @Test    public void testJdkProxy(){        // 目标对象        PersonDao target = new PersonDaoImpl();        // 事务对象        Transaction transaction = new Transaction();        // 拦截器对象        MyHandler myIntercepter = new MyHandler(target, transaction);        // PersonDao代理对象        PersonDao proxy = (PersonDao) Proxy.newProxyInstance(target.getClass().getClassLoader(),            target.getClass().getInterfaces(), myIntercepter);        proxy.deletePerson();        System.out.println();        proxy.updatePerson();    }}

代码执行结果:

begin transaction !~delete Person !~transaction commit !~begin transaction !~update Person !~transaction commit !~

如果想再加入其他功能,比如日志,则需要在MyHandler类中,新增成员变量Logger,修改对应的构造方法,在invoke方法中增加对应操作。同时,如果觉得不需要事务,也同样可以操作MyHandler类来去除事务,这样的操作与目标类没有任何影响,完全松耦合。

3.2 cglib动态代理模式

cglib动态代理模式与jdk动态代理模式类似,cglib动态代理模式代码如下:
PersonDao接口

/*** @ClassName: PersonDao* @Description: PersonDao接口* @author Yue Chang * @date 2017年3月23日 上午10:42:46 * @since 1.0*/public interface PersonDao {    public void deletePerson();    public void updatePerson();}

PersonDao接口实现类

/*** @ClassName: PersonDaoImpl* @Description: PersonDao接口实现类* @author Yue Chang * @date 2017年3月23日 上午10:42:05 * @since 1.0*/public class PersonDaoImpl implements PersonDao {    @Override    public void deletePerson() {        System.out.println("delete Person !~");    }    @Override    public void updatePerson() {        System.out.println("update Person !~");    }}

事务类

/*** @ClassName: Transaction* @Description: 事务类* @author Yue Chang * @date 2017年3月23日 上午10:45:19 * @since 1.0*/public class Transaction {    public void beginTransaction(){        System.out.println("begin transaction !~");    }    public void commit(){        System.out.println("transaction commit !~");    }    public void rollback(){        System.out.println("transaction rollback !~");    }}

cglib代理类拦截器

/** * @ClassName: MyInterceptor * @Description: cglib代理类拦截器 * @author Yue Chang * @date 2017年3月23日 下午12:19:35 * @since 1.0 */public class MyInterceptor implements MethodInterceptor {    private Object target;    private Transaction transaction;    /**     * @param target     * @param transaction     */    public MyInterceptor(Object target, Transaction transaction) {        super();        this.target = target;        this.transaction = transaction;    }    /**     * @category 创建代理对象,可以在客户端完成     * @since cglib proxy     * @author Yue Chang      * @date 2017年3月31日 上午11:41:50      * @return     */    public Object createProxy(){        Enhancer enhancer = new Enhancer();        enhancer.setCallback(this);        enhancer.setSuperclass(target.getClass());        return enhancer.create();    }    @Override    public Object intercept(Object arg0, Method method, Object[] args,         MethodProxy arg3) throws Throwable {        try {            transaction.beginTransaction();            method.invoke(target, args);            transaction.commit();        } catch (Exception e) {            e.printStackTrace();            transaction.rollback();        }        return null;    }    // getter/setter方法}

客户端

/*** @ClassName: CglibProxyTest* @Description: cglib代理模式测试类* @author Yue Chang * @date 2017年3月25日 下午3:48:01 * @since 1.0*/public class CglibProxyTest {    @Test    public void testCglibProxy(){        PersonDao target = new PersonDaoImpl();        Transaction transaction = new Transaction();        MyInterceptor myInterceptor = new MyInterceptor(target, transaction);        PersonDao proxy = (PersonDao) myInterceptor.createProxy();        proxy.deletePerson();        System.out.println();        proxy.updatePerson();    }}

程序运行结果:

begin transaction !~delete Person !~transaction commit !~begin transaction !~update Person !~transaction commit !~

3.3 jdk动态代理模式和cglib动态代理模式的区别

均在invoke方法中,对于复杂的逻辑处理比较困难。其中,具体方法由对应method参数决定。

jdk动态代理模式中,是通过Proxy.newProxyInstance来创建代理对象;
cglib动态代理模式中,是通过Enhancer对象来创建代理对象;

jdk动态代理模式中,代理类与目标类实现了相同的接口;
cglib动态代理模式中,代理类是目标类的子类;

这一点区别其实也可以从创建代理对象中发现,jdk的获得目标类以及目标类的所有接口

Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), myIntercepter);

cglib 将目标类设置为代理对象的超类

Enhancer enhancer = new Enhancer();        enhancer.setCallback(this);        enhancer.setSuperclass(target.getClass());        return enhancer.create();

4、拓展

可以申明一个Interceptor类,里面定义interceptor方法,将所有需要附加的功能类都实现Interceptor接口,将需要的操作在interceptor方法中实现,然后在动态代理模式中定义List interceptorList成员变量,初始化时传入interceptorList,在invoke方法中迭代此List,并执行Interceptor对象的interceptor方法,这样可以执行附加多个功能,并且不频繁改动拦截器类。

0 0
原创粉丝点击