Spring中自定义注解
前言
在我的理解中,从功能上区分,注解分为两类,一类是类似于@Service,定义某种性质,通常在项目启动时就会被注册使用;一类是类似于@Log,实现特定的具体功能,通常在项目运行过程中使用。
在日常开发中,总结了在spring中这两种注解的常用开发方式,备忘。
项目启动时使用的注解
此处参考xxl-job中的@XxlJob注解
@XxlJob注解使用在方法上,标注该方法为调度器远程调用的执行器方法。类似于spring中的定时任务,只不过控制方为远程调度器,具体可以参考 xxl-job详细文档
// 获取所有的单例beanDefinition,第一个参数表示type,第二个参数表示是否接受非单例,第三个参数表示接受懒加载和FactoryBeans
String[] beanDefinitionNames = applicationContext.getBeanNamesForType(Object.class, false, true);
for (String beanDefinitionName : beanDefinitionNames) {
// 获取bean
Object bean = applicationContext.getBean(beanDefinitionName);
// 获取XxlJob注解的方法集合
Map<Method, XxlJob> annotatedMethods = null; // referred to :org.springframework.context.event.EventListenerMethodProcessor.processBean
try {
annotatedMethods = MethodIntrospector.selectMethods(bean.getClass(),
new MethodIntrospector.MetadataLookup<XxlJob>() {
@Override
public XxlJob inspect(Method method) {
return AnnotatedElementUtils.findMergedAnnotation(method, XxlJob.class);
}
});
} catch (Throwable ex) {
logger.error("xxl-job method-jobhandler resolve error for bean[" + beanDefinitionName + "].", ex);
}
if (annotatedMethods==null || annotatedMethods.isEmpty()) {
continue;
}
//遍历方法集合,实现特定功能
for (Map.Entry<Method, XxlJob> methodXxlJobEntry : annotatedMethods.entrySet()) {
Method method = methodXxlJobEntry.getKey();
XxlJob xxlJob = methodXxlJobEntry.getValue();
if (xxlJob == null) {
continue;
}
String name = xxlJob.value();
if (name.trim().length() == 0) {
throw new RuntimeException("xxl-job method-jobhandler name invalid, for[" + bean.getClass() + "#" + method.getName() + "] .");
}
if (loadJobHandler(name) != null) {
throw new RuntimeException("xxl-job jobhandler[" + name + "] naming conflicts.");
}
// execute method
if (!(method.getParameterTypes().length == 1 && method.getParameterTypes()[0].isAssignableFrom(String.class))) {
throw new RuntimeException("xxl-job method-jobhandler param-classtype invalid, for[" + bean.getClass() + "#" + method.getName() + "] , " +
"The correct method format like \" public ReturnT<String> execute(String param) \" .");
}
if (!method.getReturnType().isAssignableFrom(ReturnT.class)) {
throw new RuntimeException("xxl-job method-jobhandler return-classtype invalid, for[" + bean.getClass() + "#" + method.getName() + "] , " +
"The correct method format like \" public ReturnT<String> execute(String param) \" .");
}
method.setAccessible(true);
// init and destory
Method initMethod = null;
Method destroyMethod = null;
// 初始化方法
if (xxlJob.init().trim().length() > 0) {
try {
initMethod = bean.getClass().getDeclaredMethod(xxlJob.init());
initMethod.setAccessible(true);
} catch (NoSuchMethodException e) {
throw new RuntimeException("xxl-job method-jobhandler initMethod invalid, for[" + bean.getClass() + "#" + method.getName() + "] .");
}
}
// 销毁方法
if (xxlJob.destroy().trim().length() > 0) {
try {
destroyMethod = bean.getClass().getDeclaredMethod(xxlJob.destroy());
destroyMethod.setAccessible(true);
} catch (NoSuchMethodException e) {
throw new RuntimeException("xxl-job method-jobhandler destroyMethod invalid, for[" + bean.getClass() + "#" + method.getName() + "] .");
}
}
// registry jobhandler 对该方法进行注册,用于远程调度器进行远程调度
registJobHandler(name, new MethodJobHandler(bean, method, initMethod, destroyMethod));
}
}
1、XxlJobSpringExecutor中implements ApplicationContextAware, SmartInitializingSingleton,获得applicationContext,并且在spring项目加载完成后,调用afterSingletonsInstantiated()方法,实现特定功能。
2、通过applicationContext对象获取所有的beanDefinitionNames。
3、获取XxlJob注解的方法集合。
4、对方法集合进行遍历,获取注解的属性,用于实现特定功能;
5、获取初始化方法和销毁方法。
6、对该方法进行注册,用于调度器远程调用。
项目过程中使用的注解
Spring中的AOP切面,可以很方便的实现项目过程中的注解开发,可以参考Spring项目中自定义注解的使用。