对外接口封装--注解+反射+泛型 的运用

   也不知道这个叫什么,反正自己没事搞出来感觉挺有意思,拿出来分享一下:

  这个小玩意在  对外部访问只提供一个接口,而在内部根据请求中的参数匹配方法。

现在上代码:

/**
 * 异步通知处理接口
 *
 * @create 2018-05-09 10:08
 **/
public interface AsyncMsgFailureManage<V,T> {


    /**
     * 统一处理放法
     *
     * @author 刘俊汉
     * @date 2018/5/9 10:39
     * @param []
     * @return void
     */
    V asyncMsgFailureManage(T t);


}

所有接口的服务类,任何被封装的处理逻辑类实现该接口。

实现类:

/**
 * 会员激活接收异步回调失败时处理方法
 *
 * @author 刘俊汉
 * @create 2018-05-09 10:41
 **/
@Component
@ServiceName(serviceName = "ACTIVATE_STOCKED_USER")
public class ActivateStockedUserAsyncMsgFailureManage implements AsyncMsgFailureManage<Integer,Object> {




    /**
     *
     * 会员激活未接受到异步通知时的处理方法
     * @author 刘俊汉
     * @date 2018/5/9 10:42
     * @param t
     * @return void
     */
    @Override
    public Integer asyncMsgFailureManage(Object t) {


        System.out.println("===============我是会员激活处理方法================");

        return null;
    }
}

@ServiceName这个注解是自己生成的,没有这个,整个代码都说不通。

/**
 * Created by liujunhan on 2018/5/9.
 */
@Target(ElementType.TYPE)//表示只能给类添加该注解
@Retention(RetentionPolicy.RUNTIME)//这个必须要将注解保留在运行时
public @interface ServiceName {

    String  serviceName()  default  "DEFAULT";
}

 

我的项目里我使用了很多实例,这里贴出一个作为例子,下边看看使用这些类是如何被使用的。

/**
 * 根据注解获取相应的bean
 *
 * @author 刘俊汉
 * @create 2018-05-09 11:28
 **/
public class BeanGetFactory {
    /**
     *  这里是一个常量,表示我们扫描策略的包
     */

    private static final String BEAN_GET_PACKAGE = "com.yipuhui.fastgo.utils.factory";

    private ClassLoader classLoader = getClass().getClassLoader();


    private List<Class<? extends AsyncMsgFailureManage>> asyncMsgFailureManages;


    /**
     * 获取对应的实例
     *
     * @param []
     * @return com.yipuhui.fastgo.utils.factory.AsyncMsgFailureManage
     * @author 刘俊汉
     * @date 2018/5/9 12:02
     */
    public AsyncMsgFailureManage ceretBean(String serviceName) {

        for (Class<? extends AsyncMsgFailureManage> clazz : asyncMsgFailureManages) {
            //获取该策略的注解
            ServiceName serviceName1 = handleAnnotation(clazz);


            if (serviceName1.serviceName().equals(serviceName)) {

                return SpringUtil.getBean(clazz);


            }


        }

        return null;

    }


    /**
     * Description:处理注解,我们传入一个策略类,返回它的注解
     *
     * @author 刘俊汉
     * @param null
     * @date 2018/5/14 15:35
     * @return
     */
    private ServiceName handleAnnotation(Class<? extends AsyncMsgFailureManage> clazz) {
        Annotation[] annotations = clazz.getDeclaredAnnotations();
        if (annotations == null || annotations.length == 0) {
            return null;
        }
        for (int i = 0; i < annotations.length; i++) {
            if (annotations[i] instanceof ServiceName) {

                System.out.println( annotations[i]);
                return (ServiceName) annotations[i];
            }
        }
        return null;
    }


    //工厂类单例模式

    private BeanGetFactory() {

        init();
    }


