zoukankan      html  css  js  c++  java
  • 当动态代理遇到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);
        }
    }
    
  • 相关阅读:
    dapper+linq+json+ztree构建树
    ubuntu,从一个新用户,要转到新用户的命令行操作
    OC本学习笔记Foundatio框架集
    无法Debug SQL: Unable to start T-SQL Debugging. Could not attach to SQL Server process on
    Struts2 + uploadify 多文件上传完整的例子!
    How use Instruments and display the console in Command Lines applications
    Android ActionBar详解(二):ActionBar实现Tabs标签以及下拉导航
    Android ActionBar详解(一):ActionBar概述及其创建
    Android Fragment详解(六):Fragement示例
    Android Fragment详解(五):Fragment与Activity通讯
  • 原文地址:https://www.cnblogs.com/silyvin/p/12803333.html
Copyright © 2011-2022 走看看