在分析動態代理回調的invoke
方法之前,我們先看下factory.create(UserDAO.class)
裏面做了什麼。
1.JadeFactory工廠分析
JadeFactory類的代碼如下:
public class JadeFactory {
private RowMapperFactory rowMapperFactory = new DefaultRowMapperFactory();
private DefaultInterpreterFactory interpreterFactory = new DefaultInterpreterFactory();
private DataAccessFactoryAdapter dataAccessFactory;
private CacheProvider cacheProvider;
// 可選的
private StatementWrapperProvider statementWrapperProvider;
public JadeFactory() {
}
public JadeFactory(DataSource defaultDataSource) {
setDataSourceFactory(new SimpleDataSourceFactory(defaultDataSource));
}
public JadeFactory(DataSourceFactory dataSourceFactory) {
setDataSourceFactory(dataSourceFactory);
}
public void setDataSourceFactory(DataSourceFactory dataSourceFactory) {
this.dataAccessFactory = new DataAccessFactoryAdapter(dataSourceFactory);
}
public void setCacheProvider(CacheProvider cacheProvider) {
this.cacheProvider = cacheProvider;
}
public DataSourceFactory getDataSourceFactory() {
if (this.dataAccessFactory == null) {
return null;
}
return this.dataAccessFactory.getDataSourceFactory();
}
public void setRowMapperFactory(RowMapperFactory rowMapperFactory) {
this.rowMapperFactory = rowMapperFactory;
}
public StatementWrapperProvider getStatementWrapperProvider() {
return statementWrapperProvider;
}
public void setStatementWrapperProvider(StatementWrapperProvider statementWrapperProvider) {
this.statementWrapperProvider = statementWrapperProvider;
}
public void addInterpreter(Interpreter... interpreters) {
for (Interpreter interpreter : interpreters) {
interpreterFactory.addInterpreter(interpreter);
}
}
@SuppressWarnings("unchecked")
public <T> T create(Class<?> daoClass) {
try {
DAOConfig config = new DAOConfig(dataAccessFactory, rowMapperFactory,
interpreterFactory, cacheProvider, statementWrapperProvider);
DAOMetaData daoMetaData = new DAOMetaData(daoClass, config);
JadeInvocationHandler handler = new JadeInvocationHandler(daoMetaData);
ClassLoader classLoader = ClassUtils.getDefaultClassLoader();
return (T) Proxy.newProxyInstance(classLoader, new Class[] { daoClass }, handler);
} catch (RuntimeException e) {
throw new IllegalStateException("failed to create bean for " + daoClass.getName(), e);
}
}
}
我們需要關注的是create()
方法:
public <T> T create(Class<?> daoClass) {
try {
DAOConfig config = new DAOConfig(dataAccessFactory, rowMapperFactory,
interpreterFactory, cacheProvider, statementWrapperProvider);
DAOMetaData daoMetaData = new DAOMetaData(daoClass, config);
JadeInvocationHandler handler = new JadeInvocationHandler(daoMetaData);
ClassLoader classLoader = ClassUtils.getDefaultClassLoader();
return (T) Proxy.newProxyInstance(classLoader, new Class[] { daoClass }, handler);
} catch (RuntimeException e) {
throw new IllegalStateException("failed to create bean for " + daoClass.getName(), e);
}
}
在create()
方法中:
1.新建了一個DAOConfig對象。DAOConfig的功能非常簡單,它僅僅用於封裝dataAccessFactory, rowMapperFactory,interpreterFactory, cacheProvider, statementWrapperProvider這4個對象,並提供對應的get方法,以供調用。
public class DAOConfig {
private final DataAccessFactory dataAccessFactory;
private final RowMapperFactory rowMapperFactory;
private final InterpreterFactory interpreterFactory;
private final CacheProvider cacheProvider;
private final StatementWrapperProvider statementWrapperProvider;
public DAOConfig(DataAccessFactory dataAccessFactory, //
RowMapperFactory rowMapperFactory, //
InterpreterFactory interpreterFactory, CacheProvider cacheProvider,
StatementWrapperProvider statementWrapperProvider) {
this.dataAccessFactory = dataAccessFactory;
this.rowMapperFactory = rowMapperFactory;
this.interpreterFactory = interpreterFactory;
this.cacheProvider = cacheProvider;
this.statementWrapperProvider = statementWrapperProvider;
}
public DataAccessFactory getDataAccessFactory() {
return dataAccessFactory;//標準數據訪問器配置
}
public InterpreterFactory getInterpreterFactory() {
return interpreterFactory;//SQL解析器配置
}
public RowMapperFactory getRowMapperFactory() {
return rowMapperFactory;//OR映射配置
}
public CacheProvider getCacheProvider() {
return cacheProvider;
}
public StatementWrapperProvider getStatementWrapperProvider() {
return statementWrapperProvider;
}
}
2.新建一個JadeInvocationHandler對象,這個handler對象就比較重要了,它是我們上次斷點跟進去的invoke()
方法所在的對象。它實現了InvocationHandler接口,這是典型的java動態代理創建過程。
一個典型的動態代理創建對象過程可分爲以下四個步驟:
1、通過實現InvocationHandler接口創建自己的調用處理器 IvocationHandler handler = new InvocationHandlerImpl(...);
2、通過爲Proxy類指定ClassLoader對象和一組interface創建動態代理類
Class clazz = Proxy.getProxyClass(classLoader,new Class[]{...});
3、通過反射機制獲取動態代理類的構造函數,其參數類型是調用處理器接口類型
Constructor constructor = clazz.getConstructor(new Class[]{InvocationHandler.class});
4、通過構造函數創建代理類實例,此時需將調用處理器對象作爲參數被傳入
Interface Proxy = (Interface)constructor.newInstance(new Object[] (handler));
爲了簡化對象創建過程,Proxy類中的newInstance方法封裝了2~4,只需兩步即可完成代理對象的創建。
生成的ProxySubject繼承Proxy類實現Subject接口,實現的Subject的方法實際調用處理器的invoke方法,而invoke方法利用反射調用的是被代理對象的的方法(Object result=method.invoke(proxied,args))
3.接下的代碼就是java動態代理創建過程。
這裏有一篇文章講得非常詳細http://www.cnblogs.com/flyoung2008/archive/2013/08/11/3251148.html
2.invoke方法分析
先貼出代碼:
/**
* DAO代理處理器(一個DAO類對應一個處理器實例)
*
* @author 王志亮 [[email protected]]
*
*/
public class JadeInvocationHandler implements InvocationHandler {
private static final Log logger = LogFactory.getLog(JadeInvocationHandler.class);
private static final Log sqlLogger = LogFactory.getLog("jade_sql.log");
private final ConcurrentHashMap<Method, Statement> statements = new ConcurrentHashMap<Method, Statement>();
private final DAOMetaData daoMetaData;
/**
*
* @param daoMetaData
*/
public JadeInvocationHandler(DAOMetaData daoMetaData) {
this.daoMetaData = daoMetaData;
}
/**
*
* @return
*/
public DAOMetaData getDAOMetaData() {
return daoMetaData;
}
private static final String[] INDEX_NAMES = new String[] { ":1", ":2", ":3", ":4", ":5", ":6",
":7", ":8", ":9", ":10", ":11", ":12", ":13", ":14", ":15", ":16", ":17", ":18", ":19",
":20", ":21", ":22", ":23", ":24", ":25", ":26", ":27", ":28", ":29", ":30", };
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
final boolean debugEnabled = logger.isDebugEnabled();
if (debugEnabled) {
logger.debug("invoking " + daoMetaData.getDAOClass().getName() + "#" + method.getName());
}
// 調用object的方法
if (method.getDeclaringClass() == Object.class) {
return invokeObjectMethod(proxy, method, args);
}
// 獲取當前DAO方法對應的Statement對象
Statement statement = getStatement(method);
//
// 將參數放入 Map
Map<String, Object> parameters;
StatementMetaData statemenetMetaData = statement.getMetaData();
if (args == null || args.length == 0) {
parameters = new HashMap<String, Object>(4);
} else {
parameters = new HashMap<String, Object>(args.length * 2 + 4);
for (int i = 0; i < args.length; i++) {
parameters.put(INDEX_NAMES[i], args[i]);
SQLParam sqlParam = statemenetMetaData.getSQLParamAt(i);
if (sqlParam != null) {
parameters.put(sqlParam.value(), args[i]);
}
}
}
// logging
if (debugEnabled) {
logger.info("invoking " + statemenetMetaData);
}
// executing
long begin = System.currentTimeMillis();
final Object result = statement.execute(parameters);
long cost = System.currentTimeMillis() - begin;
// logging
if (sqlLogger.isInfoEnabled()) {
sqlLogger.info(statemenetMetaData + "\tcost " + cost + "ms." );
}
return result;
}
private Statement getStatement(Method method) {
Statement statement = statements.get(method);
if (statement == null) {
synchronized (method) {
statement = statements.get(method);
if (statement == null) {
// config
DAOConfig config = daoMetaData.getConfig();
DataAccessFactory dataAccessFactory = config.getDataAccessFactory();
RowMapperFactory rowMapperFactory = config.getRowMapperFactory();
InterpreterFactory interpreterFactory = config.getInterpreterFactory();
CacheProvider cacheProvider = config.getCacheProvider();
StatementWrapperProvider wrapperProvider = config.getStatementWrapperProvider();
// create
StatementMetaData smd = new StatementMetaData(daoMetaData, method);
SQLType sqlType = smd.getSQLType();
Querier querier;
if (sqlType == SQLType.READ) {
RowMapper<?> rowMapper = rowMapperFactory.getRowMapper(smd);
querier = new SelectQuerier(dataAccessFactory, smd, rowMapper);
} else {
querier = new UpdateQuerier(dataAccessFactory, smd);
}
Interpreter[] interpreters = interpreterFactory.getInterpreters(smd);
statement = new JdbcStatement(smd, sqlType, interpreters, querier);
if (cacheProvider != null) {
statement = new CachedStatement(cacheProvider, statement);
}
if (wrapperProvider != null) {
statement = wrapperProvider.wrap(statement);
}
statements.put(method, statement);
}
}
}
return statement;
}
private Object invokeObjectMethod(Object proxy, Method method, Object[] args)
throws CloneNotSupportedException {
String methodName = method.getName();
if (methodName.equals("toString")) {
return JadeInvocationHandler.this.toString();
}
if (methodName.equals("hashCode")) {
return daoMetaData.getDAOClass().hashCode() * 13 + this.hashCode();
}
if (methodName.equals("equals")) {
return args[0] == proxy;
}
if (methodName.equals("clone")) {
throw new CloneNotSupportedException("clone is not supported for jade dao.");
}
throw new UnsupportedOperationException(daoMetaData.getDAOClass().getName() + "#"
+ method.getName());
}
@Override
public String toString() {
DAO dao = daoMetaData.getDAOClass().getAnnotation(DAO.class);
String toString = daoMetaData.getDAOClass().getName()//
+ "[catalog=" + dao.catalog() + "]";
return toString;
}
}
1.
這段代碼用於記錄日誌對我們分析沒什麼作用,忽略
2.
這個method對象UserDao對象的createTable()方法的反射對象(它的原理是java的反射機制),method.getDeclaringClass()
獲得的是UserDao的類對象,它顯然和Object的類對象不等。
debug信息如圖:
3.
可以推測這個getStatement(mehtod)
方法是我們這次分析的重頭戲,可以說核心工作就是在這裏完成的。因爲這裏是invoke中唯一 一個處理非Object類對象的method的方法,可以猜想@SQL("create table user (id int, name varchar(200));")
註解就是在這個方法內被處理後生成Statement對象的。這個方法內的分析我們留在下次進行。
4.
因爲void createTable();
的方法聲明中沒有參數,所以args爲null,所以這段代碼只是創建一個HashMap對象parameters。
5.最後final Object result = statement.execute(parameters);
執行SQL語句並返回結果。
這樣代理對象的回調方法就執行完畢了。