GreenDAO基本使用及源码分析
GreenDAO介绍
GreenDAO is a light & fast ORM for Android that maps objects to SQLite databases. Being highly optimized for Android, greenDAO offers great performance and consumes minimal memory.
GreenDAO是为Android系统开发的一个轻量级且快速的ORM(对象/关系映射),它可以将对象映射到SQLite数据库。GreenDAO针对Android系统做了高度优化,提供了出色的性能,并且占用非常少内存。
GreenDAO通过ORM,使开发者可以使用简单的面向对象API来进行数据库操作,提高了开发效率。
GreenDAO基本使用
添加依赖
在根build.gradle
中:
buildscript {
dependencies {
classpath 'com.android.tools.build:gradle:3.5.3'
classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2' // add plugin
}
}
在module的build.gradle
中:
apply plugin: 'com.android.application'
apply plugin: 'org.greenrobot.greendao' // apply plugin
dependencies {
implementation 'org.greenrobot:greendao:3.2.2' // add library
}
创建存储对象实体类
@Entity
public class Student {
int studentId;
int age;
}
Gradle同步之后,会指定生成该实体类的set/get
函数
@Entity
public class Student {
int studentId;
int age;
String name;
@Generated(hash = 574930005)
public Student(int studentId, int age, String name) {
this.studentId = studentId;
this.age = age;
this.name = name;
}
@Generated(hash = 1556870573)
public Student() {
}
public int getStudentId() {
return this.studentId;
}
public void setStudentId(int studentId) {
this.studentId = studentId;
}
public int getAge() {
return this.age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
}
同时,会自动生成下面几个类:
下面是这几个类的作用:
- DaoMaster:GreenDao的总入口,负责整个库的运行,其内部类OpenHelper和DevOpenHelper是SQLiteOpenHelper实现
- DaoSession:会话层,操作Dao的具体对象,包括DAO对象的注册
- xxDao:根据每个实体生成的DAO对象,进行具体的数据库操作
- xxEntity:实体类,和表内容一一对应
下面的UML图可以更清晰理清这几个类的关系:
GreenDAO初始化
可以在Application中进行初始化操作,以便在整个APP中维持一个全局的DaoSession
:
@Override
public void onCreate() {
super.onCreate();
initGreenDao();
}
private void initGreenDao() {
DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(this, "myGreenDAO.db");
SQLiteDatabase db = helper.getWritableDatabase();
DaoMaster daoMaster = new DaoMaster(db);
daoSession = daoMaster.newSession();
}
public static DaoSession getDaoSession() {
return daoSession;
}
GreenDAO实现数据库增删改查
增
private void insertDB() {
Student student2 = new Student();
student2.setAge(13);
student2.setName("小花");
student2.setStudentId(3002);
GreenDAOApplication.getDaoSession().insert(student2);
Student student1 = new Student();
student1.setAge(14);
student1.setName("小明");
student1.setStudentId(3001);
GreenDAOApplication.getDaoSession().insert(student1);
}
运行之后数据库创建在 data/data/com.saberhao.greendaodemo/databases
目录下:
打开数据库,可以看到我们插入的数据:
删
private void deleteFromDB(Student s) {
GreenDAOApplication.getDaoSession().delete(s);
}
改
private void updateDB(Student s) {
GreenDAOApplication.getDaoSession().update(s);
}
查
public List<Student> queryData(String s) {
List<Student> students = GreenDAOApplication.getDaoSession().queryRaw(Student.class, " where Id = ?", s);
return students;
}
GreenDao源码分析
下面源码均来自GreenDao最新的3.2.2版本
1. 创建数据库帮助类对象DevOpenHelper
DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(this, "myGreenDAO.db");
DevOpenHelper
继承自OpenHelper
,OpenHelper
继承自DatabaseOpenHelper
,DatabaseOpenHelper
继承自原生SQLiteOpenHelper
。
public static class DevOpenHelper extends OpenHelper {
...
@Override
public void onUpgrade(Database db, int oldVersion, int newVersion) {
Log.i("greenDAO", "Upgrading schema from version " + oldVersion + " to " + newVersion + " by dropping all tables");
dropAllTables(db, true);
onCreate(db);
}
}
public static abstract class OpenHelper extends DatabaseOpenHelper {
...
@Override
public void onCreate(Database db) {
Log.i("greenDAO", "Creating tables for schema version " + SCHEMA_VERSION);
createAllTables(db, false);
}
}
可以看到DevOpenHelper
upgrade的时候会丢弃所有表,并新建所有表
2. 获取数据库
SQLiteDatabase db = helper.getWritableDatabase();
这里获取的是SQLiteDatabase
类型的数据库
public SQLiteDatabase getWritableDatabase() {
synchronized (this) {
return getDatabaseLocked(true);
}
}
DatabaseOpenHelper
还为我们提供了两种类型的数据库:标准型的数据库StandardDatabase
,另一种是加密型的数据库SQLCipher EncryptedDatabase
public abstract class DatabaseOpenHelper extends SQLiteOpenHelper {
public Database getWritableDb() {
return wrap(getWritableDatabase());
}
public Database getEncryptedWritableDb(String password) {
EncryptedHelper encryptedHelper = checkEncryptedHelper();
return encryptedHelper.wrap(encryptedHelper.getWritableDatabase(password));
}
}
StandardDatabase
和EncryptedDatabase
均实现了 Database接口,我们只要在使用前指定数据库类型,之后的数据库操作都是以代理形式进行,使用的接口完全一致。
public interface Database {
Cursor rawQuery(String sql, String[] selectionArgs);
void execSQL(String sql) throws SQLException;
void beginTransaction();
void endTransaction();
boolean inTransaction();
void setTransactionSuccessful();
void execSQL(String sql, Object[] bindArgs) throws SQLException;
DatabaseStatement compileStatement(String sql);
boolean isDbLockedByCurrentThread();
void close();
Object getRawDatabase();
}
3. 创建DaoMaster对象
DaoMaster daoMaster = new DaoMaster(db);
将原生数据库对象SQLiteDatabase
传入,获取DaoMaster
对象
public class DaoMaster extends AbstractDaoMaster {
public DaoMaster(SQLiteDatabase db) {
this(new StandardDatabase(db));
}
public DaoMaster(Database db) {
//-->2.1 传入schema版本和db到父类的构造函数中
super(db, SCHEMA_VERSION);
//-->2.2 注册Dao类型
registerDaoClass(StudentDao.class);
}
}
public abstract class AbstractDaoMaster {
...
//2.1 父类构造函数
public AbstractDaoMaster(Database db, int schemaVersion) {
this.db = db;
this.schemaVersion = schemaVersion;
daoConfigMap = new HashMap<Class<? extends AbstractDao<?, ?>>, DaoConfig>();
}
//2.2 注册Dao类型
protected void registerDaoClass(Class<? extends AbstractDao<?, ?>> daoClass) {
DaoConfig daoConfig = new DaoConfig(db, daoClass);
daoConfigMap.put(daoClass, daoConfig);
}
...
}
步骤2.1,在AbstractDaoMaster
对象的构造方法中,主要做了2步操作:
- 记录当前的数据库对象和版本
- 创建
daoConfigMap
的HashMap
对象,用于保存DAO对象及其数据配置对象DaoConfig
而后步骤2.2中,调用父类registerDaoClass
函数,创建DaoConfig
对象,并将其和DAO对象于daoConfigMap
中绑定。
4. AbstractDao构造函数
public AbstractDao(DaoConfig config, AbstractDaoSession daoSession) {
this.config = config;
this.session = daoSession;
db = config.db;
isStandardSQLite = db.getRawDatabase() instanceof SQLiteDatabase;
identityScope = (IdentityScope<K, T>) config.getIdentityScope();
if (identityScope instanceof IdentityScopeLong) {
identityScopeLong = (IdentityScopeLong<T>) identityScope;
} else {
identityScopeLong = null;
}
statements = config.statements;
pkOrdinal = config.pkProperty != null ? config.pkProperty.ordinal : -1;
}
在继续其他源码分析前,我们需要在看看AbstractDao
构造函数,这个函数会对我们后面用到的几个参数进行初始化,包括:isStandardSQLite
,identityScope
,identityScopeLong
,statements
,pkOrdinal
,后面用到的时候大家就知道在这里初始化的。
5. 创建DaoSeesion对象
daoSession = daoMaster.newSession();
在DaoMaster中进行初始化
//@DaoMaster.java
public DaoSession newSession() {
return new DaoSession(db, IdentityScopeType.Session, daoConfigMap);
}
//@DaoSession.java
public class DaoSession extends AbstractDaoSession {
public DaoSession(...) {
//-->5.1调用父类构造函数
super(db);
//获取DaoConfig对象
studentDaoConfig = daoConfigMap.get(StudentDao.class).clone();
//-->5.2 初始化identityScope
studentDaoConfig.initIdentityScope(type);
//创建ClassDao,将DaoConfig和DaoSeesion传入ClassDao中
studentDao = new StudentDao(studentDaoConfig, this);
//-->5.3调用父类registerDao方法
registerDao(Student.class, studentDao);
}
}
//@AbstractDaoSession.java
public class AbstractDaoSession {
//5.1调用父类构造函数
public AbstractDaoSession(Database db) {
this.db = db;
//创建entityToDao用于保存Class和ClassDao对于关系
this.entityToDao = new HashMap<Class<?>, AbstractDao<?, ?>>();
}
//5.2调用AbstractDaoSession的registerDao方法
protected <T> void registerDao(Class<T> entityClass, AbstractDao<T, ?> dao) {
//绑定Class和ClassDao
entityToDao.put(entityClass, dao);
}
}
//5.2 初始化identityScope@DaoConfig.java
public void initIdentityScope(IdentityScopeType type) {
if (type == IdentityScopeType.None) {
identityScope = null;
} else if (type == IdentityScopeType.Session) {
if (keyIsNumeric) {
identityScope = new IdentityScopeLong();
} else {
identityScope = new IdentityScopeObject();
}
} else {
throw new IllegalArgumentException("Unsupported type: " + type);
}
}
从上面的源码我们可以看到daoMaster.newSession()
主要完成的工作包括:
-
创建了Class实体与Dao对象的映射集合
-
从
daoConfigMap
中获取Config对象 -
根据
IdentityScopeType
的类型初始化IdentityScope
对象,根据type的不同,它有两种类型,分别是IdentityScopeObject
和IdentityScopeLong
,它的作用是根据主键缓存对应的实体数据。当主键是数字类型的时候,如long/Long
、int/Integer
、short/Short
、byte/Byte
,使用IdentityScopeLong
缓存实体数据,当主键不是数字类型的时候,则使用IdentityScopeObject
缓存实体数据 -
创建ClassDao,本例指的是studentDao,并将ClassDao和Class建立映射关系,存入entityToDao中
6. 插入
private void insertToDB(Student s) {
GreenDAOApplication.getDaoSession().insert(s);
}
接下来我们继续看insert是如何工作的
//@AbstractDaoSession。java
public <T> long insert(T entity) {
@SuppressWarnings("unchecked")
//-->6.1获取ClasseDao实例
AbstractDao<T, ?> dao = (AbstractDao<T, ?>) getDao(entity.getClass());
//-->6.2通过classDao插入对象
return dao.insert(entity);
}
//6.1获取ClasseDao实例 @AbstractDaoSession.java
public AbstractDao<?, ?> getDao(Class<? extends Object> entityClass) {
//在entityToDao中,通过class获取Dao对象
AbstractDao<?, ?> dao = entityToDao.get(entityClass);
...
return dao;
}
//6.2通过classDao出入对象 @AbstractDao.java
public long insert(T entity) {
//-->6.3
return executeInsert(entity, statements.getInsertStatement(), true);
}
statements
是一个TableStatements
对象,在AbstractDao
构造函数中初始化,是一个根据指定的表格创建SQL语句的一个帮助类。statements.getInsertStatement()
是获得一个插入语句
//6.3.0 @TableStatements.java
public DatabaseStatement getInsertStatement() {
if (insertStatement == null) {
//创建插入sql语句
String sql = SqlUtils.createSqlInsert("INSERT INTO ", tablename, allColumns);
//调用Database接口,StandardDatabase和EncryptedDatabase有不同给实现
//实现将sql语句编译成当前数据库(标准或者加密数据库)对应的语句,
DatabaseStatement newInsertStatement = db.compileStatement(sql);
synchronized (this) {
if (insertStatement == null) {
insertStatement = newInsertStatement;
}
}
if (insertStatement != newInsertStatement) {
newInsertStatement.close();
}
}
return insertStatement;
}
在getInsertStatement
方法中,主要做了两件事:
- 使用
SqlUtils
创建了插入的sql
语句。 - 根据不同的数据库类型(标准数据库或加密数据库)将
sql
语句编译成当前数据库对应的语句。
//6.3.1 @AbstractDao.java
private long executeInsert(T entity, DatabaseStatement stmt, boolean setKeyAndAttach) {
long rowId;
//判断数据库是否被当前线程锁定
if (db.isDbLockedByCurrentThread()) {
//-->6.4直接插入数据
rowId = insertInsideTx(entity, stmt);
} else {
// Do TX to acquire a connection before locking the stmt to avoid deadlocks
db.beginTransaction();
try {
rowId = insertInsideTx(entity, stmt);
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
}
if (setKeyAndAttach) {
updateKeyAfterInsertAndAttach(entity, rowId, true);
}
return rowId;
}
//5.4直接插入数据
private long insertInsideTx(T entity, DatabaseStatement stmt) {
synchronized (stmt) {
if (isStandardSQLite) {
SQLiteStatement rawStmt = (SQLiteStatement) stmt.getRawStatement();
//-->6.5 将数据绑定到Statement中
bindValues(rawStmt, entity);
//-->6.6 执行插入操作
return rawStmt.executeInsert();
} else {
bindValues(stmt, entity);
return stmt.executeInsert();
}
}
}
在6.4中,函数insertInsideTx
使用同步锁保证线程安全,如果当前是标准数据库,使用原生SQLiteStatement
进行实体字段属性的绑定和执行最后的插入操作,如果是加密数据,则直接使用当前的加密数据库进行操作。其中bindValues
这个方法对应的实现类在StudentDao
中:
//6.5 将数据绑定到Statement中 @StudentDao.java
public class StudentDao extends AbstractDao<Student, Long> {
@Override
protected final void bindValues(DatabaseStatement stmt, Student entity) {
stmt.clearBindings();
Long id = entity.getId();
if (id != null) {
stmt.bindLong(1, id);
}
stmt.bindLong(2, entity.getStudentId());
stmt.bindLong(3, entity.getAge());
String name = entity.getName();
if (name != null) {
stmt.bindString(4, name);
}
}
@Override
protected final void bindValues(SQLiteStatement stmt, Student entity) {
stmt.clearBindings();
Long id = entity.getId();
if (id != null) {
stmt.bindLong(1, id);
}
stmt.bindLong(2, entity.getStudentId());
stmt.bindLong(3, entity.getAge());
String name = entity.getName();
if (name != null) {
stmt.bindString(4, name);
}
}
}
可以看到,这里对Student
的所有字段使用对应的数据库语句进行了绑定操作。对于最后的插入操作executeInsert()
, 不同的statement有不同实现,如果当前数据库是加密型时,则会使用DatabaseStatement
的加密实现类EncryptedDatabaseStatement
应用代理模式去使用sqlcipher
这个加密型数据库的executeInsert
方法。
7. 删除
private void deleteFromDB(Student s) {
GreenDAOApplication.getDaoSession().delete(s);
}
我们继续分析删除的源码实现
//@AbstractDaoSession.java
public <T> void delete(T entity) {
@SuppressWarnings("unchecked")
//-->6.1获取ClasseDao实例
AbstractDao<T, ?> dao = (AbstractDao<T, ?>) getDao(entity.getClass());
//-->7.1 通过ClassDao删除对象
dao.delete(entity);
}
//6.1 通过ClassDao删除对象 @AbstractDao.java
public void delete(T entity) {
assertSinglePk();
//-->7.2 获取Key
K key = getKeyVerified(entity);
//-->7.3 通过Key删除数据库对应数据
deleteByKey(key);
}
//6.2 获取Key @AbstractDao.java
protected K getKeyVerified(T entity) {
//--> 7.4 获取key的操作在实现类中,在本例对应的是StudentDao
K key = getKey(entity);
...
return key;
...
}
//6.4 获取key的实现 @StudentDao.java
@Override
public Long getKey(Student entity) {
if(entity != null) {
return entity.getId();
} else {
return null;
}
}
//7.3 通过Key删除数据库对应数据,改操作和5.3的插入操作executeInsert类似 @AbstractDao.java
public void deleteByKey(K key) {
assertSinglePk();
//创建删除数据库的statement,实现基本同6.3.0中插入statement创建
DatabaseStatement stmt = statements.getDeleteStatement();
if (db.isDbLockedByCurrentThread()) {
//-->6.5 如果数据库被当前线程锁定,直接执行数据库操作
synchronized (stmt) {
deleteByKeyInsideSynchronized(key, stmt);
}
} else {
// 如果数据库未被当前线程锁定,需要先提交事务在进行操作
db.beginTransaction();
try {
synchronized (stmt) {
deleteByKeyInsideSynchronized(key, stmt);
}
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
}
//将数据在identityScope中删除
if (identityScope != null) {
identityScope.remove(key);
}
}
//7.5 删除据库操作 @AbstractDao
//stmt根据数据库类型,分别为EncryptedDatabaseStatement或者StandardDatabaseStatement
private void deleteByKeyInsideSynchronized(K key, DatabaseStatement stmt) {
//绑定数据
if (key instanceof Long) {
stmt.bindLong(1, (Long) key);
} else if (key == null) {
throw new DaoException("Cannot delete entity, key is null");
} else {
stmt.bindString(1, key.toString());
}
//执行删除操作
stmt.execute();
}
删除和插入的操作基本一直,就是传入的sql
语句有区别。
8. 修改
private void updateDB(Student s) {
GreenDAOApplication.getDaoSession().update(s);
}
接下去是源码实现:
public <T> void update(T entity) {
//-->6.1获取ClasseDao实例
AbstractDao<T, ?> dao = (AbstractDao<T, ?>) getDao(entity.getClass());
//-->8.1 修改
dao.update(entity);
}
代码已经有一股熟悉的味道~
//@AbstractDao.java
public void update(T entity) {
assertSinglePk();
DatabaseStatement stmt = statements.getUpdateStatement();
if (db.isDbLockedByCurrentThread()) {
synchronized (stmt) {
if (isStandardSQLite) {
//-->8.1
updateInsideSynchronized(entity, (SQLiteStatement) stmt.getRawStatement(), true);
} else {
//-->8.2
updateInsideSynchronized(entity, stmt, true);
}
}
} else {
db.beginTransaction();
try {
synchronized (stmt) {
updateInsideSynchronized(entity, stmt, true);
}
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
}
}
//8.1 @AbstractDao.java
protected void updateInsideSynchronized(T entity, DatabaseStatement stmt, boolean lock) {
// To do? Check if it's worth not to bind PKs here (performance).
bindValues(stmt, entity);
int index = config.allColumns.length + 1;
K key = getKey(entity);
if (key instanceof Long) {
stmt.bindLong(index, (Long) key);
} else if (key == null) {
throw new DaoException("Cannot update entity without key - was it inserted before?");
} else {
stmt.bindString(index, key.toString());
}
stmt.execute();
//-->8.3
attachEntity(key, entity, lock);
}
//8.2 @AbstractDao.java
protected void updateInsideSynchronized(T entity, SQLiteStatement stmt, boolean lock) {
// To do? Check if it's worth not to bind PKs here (performance).
bindValues(stmt, entity);
int index = config.allColumns.length + 1;
K key = getKey(entity);
if (key instanceof Long) {
stmt.bindLong(index, (Long) key);
} else if (key == null) {
throw new DaoException("Cannot update entity without key - was it inserted before?");
} else {
stmt.bindString(index, key.toString());
}
stmt.execute();
attachEntity(key, entity, lock);
}
//8.3 @AbstractDao.java
protected final void attachEntity(K key, T entity, boolean lock) {
attachEntity(entity);
if (identityScope != null && key != null) {
if (lock) {
identityScope.put(key, entity);
} else {
identityScope.putNoLock(key, entity);
}
}
}
因为套路上插入删除基本一致,我就简单说下,修改操作主要完成:
-
通过
getUpdateStatement
方法获取修改数据库sql
语句 -
更新数据库并更新identityScope
9. 查询
public List<Student> queryData(String s) {
List<Student> students = GreenDAOApplication.getDaoSession().queryRaw(Student.class,
" where Id = ?", s);
return students;
}
源码实现:
//@AbstractDao.java
public <T, K> List<T> queryRaw(Class<T> entityClass, String where, String... selectionArgs) {
//-->6.1获取ClasseDao实例
AbstractDao<T, K> dao = (AbstractDao<T, K>) getDao(entityClass);
//-->9.1 查询数据
return dao.queryRaw(where, selectionArgs);
}
//9.1查询数据 @AbstractDao.java
public List<T> queryRaw(String where, String... selectionArg) {
//根据查询语句获取游标
Cursor cursor = db.rawQuery(statements.getSelectAll() + where, selectionArg);
//-->9.2加载数据
return loadAllAndCloseCursor(cursor);
}
//9.2 @AbstractDao.java
protected List<T> loadAllAndCloseCursor(Cursor cursor) {
try {
//-->9.3 从游标位置加载数据
return loadAllFromCursor(cursor);
} finally {
cursor.close();
}
}
//9.3加载数据 @AbstractDao.java
protected List<T> loadAllFromCursor(Cursor cursor) {
...
if (window.getNumRows() == count) {
//如果cursor函数没有偏差,使用FastCursor进行快速定位
cursor = new FastCursor(window);
useFastCursor = true;
}
...
if (cursor.moveToFirst()) {
...
try {
if (!useFastCursor && window != null && identityScope != null) {
//最终调用list.add(loadCurrent(...))
loadAllUnlockOnWindowBounds(cursor, window, list);
} else {
do {
//9.4 加载游标标记位置数据
list.add(loadCurrent(cursor, 0, false));
} while (cursor.moveToNext());
}
} finally {
if (identityScope != null) {
identityScope.unlock();
}
}
}
return list;
}
// 9.4 获取数据 @AbstractDao.java
final protected T loadCurrent(Cursor cursor, int offset, boolean lock) {
if (identityScopeLong != null) {
...
//获取缓存数据
T entity = lock ? identityScopeLong.get2(key) : identityScopeLong.get2NoLock(key);
if (entity != null) {
//如果有缓存,直接返回
return entity;
} else {
//-->9.5 获取数据并封装到实例对象中,这里的实现在StudentDao中
entity = readEntity(cursor, offset);
attachEntity(entity);
//对数据进行缓存
if (lock) {
identityScopeLong.put2(key, entity);
} else {
identityScopeLong.put2NoLock(key, entity);
}
return entity;
}
} else if (identityScope != null) {
K key = readKey(cursor, offset);
if (offset != 0 && key == null) {
// Occurs with deep loads (left outer joins)
return null;
}
T entity = lock ? identityScope.get(key) : identityScope.getNoLock(key);
if (entity != null) {
return entity;
} else {
entity = readEntity(cursor, offset);
attachEntity(key, entity, lock);
return entity;
}
} else {
// Check offset, assume a value !=0 indicating a potential outer join, so check PK
if (offset != 0) {
K key = readKey(cursor, offset);
if (key == null) {
// Occurs with deep loads (left outer joins)
return null;
}
}
T entity = readEntity(cursor, offset);
attachEntity(entity);
return entity;
}
}
// 9.5 将查询数据封装到实例对象中 @StudentDao.java
@Override
public Student readEntity(Cursor cursor, int offset) {
Student entity = new Student( //
cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0), // id
cursor.getInt(offset + 1), // studentId
cursor.getInt(offset + 2), // age
cursor.isNull(offset + 3) ? null : cursor.getString(offset + 3) // name
);
return entity;
}
首先,如果有实体数据缓存identityScopeLong
/identityScope
,则先从缓存中取,如果缓存中没有,会使用cursor进行查询,并将数据封装到实例对象中,然后缓存到对应的identityScopeLong
/identityScope
,方便下次快速查询。
10.自动生成代码
Android中使用比较常见的注解处理器是APT,但是GreenDao使用的是JDT。发中常见的注解处理器有反射、APT、JDT等。反射在java开发中是比较常见的、apt是android开发经常使用的方式、JDT是eclipse开发工具使用的处理器。GreenDao使用的代码生成模板为freemarker
开源框架。详细流程如下:
该图来自:GreenDAO系列(二) GreenDao 代码生成策略分析,有兴趣的童鞋可以点击查看。
小结
在分析完GreenDao的核心源码之后,我们可以发现GreenDao作为流行数据库框架有如下特点:
- 内部提供了实体数据的映射缓存机制,能够加快查询速度
- 使用代理模式进行了封装,对不同数据库进行适配
- 它使用了
sqlcipher
提供了加密数据库的功能 - 使用
freemarker
模板生成所需的静态代码,是框架易用性更高
参考