设计模式(java)

代理模式

2019-06-19  本文已影响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();
            }

    }

}
上一篇下一篇

猜你喜欢

热点阅读