与动态代理不得不说的故事

      最近呢和动态代理发生了一些故事。从相识,到相知,到今天520,写写博客。算是对动态代理有一个交代。下一步转战rabbitMQ,没办法MQ和动态代理就没法比,因为就是两个东西。

     由于早早的就知道了动态代理的美名,所以特地针对它做了一番布置。基本上就是从简单,到复杂,到深入的这么一个过程。

1、从基本概念入手,多多了解,足够了解了才能好好的嘛。这部分主要是静态代理,还有动态代理的一些基本概念。

2、深入发展,参考一些论坛,博客,尤其是百度,看看动态代理都有哪些特质,动态代理的一些代码。多参考一些博客,不止看一篇博客,多看几篇,这样才会不至于自己理解的有所偏执。

3、打入内部,看看动态代理的源码部分。仍旧百度,博客,可以找一些书看看。深度随意。

4、动态代理是我的了,把自己的知识和动态代理糅杂在一起。这样就不容易分开了。结合自己所学,再找一些稍微复杂的demo,加强理解和应用。

5、带着动态代理溜溜去。带着动态代理的经典应用去看看框架里是怎么应用的。

静态代理

        我们为什么要采用代理模式呢,根据它的特点,我们知道代理对象可以实现面向切面的这种编程实现。那么一些公共的内容就可以放在代理对象的方法里,业务逻辑代码放在真正对象里,做到让程序员只关注业务实现,其他的类似事务处理,日志打印等程序员不必关心。

       下面先来个类图:在实现静态代理的过程中,我们需要建立一个真正对象,放在项目里也就是Service实现,也需要一个代理对象。最后在调用代理对象的方法。其中可以在代理对象方法中,嵌入非业务方法。比如事务的开启,提交或回滚。

public interface Action {
    void send(String str);
}

public class Person implements  Action{
    @Override
    public void send(String str) {
        System.out.println(str);
    }
}

public class ProxyPerson implements Action {
    private Action action;
    ProxyPerson(Action action){
        this.action = action;
    }
    @Override
    public void send(String str) {
        System.out.println("执行业务方法前:开启事务了");
        this.action.send(str);
        System.out.println("执行业务方法后:事务提交/回滚了");
    }
}

public class TestProxy {
    public static void main(String[] args) {
        Person person = new Person();
        ProxyPerson proxy = new ProxyPerson(person);
        proxy.send("论520与250的区别");
    }
}

    但是项目中有很多的Service,难道我们要建立很多代理对象吗?下面就来看看动态代理对象是怎么解决这个问题的,当然解决这个问题可以有各种各样的办法,但动态代理是目前最好的一种实现方法,为什么呢?因为好多框架都采用这种方式。

动态代理

       动态代理是静态代理的进一步实现,现在本人了解到的有jdk动态代理实现和cglib的动态代理实现。其中jdk动态代理是根据业务对象的接口,采用字节码动态生成一个动态代理类。而cglib采用继承的方式动态生成一个子类。jdk的实现,必须有一个

InvocationHandler的实现。


代码实现

public interface UserService {

    String getInfo();
}

public class UserServiceImpl implements  UserService {
    @Override
    public String getInfo() {
        return "Service 实现";
    }
}

public class MyInvocationHandler implements InvocationHandler {

    private Object target;
    MyInvocationHandler(Object target){
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        try{
            System.out.println("Service 实现前");
            System.out.println("方法名" + method.getName());
            Object result = method.invoke(target,args);
            System.out.println(result);
            System.out.println("Service 实现后");
            return result;
        }catch (Exception e){
          throw e;
        }

    }
}

测试代码

public class ProxyTest {

    public static void main(String[] args) throws Exception {
//            System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
        UserService service = new UserServiceImpl();
        MyInvocationHandler handler = new MyInvocationHandler(service);
        UserService infoService = (UserService) Proxy.newProxyInstance(
                service.getClass().getClassLoader(), service.getClass().getInterfaces(), handler);
        String info = infoService.getInfo();
        System.out.println(info);
        //以下方法是把动态类生成到文件里。
        byte[] proxyClass = ProxyGenerator.generateProxyClass(infoService.getClass()
                .getSimpleName(), infoService.getClass().getInterfaces());
        //将字节码文件保存到D盘,文件名为$Proxy0.class
        FileOutputStream outputStream = new FileOutputStream(new File(
                "d:\\$Proxy0.class"));
        outputStream.write(proxyClass);
        outputStream.flush();
        outputStream.close();
    }

接触jdk动态代理的源码

     一下是基于个人的理解,有所偏颇,还请指正。jdk动态代理是首先从缓存里获取动态代理类,如果没有的话,创建一个,然后放入缓存里。下次的话直接从缓存里获取吧。其中生成动态类的字节码是通过 ProxyGenerator.generateProxyClass方法生成。然后根据构造器的newInstance方法,返回动态代理类的实例。在阅读源码中的收获呢,其中知道了弱引用在这有用的,还有生成动态代理类的类名是$Proxy0,其中后面的这个0数字通过AtomicInteger进行的。知道了一些原子类类型的简单应用。加强了对动态代理的印象。下面看下动态代理类的代码。

public final class $Proxy0 extends Proxy implements UserService {
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m0;

    public $Proxy0(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 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 String getInfo() throws  {
        try {
            return (String)super.h.invoke(this, m3, (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", new Class[]{Class.forName("java.lang.Object")});
            m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
            m3 = Class.forName("com.ssm.proxy.UserService").getMethod("getInfo", new Class[0]);
            m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

      从上面构造函数,以及getInfo方法,我们就知道为什么一定需要InvocationHandler的实现类了。因为调用动态代理类的方法时,真正调用的其实是InvocationHandler的invoke方法。



猜你喜欢

转载自blog.csdn.net/wgp15732622312/article/details/80382829