大家都知道,Spring中IOC贯穿了其整个框架,IOC已经是框架设计中必不可少的部分,就实现上来讲Spring采取了配置文件的形式来实现依赖的注射,很好的解决了应用程序与服务之间的耦合的问题,除此之外,Spring还对事务管理提供了很好的支持。今天我要说的不是Spring的IOC,也不是Spring的事务管理,而是我自己写的类似Spring的IOC和事务管理,IOC采用工厂模式和单例模式来实现,事务管理使用动态代理模式来实现,当然功能没有Spring的那么强大。
beans.xml文件将配置数据库的相关信息、哪些类的哪些方法需要使用事务以及用来创建bean,具体配置如下:
用来封装数据库配置信息的类:
读取数据库配置信息的类:
数据库的连接管理类:
使用动态代理模式来对被代理的类进行管理,如果被代理的类跟配置文件的表达式匹配,则进行事务代理(开启事物,事务提交,事物回滚)。
所有类将通过读取xml文件来创建,使用工厂模式和单例模式,创建好的bean将放到工厂中,同一系列的bean由同一工厂管理,这样就很好地降低各层之间的耦合性。
下面将贴出各个类的代码
包 com.lrh.orm下的类:
User类:
包com.lrh.dao下的接口或类:
UserDao接口:
实现UserDao接口的UserDaoImpl类:
包 com.lrh.service下的接口或类:
UserService接口:
实现UserService接口的UserServiceImpl类:
最后编写一个类来测试一下:
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;
}
}
下面将贴出各个类的代码
包 com.lrh.orm下的类:
User类:
package com.lrh.orm;
/**
* @author jenhui
*
*/
public class User {
private String id;
private String name;
private String password;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
包com.lrh.dao下的接口或类:
UserDao接口:
package com.lrh.dao;
import com.lrh.orm.User;
/**
* @author jenhui
*
*/
public interface UserDao {
public void addUser(User user);
}
实现UserDao接口的UserDaoImpl类:
package com.lrh.dao;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import com.lrh.orm.User;
import com.lrh.utils.ConnectionManager;
/**
* @author jenhui
*
*/
public class UserDaoImpl implements UserDao {
public void addUser(User user) {
System.out.println("this is UserDaoImpl.addUser()");
String sql="insert into user(Id,Name,Password) values(?,?,?)";
try {
PreparedStatement ps = ConnectionManager.getConnection().prepareStatement(sql);
ps.setString(1, user.getId());
ps.setString(2, user.getName());
ps.setString(3, user.getPassword());
ps.execute();
System.out.println(ConnectionManager.getConnection());
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
包 com.lrh.service下的接口或类:
UserService接口:
package com.lrh.service;
import com.lrh.orm.User;
/**
* @author jenhui
*
*/
public interface UserService {
public void addUser(User user);
}
实现UserService接口的UserServiceImpl类:
package com.lrh.service;
import com.lrh.dao.UserDao;
import com.lrh.orm.User;
import com.lrh.utils.BeansFactory;
/**
* @author jenhui
*
*/
public class UserServiceImpl implements UserService {
private UserDao userDao=(UserDao)BeansFactory.getInstance().getDaoObject("userDao");
public void addUser(User user) {
userDao.addUser(user);
}
}
最后编写一个类来测试一下:
package com.lrh.web;
import com.lrh.orm.User;
import com.lrh.service.UserService;
import com.lrh.utils.BeansFactory;
/**
* @author jenhui
*
*/
public class Client {
public static void main(String[] args){
UserService userService=(UserService)BeansFactory.getInstance().getServiceObject("userService");
User user=new User();
user.setId("A00810");
user.setPassword("QQ1259111695");
user.setName("kelly");
userService.addUser(user);
}
}