猿思考系列5——代理之明白java和微商那点儿事儿

看完上一个章节,相信你已经掌握了一些编写并发代码编写的要领了。今天我们来聊一个新的话题。

猿思考是一个原创系列文章,帮助你从一个小白快速掌握基础知识,很多基础知识,在于思考的变通,更多精彩内容,敬请大家关注公主号猿人工厂,点击猿人养成获取

猿思考系列5——代理之明白java和微商那点儿事儿_第1张图片

猿思考系列5——代理之明白java和微商那点儿事儿_第2张图片

猿思考系列5——代理之明白java和微商那点儿事儿_第3张图片

猿思考系列5——代理之明白java和微商那点儿事儿_第4张图片

猿思考系列5——代理之明白java和微商那点儿事儿_第5张图片

猿思考系列5——代理之明白java和微商那点儿事儿_第6张图片

猿思考系列5——代理之明白java和微商那点儿事儿_第7张图片

猿思考系列5——代理之明白java和微商那点儿事儿_第8张图片

猿思考系列5——代理之明白java和微商那点儿事儿_第9张图片

猿思考系列5——代理之明白java和微商那点儿事儿_第10张图片

开动你的小脑筋,你怎样才能代替我去卖面膜?先看下面的代码,卖面膜是一种行为,定义成一个接口,MaiMianMo,还有一个实现类MaiMianMoImpl,具体怎么卖面膜由MaiMianMoImpl去做。

package com.pz.se.demo;

public interface MaiMianMo {

    public Object maiMianMo(Object obj);
}

packagecom.pz.se.demo;

public class MaiMianMoImpl implements MaiMianMo {

    @Override
    public Object maiMianMo(Object obj) {
        System.out.println("我正在售卖 面米:"+obj);
        return obj;
    }
}

嗯,你的意思是代替你去卖面膜,这还不简单,编写一个类实现MaiMianMo接口,代替你嘛,我就是你的代理,我直接在新的类中使用MaiMianMoImpl的方法就好了,名字嘛就叫MaiMianMoProxy好了,talk is cheap show me your code…

package com.pz.se.demo;

public class MaiMianMoProxyimplements MaiMianMo {

   private MaiMianMo maiMianMoImpl = new MaiMianMoImpl();

   @Override
   public Object maiMianMo(Object obj) {
        System.out.println("我是微商,我卖面膜");
        return maiMianMoImpl.maiMianMo(obj);
   }

   public static void main(String args[]){

        MaiMianMo maiMianMo = newMaiMianMoProxy();
        maiMianMo.maiMianMo(new Object());

   }
}

猿思考系列5——代理之明白java和微商那点儿事儿_第11张图片

猿思考系列5——代理之明白java和微商那点儿事儿_第12张图片

猿思考系列5——代理之明白java和微商那点儿事儿_第13张图片

所谓动态代理,是指利用Java的反射技术(JavaReflection)生成字节码,在运行时创建一个新的类给指定接口或接口引用,从而实现代理了或接口的职责。

JDK提供了动态代理,都在Java.lang.reflect包下,一个接口InvocationHandler,一个类Proxy。

InvocationHandler:该接口中仅定义了一个方法Object:invoke(Object obj,Method method,Object[] args)。在实际使用时,第一个参数obj一般是指代理类,method是被代理的方法,args为该方法的参数数组。这个抽象方法在代理类中动态实现。

Proxy类就是动态代理类,用于在程序运行时,生产生产代理对象。我们可以看下使用JDK的动态代理,来帮助我们成为微商,售卖面膜。

第一步,实现InvocationHandler接口。

