也不知道这个叫什么,反正自己没事搞出来感觉挺有意思,拿出来分享一下:
这个小玩意在 对外部访问只提供一个接口,而在内部根据请求中的参数匹配方法。
现在上代码:
/**
* 异步通知处理接口
*
* @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);
}
}
自己写这些代码是为了解决之前做支付的第三方异步通知很多,而且没个异步通知都带有一个标识字符串,自己以前用枚举和和选择器确定调用哪个方法,由于太多而且生产的过程中一直在增加接口,所以想了这样一个办法,这样做只需要多写一个实现了接口的子类,将唯一标识使用注解标注,就可以了。感觉上方便很多。