最近正在看Mybatis源码,重点研究了自定义Mapper接口里方法实现如何与xml配置文件进行绑定,最后了解到是通过java动态代理实现了接口方法。
主要使用了Proxy.newProxyInstance(loader, interfaces, invocationHandler方法来实现实例化,第一个参数为classLoader,第二个参数为要实例化的接口,第三个是InvocationHanler接口,需要实现此接口来实现方法的具体操作。例:
public void proxyTest() throws ClassNotFoundException,
InstantiationException, IllegalAccessException {
MethodProxy invocationHandler = new MethodProxy();
Object newProxyInstance = Proxy.newProxyInstance(
IUserService.class.getClassLoader(),
new Class[] { IUserService.class }, invocationHandler);
IUserService userService = (IUserService) newProxyInstance;
User query = userService.query();
System.out.println("query result->" + query.toString());
}
执行结果:
具体代码实现如下(仅为了说明实现方式,请忽略结构层次和命名规范):
public class MethodProxy implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
System.out.println("执行前");
if (Object.class.equals(method.getDeclaringClass())) {
try {
return method.invoke(this, args);
} catch (Throwable t) {
t.printStackTrace();
}
} else {
// System.out.println("调用方法名:"+method.getName());
return run(method, args);
}
System.out.println("执行后");
return null;
}
UserDao dao = null;
//具体实现通过方法名绑定。
public Object run(Method method,Object[] args){
if(dao == null){
dao = new UserDao();
}
Object ret = null;
String name = method.getName();
if(name.equals("add")){
dao.add(args);
}else if(name.equals("delete")){
dao.delete();
}else if(name.equals("query")){
ret = dao.query();
}
return ret;
}
class UserDao {
public void add(Object[] args){
System.out.println("dao add");
for (Object object : args) {
System.out.print(object+",");
}
}
public void delete(){
System.out.println("dao delete");
}
public User query(){
return new User("123", "济南", 22, "备注");
}
}
}
public interface IUserService {
public void add(User user);
public User query();
public void delete(int id);
}
public class User {
private String id;
private String username;
private int age;
private String remarks;
public User(String id, String username, int age, String remarks) {
super();
this.id = id;
this.username = username;
this.age = age;
this.remarks = remarks;
}
……
@Override
public String toString() {
return "User [id=" + id + ", username=" + username + ", age=" + age
+ ", remarks=" + remarks + "]";
}
}
本demo所展示的是具体接口的实现方法,为保证通用性,则可通过泛型实现接口实例化的通用方法。 (参考mybatis-src)
例地: