JAVA语言设计模式之结构型代理模式详解
小标 2018-07-13 来源 : 阅读 516 评论 0

摘要:本文主要向大家介绍了JAVA语言设计模式之结构型代理模式详解,通过具体的内容向大家展示,希望对大家学习JAVA语言有所帮助。

本文主要向大家介绍了JAVA语言设计模式之结构型代理模式详解,通过具体的内容向大家展示,希望对大家学习JAVA语言有所帮助。

主要分静态代理和动态代理

1、静态代理:

   

首先我们看下为什么要使用动态代理,先看看静态代理有什么问题。

演示一个静态代理的例子:(jdk的代理是基于接口的)

功能就是,保存数据的时候添加事务处理

    

//定义接口 PersonDao.java

    public interface PersonDao {

        public void savePerson();

    }

//定义个实现类 PersonDaoImpl.java

    public class PersonDaoImpl implements PersonDao{

        public void savePerson() {

            System.out.println("save person");

        }

    }

//定义一个事务类 Transaction.java

    public class Transaction {

        public void beginTransaction(){

            System.out.println("begin transaction");//开启事务

        }

 

        public void commit(){

            System.out.println("commit");//提交事务

        }

    }

//定义个代理类 PersonDaoProxy.java

    public class PersonDaoProxy implements PersonDao{ //实现相同的接口

        private PersonDao personDao;

        private Transaction transaction;

        public PersonDaoProxy(PersonDao personDao,Transaction transaction) {

            super();

            this.personDao = personDao;//通过构造传进来

            this.transaction = transaction;

        }

 

        public void savePerson() {

            this.transaction.beginTransaction();

            this.personDao.savePerson();

            this.transaction.commit();

        }

    }

//测试 ProxyTest.java

    public class ProxyTest {

        @Test

        public void testProxy(){

            PersonDao personDao = new PersonDaoImpl();

            Transaction transaction = new Transaction();

            PersonDaoProxy proxy = new PersonDaoProxy(personDao, transaction);

            proxy.savePerson();

        }

    }

   

看看静态代理有什么问题:

a.静态代理没有事务重用,我们还是要在每个方法里面调用this.transaction.beginTransaction();

b.如果我们dao层有100个方法,我们就需要写100个proxy类,变得更麻烦了。接口中定义了多少个方法,

    proxy也要实现多少个方法。

c.如果一个proxy实现了多个接口,如果其中的一个接口发生变化(添加了一个方法),那么proxy也要做相应的改变。

所以静态代理我们维护起来会更加的麻烦。

   

2、动态代理:

   

既然静态代理这么多的问题,那么我们看看动态代理。

顾名思义,动态代理就是动态生成Proxy类,不需要我们自己创建Proxy了。

演示下:

    

   

public interface PersonDao {

    public void savePerson();

    public void updatePerson();

}

public class PersonDaoImpl implements PersonDao{

    public void savePerson() {

        System.out.println("save person");

    }

 

    public void updatePerson() {

        System.out.println("update person");

    }

}

public class Transaction {

    public void beginTransaction(){

        System.out.println("begin transaction");

    }

    public void commit(){

        System.out.println("commit");

    }

}

 

//最主要的设置拦截器

public class MyInterceptor implements InvocationHandler{

    private Object target;//目标类

    private Transaction transaction;

    public MyInterceptor(Object target, Transaction transaction) {

        super();

        this.target = target;

        this.transaction = transaction;

    }

    //proxy这个是代表的我们MyInterceptor这个类,千万别写成method.invoke(proxy);

    //否则就死循环,jvm就挂了

    public Object invoke(Object proxy, Method method, Object[] args)

            throws Throwable {

        String methodName = method.getName();

        if("savePerson".equals(methodName)||"updatePerson".equals(methodName)

                ||"deletePerson".equals(methodName)){

            this.transaction.beginTransaction();//开启事务

            method.invoke(target);//调用目标方法

            this.transaction.commit();//事务的提交

        }else{

            method.invoke(target);

        }

        return null;

    }

}

 

//使用

public class JDKProxyTest {

    @Test

    public void testJDKProxy(){

        Object target = new PersonDaoImpl();

        Transaction transaction = new Transaction();

        MyInterceptor interceptor = new MyInterceptor(target, transaction);

        /**

         * 参数说明:

         * 1、目标类的类加载器

         * 2、目标类实现的所有的接口

         * 3、拦截器

         */

        PersonDao personDao = (PersonDao)Proxy.newProxyInstance(target.getClass().getClassLoader(),

                target.getClass().getInterfaces(), interceptor);

        //personDao.savePerson();

        personDao.updatePerson();

    }

}

    

   

