代理模式

  1. 定义 为其他对象提供一种代理以控制对这个对象的访问。
  2. 本质 控制对象访问
  3. 实例 以歌星为例:歌星的合作过程 面谈,签合同,唱歌,收尾款 其实有些步骤不需要明星亲自去做 比如面谈,签合同,收尾款。明星只需要唱歌即可。其他交由经纪人去做!

静态代理实现:

Star 歌星

/**
 * 歌星
 * @author lijun
 * @since 2018-03-12 14:12
 */
public interface Star {


    /**
     * 面谈
     */
    void confer();

    /**
     * 签合同
     */
    void signContract();

    /**
     * 唱歌
     */
    void  sing();

    /**
     * 收尾款
     */
    void collectMoney();
}

JackyCheung 具体的歌星张学友

/**
 * 张学友
 * @author lijun
 * @since 2018-03-12 14:14
 */
public class JackyCheung implements Star {
    /**
     * 面谈
     */
    @Override
    public void confer() {

    }

    /**
     * 签合同
     */
    @Override
    public void signContract() {

    }

    /**
     * 唱歌
     */
    @Override
    public void sing() {
        System.out.println("张学友唱歌。。。。");
    }

    /**
     * 收尾款
     */
    @Override
    public void collectMoney() {

    }
}

经纪人

/**
 * 经纪人
 * @author lijun
 * @since 2018-03-12 14:18
 */
public class Agent implements Star{


    private Star star;


    public Agent(Star star) {
        this.star = star;
    }

    /**
     * 面谈
     */
    @Override
    public void confer() {
        System.out.println("经纪人代表面谈!");
    }

    /**
     * 签合同
     */
    @Override
    public void signContract() {
        System.out.println("经纪人代表签合同!");
    }

    /**
     * 唱歌
     */
    @Override
    public void sing() {
        star.sing();
    }

    /**
     * 收尾款
     */
    @Override
    public void collectMoney() {
        System.out.println("经纪人代表收尾款!");
    }
}

只有唱歌 需要具体的明星来做!其他都交由经纪人来做!

调用:

 public void sing(){
        Star star = new JackyCheung();
        Agent agent = new Agent(star);
        agent.confer();
        agent.signContract();
        agent.sing();
        agent.collectMoney();
    }

输出:

经纪人代表面谈!
经纪人代表签合同!
张学友唱歌。。。。
经纪人代表收尾款!

用JDK动态代理实现

/**
 * 动态代理的经纪人
 * @author lijun
 * @since 2018-03-12 14:57
 */
public class AgentDynamic implements InvocationHandler{
    private Star star;

    /**  获取代理对象
     * @param target star
     * @return Object
     */
  public Object getInstance(Star target){
      this.star = target;
      Class<? extends Star> aClass = target.getClass();
      return Proxy.newProxyInstance(aClass.getClassLoader(),aClass.getInterfaces(),this);
  }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
          Object object = null;
        String name = method.getName();
         if (name.equals("sing")){
             System.out.println("经纪人代表面谈!");
             System.out.println("经纪人代表签合同!");
             object =  method.invoke(star, args);
             System.out.println("经纪人代表收尾款!");
         }
        return object;
    }
}

调用:

 public void singDynamic(){
        AgentDynamic agentDynamic = new AgentDynamic();
        Star star  = (Star)agentDynamic.getInstance(new JackyCheung());
        System.out.println(star.getClass());
        star.sing();
    }

输出:

class com.sun.proxy.$Proxy4
经纪人代表面谈!
经纪人代表签合同!
张学友唱歌。。。。
经纪人代表收尾款!

