当动态代理遇到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);
    }
}

 

posted on 2020-04-29 17:09  silyvin  阅读(368)  评论(0编辑  收藏  举报