美文网首页
动态代理注册到Spring容器

动态代理注册到Spring容器

作者: 淡淡的橙子 | 来源:发表于2020-05-26 22:10 被阅读0次

    1.前言

    在项目中,遇到了一个这样的需求。
    我们有一个默认的持久化层实现:

    public class BasePersistence {
        String db;
        String item;
    
        public Id queryId() {
        }
        ...
    }
    

    不同的表的持久层如果来完成的话,就需要继承自这个默认化持久层。
    比如我们有一个Vendor的表,则对应的持久层应该是:

    @Resource
    public class VendorPersistenceImpl extends BasePersistence implements IPersistence {
        ...
    }
    

    有一个问题是能不能通过简单的继承一个接口即能完成逻辑的实现,而不用显式子的还要完成一个实现类。
    比如

    @Persistence
    public interface VendorPersistence extends IPersistence {
    }
    

    对于这种情景,一个比较直观的方式就是通过反射+动态代理来进行。

    2. 反射+代理:

    以下扫描所有注解了Persistence的类:

        private Set<Class<?>> getPersistenceClasses() {
            Reflections reflections = new Reflections(
                    "com.lucifer.proxy.*",
                    new TypeAnnotationsScanner(),
                    new SubTypesScanner()
            );
            return reflections.getTypesAnnotatedWith(Persistence.class);
        }
    

    针对该类我们可以通过动态代理来进行:

    @Slf4j
    public class DynamicProxyBeanFactory implements InvocationHandler {
        private BasePersistence persistence;
    
        public DynamicProxyBeanFactory(BasePersistence persistence) {
            this.persistence = persistence;
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
          return method.invoke(proxy, args);
        }
    
        public static <T> T newMapperProxy(String db, String item,Class<T> mapperInterface) {
            ClassLoader classLoader = mapperInterface.getClassLoader();
            Class<?>[] interfaces = new Class[]{mapperInterface};
            DynamicProxyBeanFactory proxy = new DynamicProxyBeanFactory(new BasePersistence(db, item));
            return (T) Proxy.newProxyInstance(classLoader, interfaces, proxy);
        }
    }
    

    调用的时候直接:

    public static void main() {
        IPersistence persistence = DynamicProxyBeanFactory.newMapperProxy("person", "name", IPersistence);
        persistence.findById();
    }
    

    如果我们使用Spring的时候,实际可以更加便捷的在Spring加载的时候把生成的代理动态的注册到Spring容器中。

    3.动态代理注册到Spring容器

    @Slf4j
    @Component
    public class HandlerBeanDefinitionRegistry implements BeanDefinitionRegistryPostProcessor, ApplicationContextAware {
        private ApplicationContext applicationContext;
    
        @Override
        public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
            /**
             * 获取Peresistence注解的接口,这些接口就需要通过动态代理提供默认实现
             */
            Set<Class<?>> classes = getPersistenceClasses();
            for (Class<?> clazz : classes) {
    
                Type[] types = clazz.getGenericInterfaces();
                ParameterizedType type = (ParameterizedType) types[0];
                String typeName = type.getActualTypeArguments()[0].getTypeName();
    
                BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(clazz);
                GenericBeanDefinition definition = (GenericBeanDefinition) builder.getRawBeanDefinition();
                definition.getPropertyValues().add("db", clazz.name());
                definition.getPropertyValues().add("item", "");
                definition.getPropertyValues().add("interfaceClass", clazz);
                definition.getPropertyValues().add("context", applicationContext);
                definition.setBeanClass(DataIoPersistenceInterfaceFactoryBean.class);
                definition.setAutowireMode(GenericBeanDefinition.AUTOWIRE_BY_TYPE);
                beanDefinitionRegistry.registerBeanDefinition(clazz.name(), definition);
            }
        }
    
        @Override
        public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
            log.info("------------------------>postProcessBeanFactory");
        }
    
        /**
         * 通过反射扫描出所有使用HandlerRouterAutoImpl的类
         * @return
         */
        private Set<Class<?>> getAutoImplClasses() {
            Reflections reflections = new Reflections(
                    "com.lucifer.proxy.*",
                    new TypeAnnotationsScanner(),
                    new SubTypesScanner()
            );
            return reflections.getTypesAnnotatedWith(Persistence.class);
        }
    
        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            this.applicationContext = applicationContext;
            log.info("------------------->setApplicationContext");
        }
    
        /**
         * 通过class获取所有该类型的bean
         *
         * @param clazz
         * @return
         */
        private Map<String, T> getBeans(Class<T> clazz) {
            return applicationContext.getBeansOfType(clazz);
        }
    }
    
    
    @Slf4j
    @Data
    public class DataIoPersistenceInterfaceFactoryBean<T> implements FactoryBean<T> {
        private Class<T> interfaceClass;
        private String typeName;
        private ApplicationContext context;
    
        @Override
        public T getObject() throws Exception {
            Object object = DataIoDynamicProxyBeanFactory.newMapperProxy(typeName, interfaceClass, context);
            return (T) object;
        }
    
        @Override
        public Class<?> getObjectType() {
            return interfaceClass;
        }
    
        @Override
        public boolean isSingleton() {
            return true;
        }
    }
    
    @Slf4j
    public class DataIoDynamicProxyBeanFactory {
    
        public static <T> T newMapperProxy(String typeName, Class<T> mapperInterface,
                ApplicationContext applicationContext) {
            ClassLoader classLoader = mapperInterface.getClassLoader();
            Object target = new SimpleDataIoPersistence<>(Class.forName(typeName),
                    applicationContext.getBean(DataIoOperations.class));
            // Create proxy
            ProxyFactory result = new ProxyFactory();
            result.setTarget(target);
            result.setInterfaces(mapperInterface, Persistence.class);
            result.addAdvice(new ProxyPersistence(typeName, mapperInterface));
            return (T) result.getProxy(classLoader);
        }
    }
    
    

    4.参考文章

    SpringBoot 动态代理|反射|注解(四)- 动态代理对象注入到Spring容器

    相关文章

      网友评论

          本文标题:动态代理注册到Spring容器

          本文链接:https://www.haomeiwen.com/subject/mqlbahtx.html