代理模式

作者: 降龙_伏虎 | 来源:发表于2019-06-19 10:57 被阅读0次

    1.概念

    代理模式(Proxy Pattern) 是指为其它对象提供一种代理,以控制这个对象的访问,
    代理对象在客户端和目标对象之间起到中介作用,
    属于结构型设计模式
    

    2.静态代理

    "非专业"中介,只能为特定对象进行代理,如父母代理儿子找对象;
    代码中指为某个特定的对象的特定方法进行代理,
    不具有通用性,以及动态切换的能力
    
    /**
     * Description:儿子类(被代理对象)
     *
     * @date 2019-05-08 19:39
     */
    
    public class Son{
    
        /**
         * Description:找对象要求
         * @Date  2019-05-08 19:40
         * @Param []
         * @return java.lang.String
        **/
    
        public String findLove(){
            return  "租房要求:女的";
        }
    }
    
    /**
     * Description:父亲类(代理人)
     *
     * @date 2019-05-08 19:41
     */
    
    public class Father {
    
        private  Son son;
    
        public Father(Son son) {
            this.son = son;
        }
    
        public String helpFindLove(){
            System.out.println("父亲帮儿子找对象开始");//此处可进行特殊处理
            String s =  son.findLove();
            System.out.println("儿子找对象要求:"+s);
            System.out.println("父亲帮儿子找对象结束");//此处可进行特殊处理
            return s;
        }
    }
    
    /**
     * Description:静态代理测试
     *
     * @date 2019-05-08 19:47
     */
    
    public class Test {
        public static void main(String[] args) {
            Father father = new Father(new Son());
            father.helpFindLove();
        }
    }
    

    3.动态代理

    "专业"中介,能为所有对象进行代理,如婚介所;
    具有通用性,以及动态切换的能力
    

    3.1 JDK 动态代理

    /**
     * Description:人接口
     *
     * @date 2019-05-09 19:33
     */
    
    public interface Person {
    
        void findLove();
    }
    
    
    
    /**
     * Description:女孩类
     *
     * @date 2019-05-09 19:32
     */
    
    public class Girl implements Person{
    
        @Override
        public void findLove(){
            System.out.println("要求:是男的");
        }
    }
    
    /**
     * Description:媒婆
     *
     * @date 2019-05-09 19:36
     */
    
    public class MeiPo implements InvocationHandler {
    
        //被代理对象
        private Person target;
    
        //获取JDK代理
        public Object getInstance(Person person){
            this.target = person;
            Class<?> clazz = target.getClass();
            //根据被代理对象信息获取代理对象(被代理对象被代理对象"包裹")
            return Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            befor();
            Object obj =  method.invoke(this.target,args);
            after();
            return obj;
        }
    
        private void befor(){
            System.out.println("代理前置操作...");
    
        }
    
        private void after(){
            System.out.println("代理后置操作...");
        }
    }
    
    /**
     * Description:JDKd动态代理测试类
     *
     * @date 2019-05-09 19:44
     */
    
    public class Test {
    
        public static void main(String[] args) {
    
            try {
                Person obj = (Person)new MeiPo().getInstance(new Girl());
                obj.findLove();
            } catch (Exception e) {
                e.printStackTrace();
            }
    
        }
    }
    

    原理

    将被代理对象做相关特殊包装后 通过"动态生成字节码"生成一个新的"被包装"的类
    
    /**
     * 通道JDK代理生成的类
     * ① 新的类继承Proxy
     * ② 新的类实现Person接口
     *
     *
    **/
    
    public final class $Proxy0 extends Proxy implements Person {
    ....
        //被代理对象的方法
        public final void findLove() throws  {
            try {
                //执行媒婆对象的invoke方法&将当前对象传入媒婆
                super.h.invoke(this, m3, (Object[])null);
            } catch (RuntimeException | Error var2) {
                throw var2;
            } catch (Throwable var3) {
                throw new UndeclaredThrowableException(var3);
            }
        }
    ....
    
    }
    

    手工模拟JDK动态代理

    /**
     * Description:人接口
     *
     * @date 2019-05-09 19:33
     */
    
    public interface Person {
    
        void findLove();
    }
    
    /**
     * Description:女孩类
     *
     * @date 2019-05-09 19:32
     */
    
    public class Girl implements Person{
    
        @Override
        public void findLove(){
            System.out.println("要求:是男的");
        }
    }
    
    /**
     * Description:代理
     *
     * @date 2019-05-13 19:53
     */
    
    public class SkyMeiPo implements SkyInvocationHandler{
    
        //被代理对象
        private Person target;
    
        //获取JDK代理
        public Object getInstance(Person person){
            this.target = person;
            Class<?> clazz = target.getClass();
            //根据被代理对象信息获取代理对象(被代理对象被代理对象"包裹")
            return SkyProxy.newProxyInstance(new SkyClassLoader(),clazz.getInterfaces(),this);
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            befor();
            Object obj =  method.invoke(this.target,args);
            after();
            return obj;
        }
    
        private void befor(){
            System.out.println("代理前置操作...");
    
        }
    
        private void after(){
            System.out.println("代理后置操作...");
        }
    }
    
    /**
     * Description:
     *
     * @date 2019-05-13 19:50
     */
    
    public class SkyProxy {
    
        private static final String LN = "\r\n";
    
        @CallerSensitive
        public static Object newProxyInstance(SkyClassLoader loader,
                                              Class<?>[] interfaces,
                                              SkyInvocationHandler h)
                throws IllegalArgumentException {
            
            try {
                //1.动态生成代码
                String src = generateSrc(interfaces);
                System.out.println(src);
                //2.java文件输出到磁盘
                String filePath = SkyProxy.class.getResource("").getPath();
                File f = new File(filePath+"$Proxy0.java");
                FileWriter fw = new FileWriter(f);
                fw.write(src);
                fw.flush();
                fw.close();
                //编译代码
                JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();//获取系统编译器
                StandardJavaFileManager manager = compiler.getStandardFileManager(null,null,null);
                Iterable iterable = manager.getJavaFileObjects(f);
                JavaCompiler.CompilationTask task = compiler.getTask(null,manager,null,null,null,iterable);
                task.call();
                manager.close();
    
                Class proxyClass = loader.findClass("$Proxy0");
                Constructor c = proxyClass.getConstructor(SkyInvocationHandler.class);
    
                return c.newInstance(h);
                
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
    
        }
    
    
        private static String generateSrc(Class<?>[] interfaces) {
            /*用代码写代码*/
            StringBuffer sb = new StringBuffer();
            //引包
            sb.append("package com.sky.designpattern.proxy.dynamicproxy.custom;").append(LN);
            sb.append("import com.sky.designpattern.proxy.dynamicproxy.jdk.Person;").append(LN);
            sb.append("import java.lang.reflect.Method;").append(LN);
            //类头
            sb.append("public class $Proxy0 implements ").append(interfaces[0].getName()).append("{").append(LN);
            //声明变量
            sb.append("SkyInvocationHandler h;").append(LN);
            //构造方法
            sb.append("public $Proxy0(SkyInvocationHandler h){").append(LN);
            sb.append("this.h=h;").append(LN);
            sb.append("}").append(LN);
    
            //反射生成方法
            for(Method m:interfaces[0].getMethods()){
                sb.append("public ").append(m.getReturnType().getName()).append(" ").append(m.getName()).append("(){").append(LN);
                    sb.append("try{").append(LN);
                        sb.append("Method m = ").append(interfaces[0].getName()).append(".class.getMethod(\""+m.getName()+"\",new Class[]{});").append(LN);
                        sb.append("this.h.invoke(this,m,null);").append(LN);
                    sb.append("}catch(Throwable e){").append(LN);
                        sb.append("e.printStackTrace();").append(LN);
                    sb.append("}").append(LN);
    
                sb.append("}").append(LN);
            }
    
            sb.append("}");
    
            return sb.toString();
        }
    }
    
    public interface SkyInvocationHandler {
    
        public Object invoke(Object proxy, Method method, Object[] args)
                throws Throwable;
    }
    
    public class SkyClassLoader extends ClassLoader{
    
        private File classPathFile;
    
    
        public SkyClassLoader() {
            String classPath = SkyClassLoader.class.getResource("").getPath();
            this.classPathFile = new File(classPath);
    
        }
    
        @Override
        protected Class<?> findClass(String name) throws ClassNotFoundException {
            String className = SkyClassLoader.class.getPackage().getName()+"."+name;
            if(classPathFile !=null){
                File classFile = new File(classPathFile,name.replaceAll("\\.","/")+".class");
                if(classFile.exists()){
                    FileInputStream in =null;
                    ByteArrayOutputStream out = null;
                    try{
                        in = new FileInputStream(classFile);
                        out = new ByteArrayOutputStream();
                        byte [] buff = new byte[1024];
                        int len;
                        while ((len = in.read(buff)) != -1){
                            out.write(buff,0,len);
                        }
                        return defineClass(className,out.toByteArray(),0,out.size());
                    }catch (Exception e){
    
                    }
    
                }
            }
            return null;
        }
    }
    
    
    

    3.2cglib动态代理

    3.2.1与JDK的区别

    1.JDK动态代理是通过反射实现,而cglib是通过生成被代理类的子类
        来实现
    2.cglib因为没用到反射效率更高
    3.不可代理 final类
    4.被代类不需要实现统一接口
    

    3.2.2代码实现

    /**
     * Description:被代理类
     *
     * @date 2019-05-22 20:11
     */
    
    public class Persion {
    
    
        public void  findLove(){
            System.out.println("肤白貌美大长腿");
        }
    
    }
    
    /**
     * Description:代理类
     *
     * @date 2019-05-22 20:01
     */
    
    public class MeiPo implements MethodInterceptor {
    
    
        public Object getInstance(Class<?> clazz) throws Exception{
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(clazz);
            enhancer.setCallback(this);
            return enhancer.create();
    
        }
    
        @Override
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            before();
            Object object = methodProxy.invokeSuper(o,objects);
            after();
            return object;
        }
    
        private void before(){
            System.out.println("before");
    
        }
        private void after(){
            System.out.println("after");
    
        }
    }
    /**
     * Description:测试类
     *
     * @date 2019-05-22 20:01
     */
    public class Test {
    
    
        public static void main(String[] args) {
    
                try {
                    Persion persion = (Persion) new MeiPo().getInstance(Persion.class);
                    persion.findLove();
                } catch (Exception e) {
                    e.printStackTrace();
                }
    
        }
    
    }
    

    相关文章

      网友评论

        本文标题:代理模式

        本文链接:https://www.haomeiwen.com/subject/hdehqctx.html