简体   繁体   English

注释一个Spring Boot引导类并在其他地方实现注释

[英]Annotate a Spring Boot bootstrap class and implement the annotation elsewhere

I want to do something like the following:- 我想做以下事情:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyCustomAnnotation {
    public String field1();
    public String[] list1();
}

@SpringBootApplication
@MyCustomAnnotation(field1 = "value1", list1 = { "list value 1", "list value2" })
public class Application {
    public static void main(String[] args){
        SpringApplication.run(Application.class, args);
    }
}

public class AnnotationImplementationClass {
    // Inject field1 and list1 values from @MyCustomAnnotation into this class
    private String field1;
    private String[] list1;
}

I want to isolate the AnnotationImplementationClass from the annotated class so that I can package and distribute the custom annotation and its implementation, thus allowing developers to annotate their own spring boot application class with @MyCustomAnnotation. 我想将AnnotationImplementationClass与带注释的类隔离开,以便我可以打包和分发自定义注释及其实现,从而允许开发人员使用@MyCustomAnnotation对自己的Spring Boot应用程序类进行注释。

The constraints are that I will not know the class name for the spring boot class (in this case Application.java) and obviously I will not have access to this class to alter it. 约束是我将不知道Spring Boot类的类名(在本例中为Application.java),并且显然我将无法访问该类以对其进行更改。 I must somehow gain access at runtime so that I can use reflection to obtain the values within the custom annotation. 我必须以某种方式在运行时获得访问权限,以便可以使用反射来获取自定义批注中的值。

I have researched examples that attempt to demonstrate the use of BeanPostProcessor but I have been unable to locate the @MyCustomAnnotation when it is applied to the java class containing @SpringBootApplication. 我研究了一些示例,试图演示BeanPostProcessor的用法,但是当将@MyCustomAnnotation应用于包含@SpringBootApplication的java类时,我无法找到它。

Spring Boot Starter Classes contain "public static void main(String[] args)" method. Spring Boot Starter类包含“公共静态void main(String [] args)”方法。 you can refer the container class by reflection. 您可以通过反射引用容器类。

It would maybe help you.I don't know how can your goal be done. 可能会对您有所帮助。我不知道您如何实现目标。 but your custom annotation should be scanned with highest priority. 但是您的自定义注释应优先扫描。

I was finally able to resolve this myself. 我终于能够自己解决这个问题。 The following is my solution:- 以下是我的解决方案:-

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import(AnnotationImplementationClass.class)
public @interface MyCustomAnnotation {
    public String field1();
    public String[] list1();
}


@SpringBootApplication
@MyCustomAnnotation(field1 = "field1 value", list1 = { "list1 value 1", "list1 value 2" })
public class Application
{
    public static void main(String[] args)
    {
        SpringApplication.run(Application.class, args);
    }
}

public class AnnotationImplementationClass implements ApplicationContextAware
{
    private String field1;
    private String[] list1;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
    {
        // Grab the beans from the app context that are annotated with my custom annotation
        Map<String, Object> beanMap = applicationContext.getBeansWithAnnotation(MyCustomAnnotation.class);
        Collection<Object> beans = beanMap.values();

        // There is a possibility that multiple beans are annotated with the annotation. I only annotated one bean
        // but I am using a "for" loop for illustration.
        for (Object bean : beans)
        {
            // Spring annotated classes are often proxied when Spring is initializing. I found that I was unable to get
            // the annotation and its parameter values from the proxy instance. I need to find the actual class that was
            // annotated using the the proxy as a start point. The following "if" clause illustrates the process.
            Class<? extends Object> annotatedClass = null;
            if (bean instanceof TargetClassAware)
            {
                annotatedClass = ((TargetClassAware) bean).getTargetClass();
            }
            else if (ClassUtils.isCglibProxy(bean))
            {
                annotatedClass = bean.getClass().getSuperclass();
            }
            else
            {
                annotatedClass = bean.getClass();
            }

            // Now I can get the annotation and its parameter values
            MyCustomAnnotation annotation = annotatedClass.getAnnotation(MyCustomAnnotation.class);
            field1 = annotation.field1();
            list1 = annotation.list1();

            // Since I only want one of the classes annotated by my custom annotation I break out of the loop
            break;
        }
    }
}

A couple of points to note:- 需要注意的几点:

  • The use of @Import on the custom annotation interface. 在自定义注释界面上使用@Import。 This allowed me to hook the implementation class into the Spring context. 这使我可以将实现类挂接到Spring上下文中。 Not sure if this is a correct use of @Import but it was key to my eventual solution. 不知道这是否是@Import的正确用法,但这是我最终解决方案的关键。
  • The use of "implements ApplicationContextAware" on the implementation class. 在实现类上使用“实现ApplicationContextAware”。 This provided an entry point for me to take control during Spring initialization. 这为我提供了在Spring初始化期间进行控制的入口点。

Hope this helps someone else. 希望这对其他人有帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM