资讯专栏INFORMATION COLUMN

SpringBoot 动态代理|反射|注解|AOP 优化代码(三)-注解

Charles / 2770人阅读

摘要:上一篇动态代理反射注解优化代码二反射我们实现了通过反射完善找到目标类,然后通过动态代理提供默认实现,本篇我们将使用自定义注解来继续优化。下一篇动态代理反射注解四动态代理对象注入到容器

上一篇SpringBoot 动态代理|反射|注解|AOP 优化代码(二)-反射

我们实现了通过反射完善找到目标类,然后通过动态代理提供默认实现,本篇我们将使用自定义注解来继续优化。

创建注解

1.创建枚举 ClientType,用来标明Handler的实现方式

public enum ClientType {
    FEIGN,URL
}

2.创建注解ApiClient,用来标明Handler的实现方式

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ApiClient {
    ClientType type();
}

3.创建HandlerRouterAutoImpl注解,来标记该HandlerRouter是否通过代理提供默认实现

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface HandlerRouterAutoImpl {
   /**
    * 在spring容器中对应的名称
    * @return
    */
   String name();
}

4.DeviceHandlerRouter添加注解,以动态代理提供默认实现

@HandlerRouterAutoImpl(name = "deviceHandlerRouter")
public interface DeviceHandlerRouter extends HandlerRouter {
}

5.DeviceHandlerFeignImpl、DeviceHandlerUrlImpl 添加注解标明具体的实现方式

@ApiClient(type = ClientType.FEIGN)
@Component
@Slf4j
public class DeviceHandlerFeignImpl implements DeviceHandler {

    @Autowired
    private DeviceFeignClient deviceFeignClient;

    @Override
    public void remoteAddBatch(RemoteAddDeviceParam remoteAddDeviceParam, Integer envValue) {
        RestResult restResult = deviceFeignClient.create(remoteAddDeviceParam);
        ...
    }

    @Override
    public void remoteDeleteBatch(Integer envValue, List snsList) {   
        RestResult restResult = deviceFeignClient.deleteBySnList(snsList);      
        ... 
    }   
  
}
@ApiClient(type = ClientType.URL)
@Component
@Slf4j
public class DeviceHandlerUrlImpl implements DeviceHandler {

    @Override
    public void remoteAddBatch(RemoteAddDeviceParam remoteAddDeviceParam, Integer envValue) {
        String url = getAddUrlByEnvValue(envValue);
        String response = OkHttpUtils.httpPostSyn(url, JSON.toJSONString(snsList), false);
        RestResult restResult = JSON.parseObject(response, RestResult.class);
        ...
    }

    @Override
    public void remoteDeleteBatch(Integer envValue, List snsList) {
        String url = getDelUrlByEnvValue(envValue);
        String response = OkHttpUtils.httpPostSyn(url, JSON.toJSONString(snsList), false);
        RestResult restResult = JSON.parseObject(response, RestResult.class);
        ...
    }
}

6.通过注解扫描目标类

扫描HandlerRouterAutoImpl注解的类,通过动态代理提供默认的实现

    /**
     * 通过反射扫描出所有使用注解HandlerRouterAutoImpl的类
     * @return
     */
    private Set> getAutoImplClasses() {
        Reflections reflections = new Reflections(
                "io.ubt.iot.devicemanager.impl.handler.*",
                new TypeAnnotationsScanner(),
                new SubTypesScanner()
        );
        return reflections.getTypesAnnotatedWith(HandlerRouterAutoImpl.class);
    }

动态代理类中,获取业务接口的实现类,并获取ApiClient注解,然后分类,保存到Map中。以在调用getHandler方式时根据传入的环境值,返回不同实现方式的实例。

@Slf4j
public class DynamicProxyBeanFactory implements InvocationHandler {
    private String className;
    private Map clientMap = new HashMap<>(2);

    public DynamicProxyBeanFactory(String className) {
        this.className = className;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //获取过一次后不再获取
        if (clientMap.size() == 0) {
            initClientMap();
        }
        
        //如果传入的参数是1,就返回通过Feign方式实现的类 (该逻辑只是用来举例)
        Integer env = (Integer) args[0];
        return 1 == env.intValue() ? clientMap.get(ClientType.FEIGN) : clientMap.get(ClientType.URL);
    }

