AspectJ初体验
最近在写自己的框架,由于框架不是很稳定,有较多的重构,用RDBMS的话,重构数据库就能把我搞死..所以选择OODBMS ,
OODBMS用起来还是不错的,可惜没有如Spring等事务管理措施的辅助,处理起事务来还是比较吃力.
既然Spring帮不了我,那就只有自己帮自己了,做事务处理现在流行用AOP来做..对于Spring AOP这种用动态代理机制来模拟AOP
感觉不是很爽,所以一下子就选择AspectJ作为自己的AOP框架,
从www.eclipse.org/adjt下载了AspectJ的IDE之后,AspectJ之旅就开始了.
学着例子,自己摆弄了一个aj先:
被AOP的代码:
/*
@author Kevin.Huang
@date 2007-9-27
/
public class Test {/*
@param args
*/
public static void main(String[] args) {
sayHello();}
public static void sayHello() {
System.out.println("Hello");
}}
AspectJ的代码
/*
@author Kevin.Huang
@date 2007-9-27
/
public aspect World {pointcut greeting():execution(* Test.sayHello(..));
after() returning() : greeting() {
System.out.println(" World!");
}}
这是Eclipse的AspectJ插件上展示的例子,很简单.这个时候运行Test,就会打出Hello World!..World!就是通过AOP加上去的,反编译源代码发现实际上AspectJ就是在Test.class上再加上自己的字节码来实现AOP.所以一定程度上也破坏了封装性,但能跑起来,管他呢.
现在来看看AspectJ特有的一下语法:
pointcut :定义了从joinPoint运行的函数,
execution:定义了AOP运用的范围,有* .. 等通配符可以使用,所以一个aj文件可以为多个同类的方法提供AOP服务
after,before,around,这些就是指定pointcut 从那里开始运行了..
after 后面还可以跟return,throw来判断返回的类型,这个可是写事务管理很重要的特性了..
我这里就简单说说,说太多还怕误人子弟..hoho,自己才刚开始用..
下面就给大家看看我用AspectJ怎么做了一个事务管理的:
被管理的DAO(我用的是db4o作为数据库..hoho):
public class DB4ODAO implements IGenericDAO {
/*
*/
protected Class< ? extends Base > persistentClass;/*
@return the persistentClass
*/
public Class< ? extends Base > getPersistentClass() {
return persistentClass;
}/*
@param persistentClass
the persistentClass to set
/
public void setPersistentClass(Class< ? extends Base > persistentClass) {
this.persistentClass = persistentClass;
}/*
db4o的session
*/
protected ObjectContainer db;public void delete(Base entity) {
db.delete(entity);
}public List< ? extends Base > findAll() {
return db.query(getPersistentClass());
}public < K extends Base> List< K > findByExample(K exampleInstance) {
return db.get(exampleInstance);
}public < K extends Base> List< K > findByFilter(Filter filter) {
// TODO Auto-generated method stub
return null;
}public < K extends Base> K findById(Serializable id) {
Base obj = null;
try {
obj = getPersistentClass().newInstance();
} catch (InstantiationException e) {
// XXX 记录异常
throw new RuntimeException("Domain Model is ERROR!", e);
} catch (IllegalAccessException e) {
// XXX 记录异常
throw new RuntimeException("Domain Model is ERROR!", e);
}
obj.setUuid((String) id);
ObjectSet< K > result = db.get(obj);
if (result.hasNext()) {
return result.next();
} else {
return null;
}
}public Integer findCountByFilter(Filter filter) {
// TODO Auto-generated method stub
return null;
}public < K extends Base> K saveAndUpdate(K entity) {
Base obj = findById(entity.getUuid());
if (obj != null) {
db.ext().bind(entity, db.ext().getID(obj));
}
db.set(entity);
return entity;
}public ObjectContainer getDb() {
return db;
}public void setDb(ObjectContainer db) {
this.db = db;
}}
里面的find,save,delete等都需要做事务管理
下面就是针对这个DAO的一个aj:
public aspect TransactionDAOAOP {
private static final Logger LOGGER = Logger.getLogger(TransactionDAOAOP.class);private ObjectContainer db;
private Object joinPoint;
pointcut readOnly(DB4ODAO dao):execution( DB4ODAO.find*(..))&&this(dao);
pointcut update(DB4ODAO dao):execution( DB4ODAO.save*(..))&&this(dao);
pointcut delete(DB4ODAO dao):execution( DB4ODAO.delete(..))&&this(dao);
before(DB4ODAO dao) : readOnly(dao) {
start(dao, thisJoinPoint);
}after(DB4ODAO dao) returning() : readOnly(dao) {
if (joinPoint.equals(thisJoinPoint)) {
close();
}
}after(DB4ODAO dao) throwing(): readOnly(dao) {
close();
}before(DB4ODAO dao) : update(dao) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("before updata @" + dao.toString());
}
start(dao, thisJoinPoint);
}after(DB4ODAO dao) returning() : update(dao) {
if (joinPoint.equals(thisJoinPoint)) {
commit();
close();
}
}after(DB4ODAO dao) throwing(): update(dao) {
rollback();
close();
}before(DB4ODAO dao) : delete(dao) {
start(dao, thisJoinPoint);
}after(DB4ODAO dao) returning() : delete(dao) {
if (joinPoint.equals(thisJoinPoint)) {
commit();
close();
}
}after(DB4ODAO dao) throwin
g(): delete(dao) {
rollback();
close();
}private void start(DB4ODAO dao, Object thisPoint) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("db is closed? @" + isClose(dao));
}
if (isClose(dao)) {
db = Db4o.openFile(DB4OConfig.getDataPath());
dao.setDb(db);
joinPoint = thisPoint;
}
}private void commit() {
db.commit();
}private void rollback() {
db.rollback();
}private void close() {
db.close();
}private boolean isClose(DB4ODAO dao) {
if (dao.getDb() == null) {
return true;
} else {
return dao.getDb().ext().isClosed();
}
}
}
这样一来就为DAO做了AOP了
基本的思想就是
开始方法前.先判断Session是否开启,如果没有则开启,并作记录是这个方法开启的Session
然后再运行中如果有其他的AOP的方法插入,这时Session已开启就不用在开启,最后运行到开始记录的方法结束之后就commit再close
如果当中遇到异常则直接rollback并close
记录方法的方法是 joinPoint = thisJoinPoint;
thisJoinPoint是关键字,就是记录了方法开始的点…