乐趣区

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

上一篇 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<DeviceHandler> {}

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<String> 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<String> 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<Class<?>> 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<ClientType, Object> 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<String,?> classMap =SpringUtil.getBeansOfType(Class.forName(className));
        log.info("DynamicProxyBeanFactory className:{} impl class:{}",className,classMap);

        for (Map.Entry<String,?> 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> T newMapperProxy(String typeName,Class<T> 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 容器

退出移动版