Java设计模式7-结构型-代理模式

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

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
    public class MyInterceptor implements InvocationHandler{
        private Object target;//目标类
        //除了目标类以外的所有的功能都抽象为Interceptor
        private List interceptors;

        public MyInterceptor(Object target, List 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 interceptors = new ArrayList();
        interceptors.add(transaction);//我们可以添加不同的interceptor
        MyInterceptor interceptor = new MyInterceptor(target, interceptors);

        PersonDao personDao = (PersonDao)Proxy.newProxyInstance(target.getClass().getClassLoader(), 
                target.getClass().getInterfaces(), interceptor);
        personDao.updatePerson();
    }

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设计模式)