共计 3694 个字符,预计需要花费 10 分钟才能阅读完成。
SpringBoot 动态代理 | 反射 | 注解 |AOP 优化代码 (一)- 动态代理提供接口默认实现 我们抛出问题,并且提出解决问题的第一步的方法。下面我们继续深入,动态代理和反射继续解决我们的问题。
改动代码结构
新增一个 HandlerRougter 接口,其目的就是替代上一篇的 DeviceHandlerRouter
public interface HandlerRouter<T> {T getHandler(Integer env,Object... args);
}
其中 T 是具体的业务接口。下面实现 DeviceHandler 的 HandlerRouter:
public interface DeviceHandlerRouter extends HandlerRouter<DeviceHandler> {}
那么上层代码的调用方式将会类似下面的代码:
DeviceHandlerRouter deviceHandlerRouter = ...
deviceHandlerRouter.getHandler(...). remoteAddBatch(...)
反射 + 动态代理
前面说过,每增加一种接口调用,就需要重新实现 xxxHandlerRouter,那么下面我们通过动态代理和反射提供 DeviceHandler 的默认实现。
1. 通过反射获取 HandlerRouter<T> 的子接口和泛型对应的类
首先加入下面的依赖
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>0.9.10</version>
</dependency>
/**
* 通过反射扫描出所有 HandlerRouter 的子类
* @return
*/
private Set<Class<?>> getHandlerRouterClasses() {
Reflections reflections = new Reflections(
"package.name.*",
new TypeAnnotationsScanner(),// 注解扫描,本节用不到
new SubTypesScanner());
return reflections.getSubTypesOf(HandlerRouter.class);
}
Set<Class<?>> classes = getHandlerRouterClasses();
// 获取 HandlerRouter 的子接口的泛型 Class 例如:DeviceHandlerRouter 接口的 DeviceHandler
for (Class<?> clazz : classes) {
//clazz 对应 DeviceHandlerRouter.class
Type[] types = clazz.getGenericInterfaces();
ParameterizedType type = (ParameterizedType) types[0];
//typeName 对应 DeviceHandlerRouter extends HandlerRouter<DeviceHandler> 中的 DeviceHandler.class
String typeName = type.getActualTypeArguments()[0].getTypeName();}
2.SpringBoot ApplicationContext 获取注入的 bean
修改上一篇中实现的动态代理类,我们想要实现:“能够根据传入的泛型的 Class 获取到 Spring 容器中该类型的所有 bean”,因此我们就需要传入 ApplicationContext。那就需要实现 ApplicationContextAware 接口,下面的代码来自网络。
@Component
public class SpringUtil implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {SpringUtil.applicationContext = applicationContext;}
public static ApplicationContext getApplicationContext() {return applicationContext;}
/**
* 通过 class 获取所有该类型的 bean
* @param clazz
* @return
*/
public static Map<String, ?> getBeans(Class<?> clazz) {return getApplicationContext().getBeansOfType(clazz);
}
}
3. 重新实现动态代理类
@Slf4j
public class DynamicProxyBeanFactory implements InvocationHandler {
private String className;
public DynamicProxyBeanFactory(String className) {
this.className = className;
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 获取实现 className 类的所有 bean
Map<String,?> classMap =SpringUtil.getBeans(Class.forName(className));
log.info("DynamicProxyBeanFactory className:{} impl class:{}",className,classMap);
// 这里先随便返回一个
return classMap.get("deviceHandlerUrlImpl");}
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);
}
}
调用:
Set<Class<?>> classes = getHandlerRouterClasses();
// 获取 HandlerRouter 的子接口的泛型 Class 例如:DeviceHandlerRouter 接口的 DeviceHandler
for (Class<?> clazz : classes) {
//clazz 对应 DeviceHandlerRouter.class
//clazz 对应 DeviceHandlerRouter.class
//clazz 对应 DeviceHandlerRouter.class
Type[] types = clazz.getGenericInterfaces();
ParameterizedType type = (ParameterizedType) types[0];
//typeName 对应 DeviceHandlerRouter extends HandlerRouter<DeviceHandler> 中的 DeviceHandler.class
//typeName 对应 DeviceHandlerRouter extends HandlerRouter<DeviceHandler> 中的 DeviceHandler.class
//typeName 对应 DeviceHandlerRouter extends HandlerRouter<DeviceHandler> 中的 DeviceHandler.class
String typeName = type.getActualTypeArguments()[0].getTypeName();
DeviceHandler deviceHandler = DynamicProxyBeanFactory.newMapperProxy(typeName,clazz);
}
总结:这篇文章我们
1. 通过反射获取了 HandlerRouter 的所有子接口(这里是 DeviceHandlerRouter),以及子接口对应的泛型。
2. 重写动态代理类,实现通过 Spring 的 ApplicationContext 查找出传入的所有泛型的实现 bean