动态代理和Threadlocal
这样的话就可以两全其美,我重点想说的是,两个动态代理同时运行时,执行过程是怎样的?
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import javax.sql.DataSource;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class DaoUtils {
private static DataSource source=new ComboPooledDataSource();
private DaoUtils(){
}
//普通情况
/*
public static DataSource getSource(){
return source;
}*/
/**
* 改造此方法,在调用这个方法时检查,当前线程是否开启过事务
* 如果没有开启事务,返回的是最普通的数据源
* 如果开启过过事务,则返回改造过的数据源--改造底层获取连接的getConnection
*/
public static DataSource getSource(){
if(TransactionManager.hasStarTran()){
//开启过事务,返回一个改造getConnection--每次返回都开启了事务的的连接,此方法每次都返回,当前线程
DataSource proxy= (DataSource) Proxy.newProxyInstance(source.getClass().getClassLoader(),
source.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//if("getconnction".equals(method.getName())){
if("getConnection".equals(method.getName())){
//当前调用getConnection方法,使它每次都返回当前的线程变量中保存当前线程中使用开启事务的连接
final Connection conn=TransactionManager.getconn();
Connection proxy2= (Connection) Proxy.newProxyInstance(conn.getClass().getClassLoader(),
conn.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if("close".equals(method.getName())){
return null;//什么也不做
}else{
return method.invoke(conn, args) ;
}
}
});
return proxy2;
}else{
return method.invoke(source, args);
}
}
});
return proxy;
}else{//如果没有开启事务,就返回
return source;
}
}
public static Connection conn(){
try {
return source.getConnection();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}
事务的工具类:
import java.sql.Connection;
import javax.sql.DataSource;
import org.apache.commons.dbutils.DbUtils;
public class TransactionManager {
/*因为存在多个线程共用一个连接,一个ThreadLocal代表一个变量,
故其中里只能放一个数据,你有两个变量都要线程范围内共享,
则要定义两个ThreadLocal对象。如果有一个百个变量要线程共享呢?
那请先定义一个对象来装这一百个变量,然后在ThreadLocal中存储这一个对象。*/
/*private static ThreadLocal<Connection> conn_local=new ThreadLocal<Connection>(){
protected Connection initialValue() {
return DaoUtils.conn();//连接数据库
}
};*/
private static ThreadLocal<Connection> conn_local=new ThreadLocal<Connection>(){
@Override
protected Connection initialValue() {
return DaoUtils.conn();
};
};
//判断是否开启事务
private static ThreadLocal<Boolean> hasStarTran_local=new ThreadLocal<Boolean>(){
@Override
protected Boolean initialValue() {
return false;
};
};
private TransactionManager(){
}
//开启事务
public static void startTran(){
try {
conn_local.get().setAutoCommit(false);
//开启事务
hasStarTran_local.set(true);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
//判断是否开启事务
public static boolean hasStarTran(){
return hasStarTran_local.get();
}
//提交事务
public static void commit(){
try {
conn_local.get().commit();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
//回滚事务
public static void rollback(){
try {
conn_local.get().rollback();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
public static Connection getconn(){
return conn_local.get();
}
//释放连接
public static void release(){
DbUtils.closeQuietly(conn_local.get());
conn_local.remove();
hasStarTran_local.remove();
}
}
public class MyInvocationHandler implements InvocationHandler {
// 目标对象
private Object target;
/**
* 构造方法
* @param target 目标对象
*/
public MyInvocationHandler(Object target) {
super();
this.target = target;
}
/**
* 执行目标对象的方法
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 在目标对象的方法执行之前
System.out.println("------------------before------------------");
// 执行目标对象的方法
Object result = method.invoke(target, args);
// 在目标对象的方法执行之后
System.out.println("-------------------after------------------");
return result;
}
/**
* 获取目标对象的代理对象
* @return 代理对象
*/
public Object getProxy() {
return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
target.getClass().getInterfaces(), this);
}
}
下面是动态代理的源码:类加载器,一大堆接口,还有就是代理的实现类
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
if (h == null) {
throw new NullPointerException();
}
/*
* Look up or generate the designated proxy class.
*/
Class<?> cl = getProxyClass0(loader, interfaces); // stack walk magic: do not refactor
/*
* 调用它的构造函数指定调用处理程序。
*/
try {
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
SecurityManager sm = System.getSecurityManager();
if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(cl)) {
// create proxy instance with doPrivilege as the proxy class may
// implement non-public interfaces that requires a special permission
return AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
return newInstance(cons, ih);
}
});
} else {
return newInstance(cons, ih);
}
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString());
}
}
private static Object newInstance(Constructor<?> cons, InvocationHandler h) {
try {
return cons.newInstance(new Object[] {h} );
} catch (IllegalAccessException | InstantiationException e) {
throw new InternalError(e.toString());
} catch (InvocationTargetException e) {
Throwable t = e.getCause();
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
} else {
throw new InternalError(t.toString());
}
}
}
/**
* Returns true if and only if the specified class was dynamically
* generated to be a proxy class using the {@code getProxyClass}
* method or the {@code newProxyInstance} method.
*
* <p>The reliability of this method is important for the ability
* to use it to make security decisions, so its implementation should
* not just test if the class in question extends {@code Proxy}.
*
* @param cl the class to test
* @return {@code true} if the class is a proxy class and
* {@code false} otherwise
* @throws NullPointerException if {@code cl} is {@code null}
*/
public static boolean isProxyClass(Class<?> cl) {
if (cl == null) {
throw new NullPointerException();
}
return proxyClasses.containsKey(cl);
}
/**
* Returns the invocation handler for the specified proxy instance.
*
* @param proxy the proxy instance to return the invocation handler for
* @return the invocation handler for the proxy instance
* @throws IllegalArgumentException if the argument is not a
* proxy instance
*/
public static InvocationHandler getInvocationHandler(Object proxy)
throws IllegalArgumentException
{
/*
* Verify that the object is actually a proxy instance.
*/
if (!isProxyClass(proxy.getClass())) {
throw new IllegalArgumentException("not a proxy instance");
}
Proxy p = (Proxy) proxy;
return p.h;
}
进去ProxyGenerator类的静态方法generateProxyClass,这里是真正生成代理类class字节码的地方。
你可以去你的web-info目录下的classes中看到用到动态代理的类,都会多出一个字节码文件。带$的,
可以用ju-gui(反编译工具)看到,里面就是一个代理对象。
public static byte[] generateProxyClass(final String name,
Class[] interfaces)
{
ProxyGenerator gen = new ProxyGenerator(name, interfaces);
final byte[] classFile = gen.generateClassFile();
// 如果saveGeneratedFiles的值为true,则会把所生成的代理类的字节码保存到硬盘上
if (saveGeneratedFiles) {
java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction<Void>() {
public Void run() {
try {
FileOutputStream file =
new FileOutputStream(dotToSlash(name) + ".class");
file.write(classFile);
file.close();
return null;
} catch (IOException e) {
throw new InternalError(
"I/O exception saving generated file: " + e);
}
}
});
}
// 返回代理类的字节码
return classFile;
}