之前有一个需求 写一个自定义注解,然后在项目启动以后获取到所有带自定义注解的方法,然后进行业务分析,查了很多资料,但发现很多不全面,所以自己记录一下
实现ApplicationContextAware和ApplicationListener
之所以ApplicationContextAware和ApplicationListener都需要实现是因为我发现有时候只实现其中一个无法得到想要的结果,接下来细说。
public class TestListener implements ApplicationContextAware, ApplicationListener<ContextRefreshedEvent> {
private ApplicationContext applicationContext;
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
getAnnotationMap(applicationContext);
}
}
通过重写setApplicationContext方法获取applicationContext以便之后获取相关bean。
之前由博客说可以在重写onApplicationEvent方法中通过ContextRefreshedEvent 获得root节点的applicationContext,但是我试过之后在我的情境中无法获得root节点,可能和项目环境有关。
public void onApplicationEvent(ContextRefreshedEvent event) {
// 根容器为Spring容器
if(event.getApplicationContext().getParent()==null){
Map<String,Object> beans = event.getApplicationContext().getBeansWithAnnotation(IMobile.class);
for(Object bean:beans.values()){
System.err.println(bean==null?"null":bean.getClass().getName());
}
System.err.println("=====ContextRefreshedEvent====="+event.getSource().getClass().getName());
}
}
因为ApplicationContextAware的setApplicationContext方法不一定是在所有bean初始化完成后实现的,所以我在onApplicationEvent方法中调用自定义方法,确保此时所有bean都已经初始化完毕。
通过反射获取具体注解
获取到bean以后可以通过反射获取class对象来获取指定注解
Class<?> clazz = bean.getClass();
Method[] ms = clazz.getMethods();
for(Method m:ms){
Service service= m.getAnnotation(Service.class);
}
但是这样会有一个问题,因为当bean被代理后,像是加了事务,此时获取到的class是代理类,无法获得到源类上的注解属性,所以获得注解的为空
此时需要使用aop工具类进行class文件获取
Class clazz = AopUtils.getTargetClass(value);
Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
这样获取到class对象和method方法对象中都可以拿到源类上的注解属性。
整体代码
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Service;
import org.springframework.util.ReflectionUtils;
import java.lang.reflect.Method;
import java.util.Map;
public class TestListener implements ApplicationContextAware, ApplicationListener<ContextRefreshedEvent> {
private ApplicationContext applicationContext;
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
getAnnotationMap(applicationContext);
}
public void getAnnotationMap(ApplicationContext applicationContext) {
Map<String, Object> beansWithAnnotationMap = this.applicationContext.
getBeansWithAnnotation(Service.class);
beansWithAnnotationMap.values().forEach(value -> {
Class clazz = AopUtils.getTargetClass(value);
Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
for (Method method:methods){
if(method.isAnnotationPresent(Service.class)) {
Service service = method.getAnnotation(Service.class);
// 业务操作
}
}
});
}
}