大家都知道,Spring中IOC贯穿了其整个框架,IOC已经是框架设计中必不可少的部分,就实现上来讲Spring采取了配置文件的形式来实现依赖的注射,很好的解决了应用程序与服务之间的耦合的问题,除此之外,Spring还对事务管理提供了很好的支持。今天我要说的不是Spring的IOC,也不是Spring的事务管理,而是我自己写的类似Spring的IOC和事务管理,当然功能没有Spring的那么强大,IOC采用工厂模式和单例模式来实现,事务管理使用动态代理模式来实现。
beans.xml文件将配置数据库的相关信息、哪些类的哪些方法需要使用事务以及用来创建bean,具体配置如下:
<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<beans>
<!-- 数据库的配置 -->
<config>
<db-info>
<driver-name>com.mysql.jdbc.Driver</driver-name>
<url>jdbc:mysql://localhost:3306/jdbctest</url>
<username>root</username>
<password>111</password>
</db-info>
</config>
<bean-service>
<bean id=\"userDao\" class=\"com.lrh.dao.UserDaoImpl\">
</bean>
</bean-service>
<bean-dao>
<bean id=\"userService\" class=\"com.lrh.service.UserServiceImpl\">
</bean>
</bean-dao>
<aop-config>
<aop-pointcut expression=\"com.lrh.service\"/>
</aop-config>
<tx-advice>
<tx-attributes>
<tx-method name=\"add*\"/>
<tx-method name=\"delete*\"/>
<tx-method name=\"modify*\"/>
<tx-method name=\"*\"/>
</tx-attributes>
</tx-advice>
</beans>用来封装数据库配置信息的类:
package com.lrh.utils;
/**
* 用来封装数据库的配置数据
* @author jenhui
*
*/
public class JdbcConfig {
private String driverName;
private String url;
private String userName;
private String password;
public String getDriverName() {
return driverName;
}
public void setDriverName(String driverName) {
this.driverName = driverName;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return this.getClass().getName() + \"{driverName:\" + driverName + \", url:\" + url + \", userName:\" + userName + \"}\";
}
}读取数据库配置信息的类:
package com.lrh.utils;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
/**
* 读取数据库配置信息
* @author jenhui
*
*/
public class JdbcConfigReader {
private static JdbcConfigReader instance = null;
private JdbcConfig jdbcConfig = new JdbcConfig();
private JdbcConfigReader() {
SAXReader reader = new SAXReader();
InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(\"beans.xml\");
try {
Document doc = reader.read(in);
Element driverNameElt = (Element)doc.selectObject(\"/beans/config/db-info/driver-name\");
Element urlElt = (Element)doc.selectObject(\"/beans/config/db-info/url\");
Element userNameElt = (Element)doc.selectObject(\"/beans/config/db-info/username\");
Element passwordElt = (Element)doc.selectObject(\"/beans/config/db-info/password\");
jdbcConfig.setDriverName(driverNameElt.getStringValue());
jdbcConfig.setUrl(urlElt.getStringValue());
jdbcConfig.setUserName(userNameElt.getStringValue());
jdbcConfig.setPassword(passwordElt.getStringValue());
} catch (DocumentException e) {
e.printStackTrace();
}
}
public static synchronized JdbcConfigReader getInstance() {
if (instance == null) {
instance = new JdbcConfigReader();
}
return instance;
}
public JdbcConfig getJdbcConfig() {
return jdbcConfig;
}
}数据库的连接管理类:
package com.lrh.utils;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
/**
* 数据库连接管理类
* @author jenhui
*
*/
public class ConnectionManager {
private static ThreadLocal<Connection> connectionHolder = new ThreadLocal<Connection>();
public static Connection getConnection() {
Connection conn = connectionHolder.get();
if (conn == null) {
try {
JdbcConfig jdbcConfig = JdbcConfigReader.getInstance().getJdbcConfig();
Class.forName(jdbcConfig.getDriverName());
conn = DriverManager.getConnection(jdbcConfig.getUrl(), jdbcConfig.getUserName(), jdbcConfig.getPassword());
connectionHolder.set(conn);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
}
return conn;
}
public static void closeConnection() {
Connection conn = connectionHolder.get();
if (conn != null) {
try {
conn.close();
connectionHolder.remove();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static void beginTransaction(Connection conn) {
try {
if (conn != null) {
if (conn.getAutoCommit()) {
conn.setAutoCommit(false);
}
}
}catch(SQLException e) {}
}
public static void commitTransaction(Connection conn) {
try {
if (conn != null) {
if (!conn.getAutoCommit()) {
conn.commit();
}
}
}catch(SQLException e) {}
}
public static void rollbackTransaction(Connection conn) {
try {
if (conn != null) {
if (!conn.getAutoCommit()) {
conn.rollback();
}
}
}catch(SQLException e) {}
}
}使用动态代理模式来对被代理的类进行管理,如果被代理的类跟配置文件的表达式匹配,则进行事务代理(开启事物,事务提交,事物回滚)。
package com.lrh.utils;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.util.Iterator;
import java.util.List;
import org.dom4j.Element;
/**
*
* @author jenhui
*
*/
public class ProxyHandler implements InvocationHandler {
private Object targetObject=null;
public Object createProxyInstance(Object targetObject){
this .targetObject=targetObject;
return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), targetObject.getClass().getInterfaces(), this);
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object obj=null;
Connection conn=null;
try{
conn=ConnectionManager.getConnection();
System.out.println(conn);
List methodsEle=BeansFactory.getInstance().getDocument().selectNodes(\"/beans/tx-advice/tx-attributes/tx-method\");
for(Iterator iter=methodsEle.iterator();iter.hasNext();){
Element methodEle=(Element)iter.next();
String str=methodEle.attributeValue(\"name\");
if(method.getName().startsWith(str.substring(0, str.length()-1)) && str.length()>1){
ConnectionManager.beginTransaction(conn);
}
}
obj= method.invoke(targetObject, args);
if(!conn.getAutoCommit()){
ConnectionManager.commitTransaction(conn);
}
}catch(Exception e){
e.printStackTrace();
ConnectionManager.rollbackTransaction(conn);
}finally{
ConnectionManager.closeConnection();
}
return obj;
}
}所有类将通过读取xml文件来创建,使用工厂模式和单例模式,创建好的bean将放到工厂中,同一系列的bean由同一工厂管理,这样就很好地降低各层之间的耦合性。
package com.lrh.utils;
import java.io.File;
import java.io.FileInputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import com.lrh.dao.UserDao;
/**
* 创建bean的工厂类
* @author jenhui
*
*/
public class BeansFactory {
private static BeansFactory instance=null;
private Map daoMap=new HashMap();
private Map serviceMap =new HashMap();
private Document document=null;
private BeansFactory(){
try{
SAXReader reader=new SAXReader();
document=reader.read(new FileInputStream(\"D:/workspace/beans.xml\"));
}catch(Exception e){
e.printStackTrace();
}
}
public synchronized static BeansFactory getInstance(){
if(instance==null){
instance= new BeansFactory();
}
return instance;
}
public Object getServiceObject(String beanId){
if(serviceMap.containsKey(beanId)){
return serviceMap.get(beanId);
}
Element serviceEle=(Element)document.selectSingleNode(\"//bean[@id=\"\"+beanId+\"\"]\");
String className=serviceEle.attributeValue(\"class\");
Object obj=null;
try{
obj=Class.forName(className).newInstance();
Element aopEle=(Element)document.selectSingleNode(\"/beans/aop-config/aop-pointcut\");
String expression=aopEle.attributeValue(\"expression\");
String packName=className.substring(0, className.lastIndexOf(\".\"));
if(expression.equals(packName)){
ProxyHandler proxyHandler=new ProxyHandler();
obj=proxyHandler.createProxyInstance(obj);
}
serviceMap.put(beanId, obj);
}catch(Exception e){
e.printStackTrace();
}
return obj;
}
public Object getDaoObject(String beanId){
if(daoMap.containsKey(beanId)){
return daoMap.get(beanId);
}
Element daoEle=(Element)document.selectSingleNode(\"//bean[@id=\"\"+beanId+\"\"]\");
String className=daoEle.attributeValue(\"class\");
Object obj=null;
try{
//obj=Class.forName(className).newInstance();
obj=Class.forName(className).newInstance();
Element aopEle=(Element)document.selectSingleNode(\"/beans/aop-config/aop-pointcut\");
String expression=aopEle.attributeValue(\"expression\");
String packName=className.substring(0, className.lastIndexOf(\".\"));
if(expression.equals(packName)){
ProxyHandler proxyHandler=new ProxyHandler();
obj=proxyHandler.createProxyInstance(obj);
}
daoMap.put(beanId, obj);
}catch(Exception e){
e.printStackTrace();
}
return obj;
}
public Document getDocument(){
return document;
}
}