代理模式

代理模式

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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值