    private void init() {

        asyncMsgFailureManages = new ArrayList<>();
        //获取到包下所有的class文件
        File[] resources = getResources();

        Class<AsyncMsgFailureManage> asyncMsgFailureManageClass = null;
        try {
            //使用相同的加载器加载接口
            asyncMsgFailureManageClass = (Class<AsyncMsgFailureManage>) classLoader.loadClass(AsyncMsgFailureManage.class.getName());
        } catch (ClassNotFoundException e1) {
            throw new RuntimeException("未找到接口");
        }

        for (int i = 0; i < resources.length; i++) {
            try {
                //载入包下的类
                Class<?> clazz = classLoader.loadClass(BEAN_GET_PACKAGE + "." + resources[i].getName().replace(".class", ""));
                //判断是否是CalPrice的实现类并且不是CalPrice它本身,满足的话加入到策略列表
                if (AsyncMsgFailureManage.class.isAssignableFrom(clazz) && clazz != asyncMsgFailureManageClass) {
                    asyncMsgFailureManages.add((Class<? extends AsyncMsgFailureManage>) clazz);
                }
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }


    }


    private File[] getResources() {

      final   String classname = ".class";
        try {
            File file = new File(classLoader.getResource(BEAN_GET_PACKAGE.replace(".", "/")).toURI());
            return file.listFiles(new FileFilter() {
                @Override
                public boolean accept(File pathname) {
                    //我们只扫描class文件
                    if (pathname.getName().endsWith(classname)) {
                        return true;
                    }
                    return false;
                }
            });
        } catch (URISyntaxException e) {
            throw new RuntimeException("未找到资源");
        }

    }


    private static BeanGetFactory beanGetFactory = null;

    public static BeanGetFactory getInstance() {

        if (beanGetFactory != null) {

            return beanGetFactory;
        }


        synchronized (BeanGetFactory.class) {
            if (beanGetFactory != null) {

                return beanGetFactory;
            } else {

                beanGetFactory = new BeanGetFactory();

                return beanGetFactory;


            }

        }

    }


}

该类使用了单例设计模式,保证整个环境中实例唯一,在该实例中对接口的实现类进行了校验,保存了还有自定义注解的类信息。

并在其他类调用时,使用spring容器中实例化的bean作为返回的子类实例,因为最终只有回到容器里才能更好的使用这些类(类依赖的其他类,数据库连接等)

关于spring获取实例的方式我全部粘到下边,没什么好说的,spring的基础

/**
 * 获取spring bean
 *
 * @author 刘俊汉
 * @create 2018-05-09 10:32
 **/
@Component
public class SpringUtil implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        if(SpringUtil.applicationContext == null) {
            SpringUtil.applicationContext = applicationContext;
        }

    }

    /**
     * Description:获取applicationContext
     *
     * @author 刘俊汉
     * @param null
     * @date 2018/5/14 16:01
     * @return
     */
    private static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    /**
     * Description:通过name获取 Bean.
     *
     * @author 刘俊汉
     * @param null
     * @date 2018/5/14 16:01
     * @return
     */
    public static Object getBean(String name){
        return getApplicationContext().getBean(name);
    }

    /**
     * Description:通过class获取Bean.
     *
     * @author 刘俊汉
     * @param null
     * @date 2018/5/14 16:01
     * @return
     */
    public static <T> T getBean(Class<T> clazz){
        return getApplicationContext().getBean(clazz);
    }

    /**
     * Description:通过name,以及Clazz返回指定的Bean
     *
     * @author 刘俊汉
     * @param null
     * @date 2018/5/14 16:02
     * @return
     */
    public static <T> T getBean(String name,Class<T> clazz){
        return getApplicationContext().getBean(name, clazz);
    }



}

自己写这些代码是为了解决之前做支付的第三方异步通知很多,而且没个异步通知都带有一个标识字符串,自己以前用枚举和和选择器确定调用哪个方法,由于太多而且生产的过程中一直在增加接口,所以想了这样一个办法,这样做只需要多写一个实现了接口的子类,将唯一标识使用注解标注,就可以了。感觉上方便很多。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值