• java之代理设计模式


    代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。
    按照代理的创建时期,代理类可以分为两种。
    静态代理:由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。
    动态代理:在程序运行时,运用反射机制动态创建而成。

    这里写图片描述

    静态代理

    1. 定义一个接口
    package cn.itcast.proxy.sh;
    
    public interface PersonDao {
        public void savePerson();
        public void updatePerson();
        public void deletePerson();
    }

    2、 目标类

    package cn.itcast.proxy.sh;
    
    public class PersonDaoImpl implements PersonDao{
        public void deletePerson() {
            System.out.println("delete person");
        }
        public void savePerson() {
            System.out.println("save person");
        }
        public void updatePerson() {
            System.out.println("update person");
        }
    }

    3、代理类,包含了目标类和一些额外的操作

    package cn.itcast.proxy.sh;
    
    public class PersonDaoProxy implements PersonDao{
        private PersonDao personDao;
        private Transaction transaction;
        public PersonDaoProxy(PersonDao personDao,Transaction transactions){
            this.personDao = personDao;
            this.transaction = transactions;
        }
        public void deletePerson() {
            this.transaction.beginTransaction();
            this.personDao.deletePerson();
            this.transaction.commit();
        }
        public void savePerson() {
            this.transaction.beginTransaction();
            this.personDao.savePerson();
            this.transaction.commit();
        }
        public void updatePerson() {
            this.transaction.beginTransaction();
            this.personDao.updatePerson();
            this.transaction.commit();
        }
    }

    4、使用

    package cn.itcast.proxy.sh;
    
    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class ProxyTest {
        @Test
        public void test(){
            ApplicationContext context = new ClassPathXmlApplicationContext("cn/itcast/proxy/sh/applicationContext-proxy.xml");
            PersonDao personDao = (PersonDao)context.getBean("personDao2");
            personDao.deletePerson();
        }
    }

    静态代理的缺点

    静态代理模式的缺点:
    1、如果一个系统中有100Dao,则创建100个代理对象
    2、如果一个dao中有很多方法需要事务,则代理对象的方法中重复代码还是很多
    3、由第一点和第二点可以得出:proxy的重用性不强

    动态代理

    1、产生的代理对象和目标对象实现了共同的接口
    jdk动态代理
    2、代理对象是目标对象的子类
    hibernate: Person person = session.load(Person.class,1L); javassisit
    spring:cglib动态代理

    jdk的动态代理:
    1、因为是用jdk的API做到的
    2、代理对象是动态产生的
    cglib产生的代理类是目标类的子类

    注意事项:
    1、拦截器中invoke方法体的内容就是代理对象方法体的内容
    2、当客户端执行代理对象.方法时,进入到了拦截器的invoke方法体
    3、拦截器中invoke方法的method参数是在调用的时候赋值的

    jdk动态代理

    定义一个接口

    package cn.itcast.jdkproxy.sh;
    
    public interface PersonDao {
        public void savePerson();
        public void updatePerson();
        public void deletePerson();
    }

    目标类

    package cn.itcast.jdkproxy.sh;
    
    public class PersonDaoImpl implements PersonDao{
        public void deletePerson() {
            System.out.println("delete person");
        }
        public void savePerson() {
            System.out.println("save person");
        }
        public void updatePerson() {
            System.out.println("update person");
        }
    }

    拦截器

    package cn.itcast.jdkproxy.sh;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    
    /**
     * 拦截器
     * @author Think
     *   1、引入目标类
     *   2、引入事务
     *   3、通过构造函数给目标类和事务赋值
     *   4、填充invoke方法
     *
     */
    public class PersonInterceptor implements InvocationHandler{
    
        private Object target;//目标类
        private Transaction transaction;//引入事务
    
        public PersonInterceptor(Object target,Transaction transaction){
            this.target = target;
            this.transaction = transaction;
        }
    
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args)
                throws Throwable {
            // TODO Auto-generated method stub
            this.transaction.beginTransaction();
            method.invoke(this.target, args);//调用目标类的方法
            this.transaction.commit();
            return null;
        }
    
    }

    使用

    package cn.itcast.jdkproxy.sh;
    
    import java.lang.reflect.Proxy;
    
    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class ProxyTest {
        @Test
        public void test(){
            Object target = new PersonDaoImpl();
            Transaction transaction = new Transaction();
            PersonInterceptor interceptor = new PersonInterceptor(target, transaction);
            /**
             * 1、目标类的类加载器
             * 2、目标类实现的所有的接口
             * 3、拦截器
             */
            PersonDao personDao = (PersonDao)Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), interceptor);
            personDao.deletePerson();
        }
    }

    cglib动态代理

    JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。

    目标类

    package net.battier.dao.impl;  
    
     /** 
      * 这个是没有实现接口的实现类 
      *  
      * @author student 
      *  
      */  
     public class BookFacadeImpl1 {  
         public void addBook() {  
             System.out.println("增加图书的普通方法...");  
         }  
     }  

    拦截类

    package net.battier.proxy;  
    
    import java.lang.reflect.Method;  
    
    import net.sf.cglib.proxy.Enhancer;  
    import net.sf.cglib.proxy.MethodInterceptor;  
    import net.sf.cglib.proxy.MethodProxy;  
    
    /** 
     * 使用cglib动态代理 
     *  
     * @author student 
     *  
      */  
     public class BookFacadeCglib implements MethodInterceptor {  
         private Object target;  
    
        /** 
         * 创建代理对象 
          *  
          * @param target 
          * @return 
          */  
         public Object getInstance(Object target) {  
            this.target = target;  
            Enhancer enhancer = new Enhancer();  
            enhancer.setSuperclass(this.target.getClass());  
            // 回调方法  
            enhancer.setCallback(this);  
            // 创建代理对象  
            return enhancer.create();  
        }  
    
        @Override  
        // 回调方法  
        public Object intercept(Object obj, Method method, Object[] args,  
                MethodProxy proxy) throws Throwable {  
            System.out.println("事物开始");  
            proxy.invokeSuper(obj, args);  
            System.out.println("事物结束");  
            return null;  
    
    
        }  
    
    }  

    使用

    package net.battier.test;  
    
    import net.battier.dao.impl.BookFacadeImpl1;  
    import net.battier.proxy.BookFacadeCglib;  
    
    public class TestCglib {  
    
        public static void main(String[] args) {  
            BookFacadeCglib cglib=new BookFacadeCglib();  
            BookFacadeImpl1 bookCglib=(BookFacadeImpl1)cglib.getInstance(new BookFacadeImpl1());  
            bookCglib.addBook();  
        }  
    }  

    参考链接

    java动态代理(JDK和cglib) - C’est la vie - 博客园

  • 相关阅读:
    冒泡/快速排序
    Windows RT和WinRT
    UAC(User Access Control)操作小结(C++)
    将CHM文件转换为HTML文件
    WPF实现窗口比例恒定不变小结(2)
    用WinForm的ShowHelp()函数处理CHM文件
    Windows 8下对Microsoft Surface SDK 2.0的调查小结
    WPF实现窗口比例恒定不变小结(1)
    资源释放
    axis 1.4 使用及介绍
  • 原文地址:https://www.cnblogs.com/jjx2013/p/6223679.html
Copyright © 2020-2023  润新知