简单创建代理工厂
一般对于JDBC来说,无非就是连接数据库、查询数据库、封装实体、返回实体,如果要设计一个ORM框架的话也就是要考虑怎么把用户自定义的数据库操作接口、XML中的SQL语句、数据库三者给联系起来,其实最适合的操作就是代理,使用代理的方式来进行处理,因为代理可以封装一个复杂的流程为借口对象的实现类。
这张图描述了一个使用代理模式的流程,主要涉及IUserDao
接口及其代理对象的创建和调用。以下是详细解释:
-
IUserDao 接口:
- 该接口定义了一个方法
queryUserName()
,用于查询用户名。
- 该接口定义了一个方法
-
MapperProxyFactory:
- 这是一个代理工厂类,用于创建代理对象。它根据
IUserDao
接口生成相应的代理。
- 这是一个代理工厂类,用于创建代理对象。它根据
-
MapperProxy:
- 这是实际的代理类。
MapperProxyFactory
会创建一个MapperProxy
实例,该实例包装了IUserDao
的具体操作。 MapperProxy
接收到方法调用后,会拦截并处理这些调用。
- 这是实际的代理类。
-
代理对象:
- 由
MapperProxyFactory
创建的代理对象,实现了IUserDao
接口,并会将queryUserName()
的调用代理给MapperProxy
处理。
- 由
-
实际调用:
- 当你调用代理对象的
queryUserName()
方法时,实际上是由MapperProxy
进行处理的,它包装了具体的 Mapper 操作。
- 当你调用代理对象的
-
包装 Mapper 操作:
MapperProxy
内部会包装具体的 Mapper 操作,比如执行 SQL 查询等,从而实现queryUserName()
的功能。
这个流程图展示了如何通过代理工厂和代理模式,动态创建 IUserDao
接口的代理对象,并通过代理对象来处理接口方法的调用,从而实现接口的具体操作。
首先是IUserDao
package com.hayaizo.test.dao;
public interface IUserDao {
String queryUserName(String uid);
String queryUserAge(String uid);
}
映射器代理类
package com.hayaizo.binding;
import java.io.Serializable;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Map;
/**
* 映射器代理类
* 实现了 InvocationHandler 接口和 Serializable 接口
*/
public class MapperProxy<T> implements InvocationHandler, Serializable {
// 序列化版本号,用于反序列化时的一致性校验
private static final long serialVersionUID = -238941387264L;
// SQL 会话,用于存储 SQL 映射,现在用Map模拟
private Map<String, String> sqlSession;
// 被代理的接口类
private final Class<T> mapperInterface;
/**
* 构造方法
*
* @param sqlSession SQL 会话
* @param mapperInterface 被代理的接口类
*/
public MapperProxy(Map<String, String> sqlSession, Class<T> mapperInterface) {
this.mapperInterface = mapperInterface;
this.sqlSession = sqlSession;
}
/**
* 代理方法的实际调用处理逻辑
*
* @param proxy 代理对象
* @param method 被调用的方法
* @param args 方法参数
* @return 方法调用的结果
* @throws Throwable 可能抛出的异常
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 如果方法是 Object 类的方法,直接调用
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
} else {
// 否则,通过 sqlSession 获取对应的 SQL 语句,并返回
// 这里返回一个字符串,表示被代理的方法被调用
return "你被代理了!" + sqlSession.get(mapperInterface.getName() + "." + method.getName());
}
}
}
映射器工厂
package com.hayaizo.binding;
import java.lang.reflect.Proxy;
import java.util.Map;
/**
* 映射器的代理工厂
*/
public class MapperProxyFactory<T> {
private final Class<T> mapperInterface;
public MapperProxyFactory(Class<T> mapperInterface) {
this.mapperInterface = mapperInterface;
}
public T newInstance(Map<String,String> sqlSession) {
//提供一个代理类
MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession,mapperInterface);
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[]{mapperInterface}, mapperProxy);
}
}
测试方法
package com.hayaizo.test.dao;
import com.hayaizo.binding.MapperProxyFactory;
import org.junit.Test;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;
public class ApiTest {
@Test
public void test_proxy_class(){
IUserDao userDao = (IUserDao) Proxy.newProxyInstance(
Thread.currentThread().getContextClassLoader(),
new Class[]{IUserDao.class},
(proxy, method, args) -> {
if ("queryUserName".equals(method.getName())) {
return "你被代理了"+" args= "+args[0];
} else if ("queryUserAge".equals(method.getName())) {
return "18";
}
return method.invoke(this,args);
}
);
String res = userDao.queryUserName("1");
String res1 = userDao.queryUserAge("1");
System.out.println(res);
System.out.println(res1);
}
@Test
public void test_MapperProxyFactory(){
MapperProxyFactory<IUserDao> mapperProxyFactory = new MapperProxyFactory<>(IUserDao.class);
Map<String,String> sqlSession = new HashMap<>();
//com.hayaizo.test.dao.IUserDao
sqlSession.put("com.hayaizo.test.dao.IUserDao.queryUserName","模拟执行Mapper.xml中的SQL语句,操作:查询用户名称");
IUserDao userDao = mapperProxyFactory.newInstance(sqlSession);
String string = userDao.queryUserName("1");
System.out.println(string);
}
}
运行结果: