日期:2014-05-16 浏览次数:20540 次
AOP(Aspect Oriented Programming,面向方面编程)是如今比较火的概念之一,再加上Spring框架的流行,很多程序员更是言必称AOP,如果对AOP不了解就像土老帽似的。AOP中的Aspect其实就是程序员关注的某一方面,如某些方法有没有被访问过、某些方法执行时间有多长、把某些方法的执行置于事务之下等等,具体实现方法就是在某些方法执行前后自动执行一些操作,就像拦截器一样。其实一些框架中的拦截器功能正是通过AOP实现的。 
??? Java反射功能中有一项就是动态代理,但代理的对象必须实现了接口,也就是Jdk目前仅支持接口的代理。其原理是首先检索被代理对象的所有接口,然后动态生成一个实现了被代理对象接口的Class(这也是为什么叫动态代理的原因),最后把这个Class的一个实例返回。因为通过Java动态代理之后,您所使用的对象就像狸猫换太子一样被掉包了,执行一个方法时,其实是执行的动态生成实例的方法,里面会有一个地方调用原对象的方法,从而达到在原对象方法执行前后运行特定代码的目的。在Spring中,利用了cglib,如果被代理对象实现了接口,就用Java的动态代理,如果仅仅是一个没有接口的类,则用cglib中继承的方式进行代理。 
??? 在Spring中有用Java注解(annotation)的方法实现事务管理的功能,也就是声明式事务,去除了代码中繁琐的事务控制代码。在本文中,利用Java的annotation、dynamic proxy实现一个简单的管理数据库连接与事务的框架,而不使用任何现成的框架。 
??? 首先是一个获取数据库连接的工具类,此处是使用的是mysql数据库,运行时需要mysql的jdbc驱动包。代码如下: 
?
package demo.dynamicproxy; 
import java.sql.Connection; 
import java.sql.DriverManager; 
public class DbUtil { 
??? /** 
???? * 获取数据库连接,如果使用其他数据库,修改这里就可以了。 
???? * @return 
???? */ 
??? public static Connection getConnection() { 
??????? Connection conn = null; 
??????? try { 
??????????? Class.forName("com.mysql.jdbc.Driver"); 
??????????? conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/st", "root", ""); 
??????? } 
??????? catch(Exception e) { 
??????????? e.printStackTrace(); 
??????? } 
???????? 
??????? return conn; 
??? } 
} 
??? 对于需要数据库操作的业务类,需要实现IDb接口: 
?
package demo.dynamicproxy; 
import java.sql.Connection;
public interface IDb { 
??? /** 
???? * 设置数据库连接 
???? * @param conn 
???? */ 
??? void setConnection(Connection conn); 
???? 
??? /** 
???? * 获取数据库连接。 
???? * 如果没有设置返回null。 
???? * @return 
???? * @throws Exception 
???? */ 
??? Connection getConnection(); 
???? 
??? /** 
???? * 释放数据库连接 
???? * @param conn 
???? * @throws Exception 
???? */ 
??? void closeConnection(); 
} 
??? 为了使用方便,建立一个IDb接口的默认实现类: 
package demo.dynamicproxy; 
import java.sql.Connection; 
import java.sql.Statement; 
public class DbImpl implements IDb { 
??? private Connection conn; 
???? 
??? @Override 
??? public void closeConnection() { 
??????? try { 
??????????? if (conn != null) conn.close(); 
??????????? conn = null; 
??????????? System.out.println("close conn"); 
??????? } 
??????? catch(Exception e) { 
??????????? e.printStackTrace(); 
??????? } 
??? } 
??? @Override 
??? public Connection getConnection() { 
??????? return conn; 
??? } 
??? @Override 
??? public void setConnection(Connection conn) { 
??????? this.conn = conn; 
??????? System.out.println("set conn"); 
??? } 
??? protected int executeNonQuery(String sql) throws Exception { 
??????? System.out.println("executeNonQuery begin:" + sql); 
??????? Statement stmt = null; 
??????? int result = 0; 
??????? try { 
??????????? stmt = getConnection().createStatement(); 
??????????? result = stmt.executeUpdate(sql); 
??????? } 
??????? catch(Exception e) { 
??????????? throw e; 
??????? } 
??????? finally { 
??????????? if (stmt != null) stmt.close(); 
??????? } 
??????? System.out.println("executeNonQuery complete:" + sql); 
??????? return result; 
??? } 
} 
??? 对于需要数据库连接和事务的方法,加上一个注解就可以了,这就是那个注解: 
package demo.dynamicproxy.annotation; 
import java.lang.annotation.ElementType; 
import java.lang.annotation.Retention; 
import java.lang.annotation.RetentionPolicy; 
import java.lang.annotation.Target; 
/** 
?* 被注解的方法可以自动获取数据库连接并开启事务。 
?* 
?*/ 
@Retention(RetentionPolicy.RUNTIME) 
@Target(ElementType.METHOD) 
public @interface Transactional { 
??? boolean autoCommit() default false; 
} 
被代理方法执行时的处理器,动态代理的核心就在这里: 
package demo.dynamicproxy; 
import java.lang.reflect.InvocationHandler; 
import java.lang.reflect.Method;