package com.pz.se.demo;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class MaiMianMoInvocationHandler implements InvocationHandler {

    private MaiMianMo  maiMianMo;

    publicMaiMianMoInvocationHandler(MaiMianMo maiMianMo) {
        this.maiMianMo = maiMianMo;
    }

    @Override
    public Object invoke(Object proxy, Methodmethod, Object[] args) throws Throwable {
        //微商嘛自然喜欢干点别的事情

        //做还是不做都在于你
        Object invoke =method.invoke(maiMianMo, args);

        System.out.println("我是微商我想干嘛干嘛的");

        System.out.println("我甚至不调用你能拿我怎样?");

        System.out.println("到了我手里我想干嘛就干嘛的");

        return invoke;
    }
}

第二步,使用Proxy类生产代理对象,然后调用就好。

package com.pz.se.demo;

importjava.lang.reflect.Proxy;

public classTestProxyMaiMianMo {

    public static void main(String args[]){

        MaiMianMoInvocationHandler handler =new MaiMianMoInvocationHandler(new MaiMianMoImpl());
        MaiMianMo maiMianMo= (MaiMianMo)Proxy.newProxyInstance(MaiMianMo.class.getClassLoader(),newClass[]{MaiMianMo.class},handler);

        maiMianMo.maiMianMo(new Object());
    }
}

猿思考系列5——代理之明白java和微商那点儿事儿_第14张图片

猿思考系列5——代理之明白java和微商那点儿事儿_第15张图片

根据JDK提供的动态代理,看起来只是针对接口来说的,我们可以想想一下,代理到底是什么?无非是代替某个类的功能而已,一个类有属性和方法,那么编写一个类继承要实现的类不就好了?结合反射来看,可以拿到太多的信息了,无非输出一个源程序文件,然后吧,假如编译了呢?然后吧,编译,然后加载然后创建了对象了呢?下面就是个例子稍微改改,妙用无穷噢。

public class ProxyUtil {

    public static Object proxyClass(Class clazz){

        String packageNam=clazz.getPackage().getName();

         return null;

    }
    private static StringappendPackageStr(Class clazz){
        return "package "+clazz.getPackage().getName()+";\n";
    }

    private static StringappendClassBodyBegin(Class clazz){
        return "public class "+clazz.getSimpleName()+"Proxy extends " +clazz.getName()+"{\n";
    }

    private static String getFileName(Class clazz){
        returnclazz.getSimpleName()+"Proxy.java";

    }

    private static String appendClassBodyEnd(){
        return "}\n";
    }

    private static String appendImports(Classclazz) {
        StringBuilder builder = newStringBuilder();
        for( Method method:clazz.getDeclaredMethods()){

            Class[] parameterTypes=method.getParameterTypes();

            for(Class param:parameterTypes){
                builder.append("import "+param.getName()+";\n");
            }
        }

       return builder.toString();
    }

    private static String appendMethod(Methodmethod,String codes) {

        StringBuilder builder = newStringBuilder();

        builder.append("public ");

       builder.append(method.getReturnType().getName() +" ");

        builder.append(method.getName()+"");

        builder.append("( ");

        Class[] parameterTypes=method.getParameterTypes();
        for(int i =0;i

猿思考系列5——代理之明白java和微商那点儿事儿_第16张图片

以上的方式都是运行时期来生产代理类的。当然除了jdk的代理之外,还有很多工具也可以做到这一点。比如经常提到的开源项目cglib,ASM,Javassist,这些框架能够更容易的做到,在运行时期,扩展一个类,总比咱自己JDK硬写编译要强吧?

那还有没有是什么时候可以做手脚去扩展一个代理类出来呢?我们之前学过java代码的执行套路,一个代码需要执行,是需要编译的吧?我们也可以在编译时期做一些手脚嘛,反正原理无非就是,读取一个类的内容,然后加入自己想加入的内容就好了。Java也有一些开源项目,比如AspectJ可以轻松的做到这一点。

介于篇幅,以上的开源项目的使用,我就暂时不做展示了。后续的内容,我会给出例子的。

不过最重要的一点需要记住,代理后,做任何事情都可以,被代理的方法只关心返回值,要不你可能学AOP只能停留在打日志的阶段了噢。

你可能感兴趣的:(java,spring,springboot,java-web,java-ee)