2017-03-07 8 views
0

を実装: -春のブートストラップクラスを注釈と注釈私は、次のような何かをしたい他の場所

@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; 
} 

私はパッケージとカスタムを配布することができるように注釈付きクラスからAnnotationImplementationClassを隔離したいです開発者は@MyCustomAnnotationを使用して独自のスプリングブートアプリケーションクラスに注釈を付けることができます。

私は春のブートクラス(この場合はApplication.java)のクラス名を知らないので、このクラスにアクセスすることはできません。私は何とか実行時にアクセスする必要があるので、リフレクションを使用してカスタム注釈内の値を取得することができます。

BeanPostProcessorの使用を実証しようとした例を調査しましたが、@ MyCustomAnnotationが@SpringBootApplicationを含むJavaクラスに適用されているときにその場所を特定できませんでした。

+0

ClassPathScanningCandidateComponentProviderを使用して、@ MyCustomAnnotationで注釈付けされたクラスを検索し、クラスに存在する他の宣言済み注釈を取得することもできます。 – Barath

+0

バラットありがとう、これはかなり良い提案です、私はそれでいくつかの成功を収めていました。ただし、ClassPathScanningCandidateComponentProviderでは、スキャンを実行するための開始点としてbasePackageが必要です。残念ながら、ブートストラップクラスの名前を知らないという私の指定された制約は、特定のパッケージまたはサブパッケージにあるそのクラスに依存できないことを意味します。すべてのパッケージをスキャンすることは、処理のオーバーヘッドのために実行可能なオプションでもありません。 – Codesnooper

+0

ClassPathScanningCandidateComponentProviderには、注釈付きの型を検索してブートストラップクラスを見つけるためのフィルタを追加できる多くのオプションが用意されています。 – Barath

答えて

0

最終的にこれを解決できました。以下は私のソリューションです: -

@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; 
     } 
    } 
} 

注意すべきポイントのカップル: -

  • カスタム注釈インターフェイス上の@importを使用します。これにより、実装クラスをSpringコンテキストに引きつけることができました。これが@Importを正しく使用しているのかどうかはわかりませんが、それは私の最終的な解決の鍵でした。
  • 実装クラスで "implements ApplicationContextAware"を使用します。これにより、Springの初期化中に私がコントロールするエントリポイントが提供されました。

これは他の人に役立つことを望みます。

0

スプリングブートスタータークラスには、 "public static void main(String [] args)"メソッドが含まれています。リフレクションによってコンテナクラスを参照できます。

これはおそらくあなたを助けるでしょう。どのように目標を達成できるか分かりません。カスタム注釈は最高の優先順位でスキャンする必要があります。

関連する問題