java - 发现带注释的方法

标签 java spring proxy annotations

在我的 Spring 应用程序中,我有使用 Spring 缓存机制的组件。每个 @Cacheable 注释指定要使用的缓存。我想自动发现启动时需要的所有缓存,以便可以自动配置它们。

最简单的方法似乎是创建一个标记接口(interface)(例如:CacheUser)以供每个缓存组件使用:

@Component
public class ComponentA implements CacheUser {
  @Cacheable("dictionaryCache")
  public String getDefinition(String word) {
    ...
  }
}

然后我会让 Spring 自动发现此接口(interface)的所有实现,并将它们自动连接到一个配置列表,该配置列表可在配置缓存管理器时使用。这行得通。

@Autowired
private Optional<List<CacheUser>> cacheUsers;

我的计划是获取每个发现的类并找到所有用 @Cacheable 注释的方法。从那里我可以访问注释的属性并获取缓存名称。我正在使用 AnnotationUtils.findAnnotation() 获取注释声明。

这就是计划失败的地方。 Spring 实际上连接代理而不是原始组件,并且注释不会复制到代理的方法中。我发现的唯一解决方法是利用代理实现 Advised 提供对代理类的访问的事实:

((Advised)proxy).getTargetSource().getTargetClass().getMethods()

从那里我可以获得原始注释,但这种方法显然很脆弱。

所以有两个问题,真的:

  1. 是否有更好的方法来获取代理类定义的注释?
  2. 你能建议任何其他方法来发现我的项目中 @Cacheable 的所有用途吗?我喜欢没有标记界面。

谢谢!

最佳答案

Spring 有很多基础设施接口(interface),可以帮助您进入容器和/或 bean 的生命周期。为了您的目的,您想要使用 BeanPostProcessorSmartInitializingSingleton .

BeanPostProcessor 将为所有构造的 beans 获得回调,您只需要实现 postProcessAfterInitialization 方法。您可以在该方法中检测注释并填充缓存列表。

然后在 SmartInitializingSingletonafterSingletonsInstantiated 方法中,您使用此列表来引导/初始化您的缓存。

类似下面的内容(未经测试但应该给你一个想法)。

public class CacheInitialingProcessor implements BeanPostProcessor, SmartInitializingSingleton {

    private final Set<String> caches = new HashSet<String>();

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        Class<?> targetClass = AopUtils.getTargetClass(bean);
        ReflectionUtils.doWithMethods(targetClass, new ReflectionUtils.MethodCallback() {
            @Override
            public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
                Cacheable cacheable = AnnotationUtils.getAnnotation(method, Cacheable.class);
                if (cacheable != null) {
                    caches.addAll(Arrays.asList(cacheable.cacheNames()));
                }
            }
        });
        return bean;
    }

    @Override
    public void afterSingletonsInstantiated() {
        for (String cache : caches) {
            // inti caches.
        }
    }
}

关于java - 发现带注释的方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33357530/

相关文章:

使用自定义 ProxySelector 时,Java 通过代理解析 dns

安卓工作室 3.1 : Proxy configuration: Unable to set https user password for git operations

java - MyBatis 将结果映射到 MyBatisRepository 中的 List<String>

java - 有没有办法将非 bean 样式对象用作 spring 表单的模型属性?

java - Spring security oauth2 - 在 oauth/token 调用后添加过滤器

java - 在 Spring 3 中禁用架构验证

node.js - 即使设置了代理,npm 也不会安装包

java - 负载测试 Java/Mysql 应用程序,从哪里开始?

java - 了解引用处理程序线程

java - 如何解决Android更新不同数据库的问题