Java动态获取实现类的方式详解
作者:Java个体户
应用场景
支付的时候,有不同的渠道,比如微信还是支付宝?
这个时候,就需要根据渠道类型,选择走哪个渠道。
读
先来看下读
/** * 根据接口和注解@SupportCodes的值,获取接口实现类 * * @param interfaceClass 接口 * @param sopportCode 接口实现类的注解@SupportCodes的值 * @return 接口实现类 */ public static <T> T getServiceImpl(Class<T> interfaceClass, String sopportCode) { // 如果没有初始化,则初始化 if (null == serviceImplFactoryMap.get(interfaceClass)) { // 初始化 init(interfaceClass); if (null == serviceImplFactoryMap) { return null; } } // 如果初始化后,还是没有,则返回null if (null == serviceImplFactoryMap.get(interfaceClass)) { return null; } // 返回接口实现类 return (T)((Map)serviceImplFactoryMap.get(interfaceClass)).get(sopportCode); }
为什么要先看读?读是需求,因为有读的需求,才需要实现写的功能。
重点来看入参,任何功能,无非是入参和出参。
入参:接口和渠道代码。
出参:渠道实现类。
那具体怎么实现呢?
类似这种需求,基本上都是map。key是渠道代码,value实现类。
大概的实现思路,基本上就是这样。存储用到的数据结构是map。
写
刚才看了读方法,再来看下写。
读,无非是从map读。写,也一样,无非是把数据写到map。
那具体怎么写呢?直接看代码
/** * 初始化 * * @param interfaceClass 接口 * @author javaself */ protected static <T> void init(Class<T> interfaceClass) { log.info("begin to init " + interfaceClass); synchronized (FactoryUtil.class) { try { // 如果已经初始化,则返回 if (null != serviceImplFactoryMap.get(interfaceClass)) { return; } Map<String, Object> serviceMap = new HashMap(); // 获取所有实现类 Map<String, T> beans = appContext.getBeansOfType(interfaceClass); //实现类名字作为key,实现类实例作为value Set<Entry<String, T>> entrySet = beans.entrySet(); Iterator<Entry<String, T>> iterator = entrySet.iterator(); // 遍历所有实现类,获取注解@SupportCodes的值,作为key,实现类实例作为value while (iterator.hasNext()) { Object interfaceServiceImpl = ((Entry)iterator.next()).getValue(); SupportCodes annotationValue = (SupportCodes)interfaceServiceImpl.getClass().getAnnotation(SupportCodes.class); if (null != annotationValue) { for (String flag : annotationValue.value()) { //可能有多个注解值,所以遍历 //写到map: key=注解值,value=实现类实例 serviceMap.put(flag, interfaceServiceImpl); log.info(flag + "=>" + interfaceServiceImpl.getClass()); } } } //写到map: key=接口,value=上面的map serviceImplFactoryMap.put(interfaceClass, serviceMap); } catch (Exception e) { log.error("init failed", e); throw new RuntimeException(e); } } log.info(interfaceClass + "inited"); }
写方法的入参是:接口。
也就是说,根据接口,可以获取不同实现类。具体是基于spring的获取bean的功能。
拿到不同实现类之后,再根据注解代码,组装成key/value写到map。key是注解代码,value是实现类。
注解代码是干嘛用的?就是前面的渠道代码。属于业务代码。具体是基于自定义注解实现。自定义注解用的时候,有几步,首先,是自定义注解,其次,注解到类上面去,最后,读注解的值的时候直接使用spring提供的工具类即可。
到这里其实基本上已经写完了,核心思路就是怎么玩弄渠道代码和渠道实现类。
何时写?
读的时候,写。也就是说,第一次用到的时候,写。而不是启动项目的时候,写。
只需要写一次即可,也就是说,只在第一次用到的时候,才写。后面直接用即可。
写的时候,注意并发问题。类似这种只写一次,但是又需要注意并发问题的情况,一般直接使用同步关键字即可。
何时读?
支付系统里面根据接口和渠道代码,决定走哪个渠道实现类
IGetPayInstructionService payService = FactoryUtil.getServiceImpl(IGetPayInstructionService.class, channelCode);
渠道代码的值,从哪里来?网关入口会判断。具体的话,用微信还是支付宝扫码的时候,可以根据请求头判断是哪个app。
完整代码
工具类
package com.xxx.commons.factory; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.support.AbstractApplicationContext; import org.springframework.stereotype.Component; /** * 工厂工具类:用于获取接口实现类 * * --- * 应用场景:当一个接口有多个实现类时,通过该工具类获取对应的实现类。 * 不同实现类,通过注解@SupportCodes来区分。获取的时候,也是通过@SupportCodes的值来获取。 * * --- * 举例说明 * * 不同渠道的支付接口,都实现了IPayService接口,如下:微信支付、支付宝支付 * * @author javaself */ @Component public class FactoryUtil implements ApplicationContextAware { private static Log log = LogFactory.getLog(FactoryUtil.class); private static Map<Class<?>, Map<String, Object>> serviceImplFactoryMap = new HashMap(); private static AbstractApplicationContext appContext; /** * 根据接口和注解@SupportCodes的值,获取接口实现类 * * @param interfaceClass 接口 * @param sopportCode 接口实现类的注解@SupportCodes的值 * @return 接口实现类 */ public static <T> T getServiceImpl(Class<T> interfaceClass, String sopportCode) { // 如果没有初始化,则初始化 if (null == serviceImplFactoryMap.get(interfaceClass)) { // 初始化 init(interfaceClass); if (null == serviceImplFactoryMap) { return null; } } // 如果初始化后,还是没有,则返回null if (null == serviceImplFactoryMap.get(interfaceClass)) { return null; } // 返回接口实现类 return (T)((Map)serviceImplFactoryMap.get(interfaceClass)).get(sopportCode); } /** * 初始化 * * @param interfaceClass 接口 * @author javaself */ protected static <T> void init(Class<T> interfaceClass) { log.info("begin to init " + interfaceClass); synchronized (FactoryUtil.class) { try { // 如果已经初始化,则返回 if (null != serviceImplFactoryMap.get(interfaceClass)) { return; } Map<String, Object> serviceMap = new HashMap(); // 获取所有实现类 Map<String, T> beans = appContext.getBeansOfType(interfaceClass); //实现类名字作为key,实现类实例作为value Set<Entry<String, T>> entrySet = beans.entrySet(); Iterator<Entry<String, T>> iterator = entrySet.iterator(); // 遍历所有实现类,获取注解@SupportCodes的值,作为key,实现类实例作为value while (iterator.hasNext()) { Object interfaceServiceImpl = ((Entry)iterator.next()).getValue(); SupportCodes annotationValue = (SupportCodes)interfaceServiceImpl.getClass().getAnnotation(SupportCodes.class); if (null != annotationValue) { for (String flag : annotationValue.value()) { //可能有多个注解值,所以遍历 //写到map: key=注解值,value=实现类实例 serviceMap.put(flag, interfaceServiceImpl); log.info(flag + "=>" + interfaceServiceImpl.getClass()); } } } //写到map: key=接口,value=上面的map serviceImplFactoryMap.put(interfaceClass, serviceMap); } catch (Exception e) { log.error("init failed", e); throw new RuntimeException(e); } } log.info(interfaceClass + "inited"); } public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { appContext = (AbstractApplicationContext)applicationContext; } }
注解类
package com.xxx.commons.factory; import java.lang.annotation.Annotation; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target({java.lang.annotation.ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface SupportCodes { String[] value(); }
接口实现类
/** * 微信公众号支付 * */ @SupportCodes("WeChatPay") @Service public class WeChatPayService implements IGetPayInstructionService {
以上就是Java动态获取实现类的方式详解的详细内容,更多关于Java动态获取实现类的资料请关注脚本之家其它相关文章!