上面看到生成的代理类名字为$Proxy4 里面的类容是什么呢!我可以把类容写到磁盘!
修改测试方法把类写到磁盘!

  public void singDynamic(){
        AgentDynamic agentDynamic = new AgentDynamic();
        Star star  = (Star)agentDynamic.getInstance(new JackyCheung());
        System.out.println(star.getClass());
        star.sing();
        byte[] bytes = ProxyGenerator.generateProxyClass("$Proxy4", new Class[]{Star.class});
        try {
            FileOutputStream fileOutputStream = new FileOutputStream("E:\\$Proxy4.class");
            fileOutputStream.write(bytes);
            fileOutputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

反编译 $Proxy4.class 得到:

import com.junli.staticed.Star;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy4 extends Proxy implements Star {
    private static Method m1;
    private static Method m4;
    private static Method m6;
    private static Method m2;
    private static Method m3;
    private static Method m5;
    private static Method m0;

    public $Proxy4(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return ((Boolean)super.h.invoke(this, m1, new Object[]{var1})).booleanValue();
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final void signContract() throws  {
        try {
            super.h.invoke(this, m4, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void collectMoney() throws  {
        try {
            super.h.invoke(this, m6, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void confer() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void sing() throws  {
        try {
            super.h.invoke(this, m5, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final int hashCode() throws  {
        try {
            return ((Integer)super.h.invoke(this, m0, (Object[])null)).intValue();
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m4 = Class.forName("com.junli.staticed.Star").getMethod("signContract");
            m6 = Class.forName("com.junli.staticed.Star").getMethod("collectMoney");
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m3 = Class.forName("com.junli.staticed.Star").getMethod("confer");
            m5 = Class.forName("com.junli.staticed.Star").getMethod("sing");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

可以看出生成类的过程,可以看到JDK动态代理的原理:
1、拿到被代理对象的引用,并且获取到它的所有的接口,反射获取
2、JDK Proxy类重新生成一个新的类、同时新的类要实现被代理类所有实现的所有的接口
3、动态生成Java代码,把新加的业务逻辑方法由一定的逻辑代码去调用(在代码中体现)
4、编译新生成的Java代码.class
5、再重新加载到JVM中运行

知道原理了我们就可以自己实现JDK动态代理的功能!其实关键就是Proxy代理类的实现!实现如下:

自定义的动态代理实现

LIInvocationHandler 自定义的InvocationHandler

/**
 * 自定义的InvocationHandler
 * @author lijun
 * @since 2018-03-12 17:02
 */
public interface LIInvocationHandler {
    /**
     *
     * @param proxy proxy
     * @param method method
     * @param args args
     * @return
     * @throws Throwable
     */
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable;
}

LIClassLoader 自定义类加载器

/**
 *  
 * @author lijun
 * @since 2018-03-12 17:59
 */
public class LIClassLoader extends ClassLoader{

    private File classPathFile;

    public LIClassLoader(){
        String classPath = LIClassLoader.class.getResource("").getPath();
        this.classPathFile = new File(classPath);
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        {

            String className = LIClassLoader.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){
                        e.printStackTrace();
                    }finally {
                        if(null != in){
                            try {
                                in.close();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }

                        if(out != null){
                            try {
                                out.close();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }

            }

            return null;

        }
    }

}

LIProxy 自定义的代理类

/**
 * 自己的代理类
 * @author lijun
 * @since 2018-03-12 17:58
 */
public class LIProxy {

    public static final String ln = "\r\n";

    public static Object newProxyInstance(LIClassLoader classLoader, Class<?>[] interfaces, LIInvocationHandler h) {
        try {
            //1、动态生成源代码.java文件
            String src = generateSrc(interfaces);
            //2、Java文件输出磁盘
            String filePath = LIProxy.class.getResource("").getPath();
            System.out.println(filePath);
            File f = new File(filePath + "$Proxy4.java");
            FileWriter fw = new FileWriter(f);
            fw.write(src);
            fw.flush();
            fw.close();

            //3、把生成的.java文件编译成.class文件
            JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
            StandardJavaFileManager manage = compiler.getStandardFileManager(null, null, null);
            Iterable iterable = manage.getJavaFileObjects(f);

            JavaCompiler.CompilationTask task = compiler.getTask(null, manage, null, null, null, iterable);
            task.call();
            manage.close();

            //4、编译生成的.class文件加载到JVM中来
            Class proxyClass = classLoader.findClass("$Proxy4");
            Constructor c = proxyClass.getConstructor(LIInvocationHandler.class);
            //f.delete();

            //5、返回字节码重组以后的新的代理对象
            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.junli.custom;" + ln);
        sb.append("import com.junli.staticed.Star;" + ln);
        sb.append("import java.lang.reflect.Method;" + ln);
        sb.append("public class $Proxy4 implements " + interfaces[0].getName() + "{" + ln);

        sb.append("LIInvocationHandler h;" + ln);

        sb.append("public $Proxy4(LIInvocationHandler h) { " + ln);

        sb.append("this.h = h;");

        sb.append("}" + ln);


        for (Method m : interfaces[0].getMethods()){
            sb.append("public " + m.getReturnType().getName() + " " + m.getName() + "() {" + ln);
            sb.append("try{" + ln);
            sb.append("Method m = " + interfaces[0].getName() + ".class.getMethod(\"" + m.getName() + "\",new Class[]{});" + ln);
            sb.append("this.h.invoke(this,m,null);" + ln);
            sb.append("}catch(Throwable e){" + ln);
            sb.append("e.printStackTrace();" + ln);
            sb.append("}");
            sb.append("}");
        }

        sb.append("}" + ln);

        return sb.toString();
    }
}

AgentCustomDynamic 自定义 动态代理的经纪人

/**
 *自定义 动态代理的经纪人
 * @author lijun
 * @since 2018-03-12 14:57
 */
public class AgentCustomDynamic implements LIInvocationHandler{
    private Star star;

    /**  获取代理对象
     * @param target star
     * @return Object
     */
  public Object getInstance(Star target){
      this.star = target;
      Class<?> aClass = target.getClass();
      return LIProxy.newProxyInstance(new LIClassLoader(),aClass.getInterfaces(),this);
  }

    /**
     * 参数:
     *proxy 被代理的对象
     *method 被代理对象的方法
     *args 方法的参数
     * 返回:
     *Object 方法返回值
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object object = null;
        String name = method.getName();
         if (name.equals("sing")){
             System.out.println("经纪人代表面谈!");
             System.out.println("经纪人代表签合同!");
             object =  method.invoke(star, args);
             System.out.println("经纪人代表收尾款!");
         }
        return object;
    }
}

调用

@Test
    public void singCustom() {
        AgentCustomDynamic agentCustomDynamic = new AgentCustomDynamic();
        Star star  = (Star)agentCustomDynamic.getInstance(new JackyCheung());
        System.out.println(star.getClass());
        star.sing();
    }

输出

class com.junli.custom.$Proxy4
经纪人代表面谈!
经纪人代表签合同!
张学友唱歌。。。。
经纪人代表收尾款!

实现了动态代理的功能!

Cglib 实现

/**
 * Cglib动态代理实现
 * @author lijun
 * @since 2018-03-12 16:11
 */
public class AgentCglib implements MethodInterceptor {

    /**
     *
     * @param clazz clazz 被代理类的具体实现类
     * @return Object
     */
    public Object getInstance(Class<?> clazz){
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);
       return enhancer.create();
    }
    /**
     * 拦截所有目标类方法的调用
     * 参数:
     * obj目标实例对象
     *method 目标方法的反射对象
     * args方法的参数
     * proxy代理类的实例
     */
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        Object object = null;

        String name = method.getName();
        if (name.equals("sing")){
            System.out.println("经纪人代表面谈!");
            System.out.println("经纪人代表签合同!");
            object =  methodProxy.invokeSuper(o, objects);
            System.out.println("经纪人代表收尾款!");
        }
        return object;
    }
}

调用

    @Test
    public void singCglib() {
        AgentCglib agentCglib = new AgentCglib();
        Star star  = (Star)agentCglib.getInstance(JackyCheung.class);
        System.out.println(star.getClass());
        star.sing();
    }
     @Test
    public void singCglib() {
        AgentCglib agentCglib = new AgentCglib();
        Star star  = (Star)agentCglib.getInstance(JackyCheung.class);
        System.out.println(star.getClass());
        star.sing();
    }

输出:

class com.junli.staticed.JackyCheung$$EnhancerByCGLIB$$89c7b75a
经纪人代表面谈!
经纪人代表签合同!
张学友唱歌。。。。
经纪人代表收尾款!

代理模式学习完毕!

源码地址

posted on 2018-03-13 13:17  未亦末  阅读(142)  评论(0编辑  收藏  举报