前言
半年前,我还一直在用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真是把很多人用傻&逼了。
转载请注明来源!
加微信,多交流