    private void initClientMap() throws ClassNotFoundException {
        //获取classStr 接口的所有实现类
        Map classMap =SpringUtil.getBeansOfType(Class.forName(className));
        log.info("DynamicProxyBeanFactory className:{} impl class:{}",className,classMap);

        for (Map.Entry entry : classMap.entrySet()) {
            //根据ApiClientType注解将实现类分为Feign和Url两种类型
            ApiClient apiClient = entry.getValue().getClass().getAnnotation(ApiClient.class);
            if (apiClient == null) {
                continue;
            }
            clientMap.put(apiClient.type(), entry.getValue());
        }
        log.info("DynamicProxyBeanFactory clientMap:{}",clientMap);
    }


    public static  T newMapperProxy(String typeName,Class mapperInterface) {
        ClassLoader classLoader = mapperInterface.getClassLoader();
        Class[] interfaces = new Class[]{mapperInterface};
        DynamicProxyBeanFactory proxy = new DynamicProxyBeanFactory(typeName);
        return (T) Proxy.newProxyInstance(classLoader, interfaces, proxy);
    }
}

以上我们通过注解、动态代理、反射就实现了通过注解,找到需要提供默认实现的HandlerRouter子类,并通过动态代理提供默认实现。
还有一个问题:通过代理生成的对象,该怎么管理,我们并不想通过代码,手动管理。如果能把动态代理生成的对象交给spring容器管理,其它代码直接自动注入就可以了。

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

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/75283.html

相关文章

  • SpringBoot 动态代理|反射|注解|AOP 优化代码(二)-反射

    摘要:动态代理反射注解优化代码一动态代理提供接口默认实现我们抛出问题,并且提出解决问题的第一步的方法。重写动态代理类,实现通过的查找出传入的所有泛型的实现下一篇动态代理反射注解优化代码三注解 SpringBoot 动态代理|反射|注解|AOP 优化代码(一)-动态代理提供接口默认实现 我们抛出问题,并且提出解决问题的第一步的方法。下面我们继续深入,动态代理和反射继续解决我们的问题。 改动代...

    spacewander 评论0 收藏0
  • SpringBoot 动态代理|反射|注解|AOP 优化代码(一)-动态代理提供接口默认实现

    摘要:生产环境由注册中心,通过调用,其它环境直接通过直接通过调用。当然动态代理提供接口的默认实现只是演示,并没有什么实际内容。下一篇动态代理反射注解优化代码二反射 一、背景 在项目中需要调用外部接口,由于需要调用不同环境(生产、测试、开发)的相同接口(例如:向生、测试、开发环境的设备下发同一个APP)。 1.生产环境由SpringCloud注册中心,通过Feign调用, 2.其它环境直接通过...

    mj 评论0 收藏0
  • SpringBoot 动态代理|反射|注解(四)- 动态代理对象注入到Spring容器

    摘要:上一篇动态代理反射注解优化代码三注解本篇我们将实现通过代理生成的对象注入到容器中。单元测试优化代码待续参考文章 上一篇:SpringBoot 动态代理|反射|注解|AOP 优化代码(三)-注解 本篇我们将实现通过代理生成的对象注入到spring容器中。首先需要实现BeanDefinitionRegistryPostProcessor, ApplicationContextAware两个...

    lingdududu 评论0 收藏0
  • Aop?看这篇文章就够了!!!

    摘要:又是什么其实就是一种实现动态代理的技术,利用了开源包,先将代理对象类的文件加载进来,之后通过修改其字节码并且生成子类。 在实际研发中,Spring是我们经常会使用的框架,毕竟它们太火了,也因此Spring相关的知识点也是面试必问点,今天我们就大话Aop。特地在周末推文,因为该篇文章阅读起来还是比较轻松诙谐的,当然了,更主要的是周末的我也在充电学习,希望有追求的朋友们也尽量不要放过周末时...

    boredream 评论0 收藏0

发表评论

0条评论

Charles

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<