注意几个问题:

    a、拦截器的invoke方法是在时候执行的?

        当在客户端,代理对象调用方法的时候,进入到了拦截器的invoke方法。

    b、代理对象的方法体的内容是什么?

        拦截器的invoke方法的内容就是代理对象的方法的内容

    c、拦截器中的invoke方法中的参数method是谁在什么时候传递过来的?

        代理对象调用方法的时候,进入了拦截器中的invoke方法,所以invoke方法中的参数method就是

        代理对象调用的方法。

 

    我们看看动态代理有什么问题:

    a.在拦截器中除了能调用目标对象的目标方法以外,功能是比较单一的,在这个例子中只能处理事务。

        这里可以有个解决方案。比如我们有 Transaction(事务),Log(打印),Access(权限控制)

        我们可以让这几个类同时实现一个接口,我们传一个接口的List过来,然后for循环处理。

        这也是种解决方案。

    b.拦截器中的invoke方法的if判断方法名称在真实的开发环境下是不靠谱的,

        因为一旦方法很多if语句需要写很多。

        我有100个方法就要判断100次,而且名称不能写错。

        这个暂时没有好的解决方法,在spring中可以解决。

    c.调用时机的问题,我们是在invoke方法之前调用还是在invoke方法之后调用,或者是出异常在调用。

   

3、基于动态代理中的第一个问题,解决方案:

    //给事务、日志等做了一个抽象,而这个抽象就是Interceptor

    public interface Interceptor {

        public void interceptor();

    }

    //事务实现了接口,其他的也同样的做法

    public class Transaction implements Interceptor{

        public void interceptor() {

            System.out.println("begin transaction");

            System.out.println("commit");

        }

    }

    //拦截器传的是一个 List<interceptor>

    public class MyInterceptor implements InvocationHandler{

        private Object target;//目标类

        //除了目标类以外的所有的功能都抽象为Interceptor

        private List<interceptor> interceptors;

 

        public MyInterceptor(Object target, List<interceptor> interceptors) {

            super();

            this.target = target;

            this.interceptors = interceptors;

        }

 

        public Object invoke(Object proxy, Method method, Object[] args)

                throws Throwable {

            for (Interceptor interceptor : interceptors) {//这样调用了多个功能方法

                interceptor.interceptor();

            }

            method.invoke(target);

            return null;

        }

    }

    //使用

    @Test

    public void testJDKProxy(){

        /**

         * 1、创建一个目标对象

         * 2、创建一个事务

         * 3、创建一个拦截器

         * 4、动态产生一个代理对象

         */

        Object target = new PersonDaoImpl();

        Transaction transaction = new Transaction();

        List<interceptor> interceptors = new ArrayList<interceptor>();

        interceptors.add(transaction);//我们可以添加不同的interceptor

        MyInterceptor interceptor = new MyInterceptor(target, interceptors);

 

        PersonDao personDao = (PersonDao)Proxy.newProxyInstance(target.getClass().getClassLoader(),

                target.getClass().getInterfaces(), interceptor);

        personDao.updatePerson();

    }

 

</interceptor></interceptor></interceptor></interceptor></interceptor>

   

4、cglib动态代理:

我们上面说的是jdk的动态代理,是基于接口的,我们的目标类需要实现接口,代理类就实现相同的接口。

cglib代理是基于子类的。

演示下:


//首先需要导入cglib的包

cglib-nodep-2.1_3.jar

 

//我们现在就没有接口了

public class PersonDaoImpl{

    public void savePerson() {

        System.out.println("save person");

    }

    public void updatePerson() {

        System.out.println("update person");

    }

}

public class Transaction {

    public void beginTransaction(){

        System.out.println("begin transaction");

    }

 

    public void commit(){

        System.out.println("commit");

    }

}

 

//我们的拦截器

public class MyInterceptor implements MethodInterceptor{

    private Object target;//目标类

    private Transaction transaction;

 

    public MyInterceptor(Object target, Transaction transaction) {

        super();

        this.target = target;

        this.transaction = transaction;

    }

 

    public Object createProxy(){

        //代码增强类

        Enhancer enhancer = new Enhancer();

        enhancer.setCallback(this);//参数为拦截器

        enhancer.setSuperclass(target.getClass());//生成的代理类的父类是目标类

        return enhancer.create();

    }

 

    public Object intercept(Object arg0, Method method, Object[] arg2,

            MethodProxy arg3) throws Throwable {

        this.transaction.beginTransaction();

        method.invoke(target);

        this.transaction.commit();

        return null;

    }

}

//使用

//通过cglib产生的代理对象,代理类是目标类的子类

public class CGLibProxyTest {

    @Test

    public void testCGlib(){

        Object target = new PersonDaoImpl();

        Transaction transaction = new Transaction();

        MyInterceptor interceptor = new MyInterceptor(target, transaction);

        //使用拦截器创建一个代理的对象

        PersonDaoImpl personDaoImpl = (PersonDaoImpl)interceptor.createProxy();

        personDaoImpl.savePerson();

    }

}

    

使用cglib的好处是我们目标类不需要实现接口就可以完成动态代理功能了。

 

讲了这么多,还是没解决多if判断等问题。

希望对JAVA有兴趣的朋友有所帮助。了解更多内容,请关注职坐标编程语言JAVA频道!


本文由 @小标 发布于职坐标。未经许可,禁止转载。
喜欢 | 1 不喜欢 | 0
看完这篇文章有何感觉?已经有1人表态,100%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程