当动态代理遇到ioc
在 work log 2020.4.28中,我们使用jdk动态代理处理方法的事务增强
图1 问题的引出
根本原因:动态代理和cglib,会丢掉被代理类成员变量和方法上的注解
起先,我们禁止被增强的类里面使用注解注入依赖,代码会自动审核这种情况
private static final class TransactionProxyProvider<T> implements Provider<T> { private Object target; public TransactionProxyProvider(Object target) { this.target = target; } @Override public T get() { try { // Class cl = target.getClass(); // Field [] fields = cl.getDeclaredFields(); // for(Field field : fields) { // field.setAccessible(true); // if(field.isAnnotationPresent(Inject.class)) // throw new RuntimeException("proxy class do not allow com.google.inject annotation - " + cl.getName()); // } return (T)new TransactionProxyFactory(target).getProxyInstance(); } catch (Exception e) { loggerCommon.error(e.getMessage(), e); } return null; } }
实用性太差,放弃
后来有了图2 解决方案,有点像:结合自定义注解的 spring 动态注入中UserServic自动装配到UserController中,UserService是带@Service类,UserController是动态注入的类,手动将工厂中UserService实例装配到UserController 的userService对象上
设计用例:
本文中,分三步走
1 设原始类A,代理类APlus对A进行JDK动态代理,通过@Bean(spring)或Provider(guice)手动注入类到factory
2 其它环境中的类会依赖A,以@Autowired(spring)或@Inject(guice)修饰
2 A本身依赖的类在private对象(设b)上,由于A没有注入,注入的是其代理类APlus,故A上的以@Autowired(spring)或@Inject(guice)修饰的依赖不会自动装配,我们手动将工厂中相应类型的实例set上去,运行期查看b是否为null
work log 中有1 2 3详细代码
JDK动态代理代码:
public class TransactionProxyFactory implements InvocationHandler { private Object target; public TransactionProxyFactory(Object target){ this.target = target; } // private <T> T getBeanFromFactoryGuice(Class<T> c) { // Injector injector = CRFGuiceContext.getInjector(); // return injector.getInstance(c); // } // // private Class getBeanInjectAnnotationGuice() { // return com.google.inject.Inject.class; // } private <T> T getBeanFromFactorySpring(Class<T> c) { return (T)SpringContextUtil.getBean(c); } private Class getBeanInjectAnnotationSpring() { return org.springframework.beans.factory.annotation.Autowired.class; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Class clProxy = target.getClass(); Field[] fields = clProxy.getDeclaredFields(); for(Field field : fields) { field.setAccessible(true); if(!field.isAnnotationPresent(getBeanInjectAnnotationSpring())) continue; String name = field.getName(); Class fieldType = field.getType(); Object obj = getBeanFromFactorySpring(fieldType); if(obj != null) field.set(target, obj); } SCEF_DB_TRANSACTIONAL scef_db_transactional = method.getAnnotation(SCEF_DB_TRANSACTIONAL.class); if(scef_db_transactional != null) { ScefOrmSession scefOrmSession = getBeanFromFactorySpring(ScefOrmSession.class); Boolean readOnly = scef_db_transactional.readOnly(); int isolation = scef_db_transactional.isolation(); try { scefOrmSession.startTransaction(readOnly, isolation); Object returnValue = method.invoke(target, args); scefOrmSession.commit(); return returnValue; } catch (InvocationTargetException ie) { Throwable throwable = ie.getTargetException(); Class c1 = throwable.getClass(); Class [] c2 = scef_db_transactional.noRollbackFor(); int sum = 0; for(Class c : c2) { if(c.equals(c1)) sum ++ ; } if(sum == 0) scefOrmSession.rollback(); else scefOrmSession.commit(); throw new DBException(throwable); } catch (Exception e) { throw new DBException(e); } finally { scefOrmSession.endTransaction(); } } else { Object returnValue = method.invoke(target, args); return returnValue; } } //给目标对象生成代理对象 public Object getProxyInstance(){ return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); } }