主要思路:
- 使用ThreadLoacal来传递Connection
- 使用动态代理来增强service层的方法,对于CUD方法添加事务
- 通过注解+反射来扫描方法是否开启事务
代码
C3P0工具类
package com.fly.utils;
import java.sql.Connection;
import java.sql.SQLException;
import javax.sql.DataSource;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class C3P0Utils {
private static ComboPooledDataSource dataSource = new ComboPooledDataSource();
private static ThreadLocal<Connection> threadLocal = new ThreadLocal<Connection>();
public static DataSource getDataSource() {
return dataSource;
}
public static Connection getConnnection() throws SQLException {
Connection conn = threadLocal.get();
if(conn==null){
conn = dataSource.getConnection();
threadLocal.set(conn);
}
return conn;
}
public static void closeConnection() throws SQLException {
Connection conn = threadLocal.get();
if(conn != null){
conn.setAutoCommit(true);
conn.close();
threadLocal.remove();
}
}
public static void beginTransaction() throws SQLException {
Connection connnection = getConnnection();
connnection.setAutoCommit(false);
}
public static void commitTransaction() throws SQLException {
Connection connnection = getConnnection();
connnection.commit();
}
public static void rollbackTransaction() throws SQLException {
Connection connnection = getConnnection();
connnection.rollback();
}
}
Transaction注解
package com.fly.utils.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Transaction注解
* 该注解用于方法
* 如果方法上有该注解,则此方法会开启事务
* (注意,需要在该方法所在的类上添加AOP注解)
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface Transaction {
}
AOP注解
package com.fly.utils.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* AOP注解
* 用于类的注解,
* 增加此注解后,用工厂生成bean时会自动为该对象增加一个代理对象,
* 该代理对象可以对内部的方法进行注解扫描,
* 如果方法含有注解@Transaction,则开启事务操作。
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface AOP {
}
动态代理的切面InvocationHandlerImpl
package com.fly.utils.aop;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import com.fly.utils.C3P0Utils;
import com.fly.utils.annotation.Transaction;
/**
* 用于实现事务控制
*/
public class InvocationHandlerImpl implements InvocationHandler {
private Object target;
public InvocationHandlerImpl() {
}
public InvocationHandlerImpl(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Exception {
Object returnValue = null;
//是否开启事务注解
boolean isTransaction = method.isAnnotationPresent(Transaction.class);
if (!isTransaction) {
//如果未开启了事务
System.out.println("未开启事务");
System.out.println(method.getName());
returnValue = method.invoke(target, args);
return returnValue;
}
//如果开启事务
System.out.println("开启了事务");
System.out.println(method.getName());
try {
C3P0Utils.beginTransaction();
returnValue = method.invoke(target, args);
C3P0Utils.commitTransaction();
} catch (Exception e) {
C3P0Utils.rollbackTransaction();
throw e;
} finally {
C3P0Utils.closeConnection();
}
return returnValue;
}
}
bean工厂接口与实现类
package com.fly.utils.ioc;
/**
* bean工厂接口
*/
public interface BeanFactory {
Object getBean(String id);
}
package com.fly.utils.ioc;
import java.lang.reflect.Proxy;
import java.util.HashMap;
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;
import com.fly.utils.annotation.AOP;
import com.fly.utils.aop.InvocationHandlerImpl;
/**
* 基于xml文件的bean工厂实现类
* 采用懒汉式单例模式
* 初始化时会加载对应的xml配置文件
* 默认加载applicationContext.xml
*/
public class XmlBeanFactory implements BeanFactory {
private static XmlBeanFactory INSTANCE;
public static BeanFactory getFactory(String xmlPath) {
if (INSTANCE == null) {
synchronized(XmlBeanFactory.class) {
if (INSTANCE == null)
INSTANCE = new XmlBeanFactory(xmlPath);
}
}
return INSTANCE;
}
public static BeanFactory getFactory() {
if (INSTANCE == null) {
synchronized(XmlBeanFactory.class) {
if (INSTANCE == null)
INSTANCE = new XmlBeanFactory();
}
}
return INSTANCE;
}
@SuppressWarnings("rawtypes")
Map<String, Class> classMap = new HashMap<>();
Map<String, Object> map = new HashMap<>();
private XmlBeanFactory() {
this("applicationContext.xml");
}
private XmlBeanFactory(String xmlPath) {
try {
Document doc = new SAXReader()
.read(BeanFactory.class.getClassLoader().getResourceAsStream(xmlPath));
Element root = doc.getRootElement();
List<Element> beans = root.elements("bean");
for (Element bean : beans) {
String classValue = bean.attributeValue("class");
String id = bean.attributeValue("id");
System.out.println(id + " " + classValue);
Class<?> clazz = Class.forName(classValue);
//懒加载,用的时候实例化
classMap.put(id, clazz);
}
} catch (DocumentException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
@Override
public Object getBean(String id) {
Class<?> c = classMap.get(id);
if (c != null) {
//单例化
Object o = map.get(id);
if (o == null) {
try {
o = c.newInstance();
if (c.isAnnotationPresent(AOP.class)) {
o = Proxy.newProxyInstance(this.getClass().getClassLoader(),
o.getClass().getInterfaces(),
new InvocationHandlerImpl(o));
}
map.put(id, o);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
return map.get(id);
}
}