动态代理是个什么梗

前言

半年前,我还一直在用JDBC,见笑了。用了一次mybatis发现山里人进城了。哎,土渣渣啊!嗯…,动态代理和mybatis难道偷情了,前言不搭后语啊!如果真是这样,请看下去。哪些玩的很niu(一声)的spring-dog,竟不不晓得动态代理是个啥子玩意,那…

  • 代理模式
  • 动态代理

代理设计模式

代理模式是JAVA23种设计模式中的一种。来个梗:n年前面试,问我java设计模式,我说了贫血模式,人家弱弱的问问什么是贫血模式,我说就是定义的类只有属性和set,get方法。差点被喷一脸,哈哈!
言归正传,我不是来说设计模式的,不清楚的自行补脑。下面的代码是会涉及到代理模式。

动态代理

动态代理是JAVA第24种设计模式,嗯,啊,呸。动态代理顾名思义动态的任命代理。概念免了。

看看mybatis先

用过mybatis的spring-dog都晓得,自己写dao层,只需要定义一个接口以及对应的mapper.xml文件。就一个接口和sql就可以查出来数据了?好神器!
但是西北大学的JAVA讲师讲的都是如下:

interface ExampleBABA{
  void execute();
}
final class Example implements ExampleBABA{
  @Override
  void execute(){
  }
}
Example example = new Example();
example.execute();

//或者如下
(new ExampleBABA{
   @Override
  void execute(){
  }
}).execute();

再来一个梗让大家乐呵乐呵,还是面试^_^,我说过所有类都可以实例化,好尴尬。
回头看,如上,不都是通过实现接口,或者生成匿名内部类对象,来调用重写过的方法么。mybatis我们都么写接口的实现,咋调用的?mybatis框架咋整的?有人可能会说,通过ASM字节码操作么,框架自动生成实现类。请这些大爷出门右转不送。咱今身体特别不适,伺候不了各位大爷。
说的就是动态代理,除了他还有谁?
这里写图片描述
这就是java提供的动态代理方法,细看样例代码吧!

package test.com;

public interface Test {

    void init();
    void execute();
}
package test.com;

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

public class Main {

    public static void main(String[] args) {

        //动态代理使用方式
        Test test = (Test) Proxy.newProxyInstance(Test.class.getClassLoader(), new Class[] {Test.class}, new InvocationHandler() {

            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                // TODO Auto-generated method stub

                System.out.println("方法[" + method + "]执行了");
                return null;
            }
        });

        test.execute();
        try {

            Thread.sleep(1000*5);
        } catch (Exception e) {
            // TODO: handle exception
        }
        System.out.println("-----------------");
        test.init();
    }
}

invoke

参数 :

参数对象 价格
ClassLoader Test.class.getClassLoader()
Class new Class[] {Test.class}
InvocationHandler InvocationHandler匿名内部类

classload为加载test的classload。
class为传入的接口。
InvocationHandler 传说种的代理。

newProxyInstance

参数 :

参数对象 价格
Object proxy
Method method
Object[] args

proxy代理实例,就是类似于 new TestImpl(); 都说这个参数么用,仁者见仁智者见智吧。最起码可以递归啊!^_^
method Test种的对象的方法的反射对象。
args Test某方法的参数

其实际就类似于下面的代码

package test.com;

public class TestImpl implements Test{

    @Override
    public void init() {
        // TODO Auto-generated method stub

    }

    @Override
    public void execute() {
        // TODO Auto-generated method stub

    }

}

package test.com;
//我是代理 我光荣  Test对外是不可见的
public class TestInvocationHandler {

    private Test test = new TestImpl();
    void invoke(String method) {

        if(method.equals("init")) {

            test.init();
        }else if(method.equals("execute")) {
            test.execute();
        }
    }
}
package test.com;

public class Main2 {

    public static void main(String[] args) {

        TestInvocationHandler handler = new TestInvocationHandler();
        handler.invoke("init");
    }
}

动态代理代码执行结果
这里写图片描述
执行结果可以说明的是不管代理对象调用那个种的方法实质都是执行的是代理的invoke方法

嗯…了解了动态代理,该知道mybatis只要一个接口就可以帮你处理数据了。
额…还不懂,简单样例,如下,和mybatis源码没有任何毛关系,只是模仿,模仿。

package test.com;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

public class CCYCCMyBatis {

    Map<String, String> sqlCahe = new HashMap<>();
    void inite() {

        this.loadMapperXml();
    }
    private void loadMapperXml(){

        String init = "select * from init";
        String execute = "select * from execute";
        sqlCahe.put("init", init);
        sqlCahe.put("execute", execute);
    }

    void select(String name) {

        String url = null;
        String user = null;
        String password = null;
        try {
            Connection conn = DriverManager.getConnection(url, user, password);
            PreparedStatement ps = conn.prepareStatement(sqlCahe.get(name));
            ResultSet rs = ps.executeQuery();
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

package test.com;

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

public class Main {

    public static void main(String[] args) {

        Test test = (Test) Proxy.newProxyInstance(Test.class.getClassLoader(), new Class[] {Test.class}, new InvocationHandler() {

            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                // TODO Auto-generated method stub

                System.out.println("方法[" + method + "]执行了");

                CCYCCMyBatis ccyccMyBatis = new CCYCCMyBatis();
                //mybatis根据方法对应的sql进行操作
                ccyccMyBatis.select(method.getName());
                return null;
            }
        });

        test.execute();
        try {

            Thread.sleep(1000*5);
        } catch (Exception e) {
            // TODO: handle exception
        }
        System.out.println("-----------------");
        test.init();
    }
}

其实。mybatis底层非常复杂,有兴趣的可以研究研究。
说了这么多,就是一个接口就把活干了,哎!spring真是把很多人用傻&逼了。

转载请注明来源!


加微信,多交流
这里写图片描述

猜你喜欢

转载自blog.csdn.net/ccycc88/article/details/79759172