可能なオプションの 1 つは、注釈を宣言する機能と、読み込み時のアスペクト ウィービングのスプリングの機能を備えた、aspectjを使用することです。
注釈は条件付きで宣言できないと思いますが、特定の環境に応じてクラスパスに入れることができる別の jar にいつでもコンパイルして、ロード時のウィーバーがそれを見つけることができるようにすることができます。
アップデート
ここには多くの有用な回答がありますが、アノテーションの無効化/有効化は、aspectj で遊んで非常に興味深いことがわかったので、サンプルを以下に示します。
Aspectj の最新バージョンはアノテーションの削除をサポートしていますが、今のところこの機能はフィールド アノテーションでのみ利用可能です。したがって、非常に便利な方法は、アノテーションをまったく宣言せず、アノテーションを有効にする必要がある場合に、jar をプリコンパイル済みのアスペクトに配置することです。前述のように、クラスパスへの注釈を有効にします。
サンプル
最初の壷
メインクラス
package org.foo.bar;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("/applicationContext.xml");
MyClass myObj = context.getBean("myObj", MyClass.class);
System.out.println(myObj);
System.out.println(myObj.getValue1());
System.out.println(myObj.getValue2());
}
}
アノテーションを宣言するクラス
package org.foo.bar;
public class MyClass {
@MyAnn("annotated-field-1")
private String field1;
private String field2;
@MyAnn("annotated-method-1")
public String getValue1() {
String value = null;
try {
MyAnn ann = getClass().getDeclaredMethod("getValue1").getAnnotation(MyAnn.class);
if(ann != null) {
value = ann.value();
}
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
return value;
}
public String getValue2() {
String value = null;
try {
MyAnn ann = getClass().getDeclaredMethod("getValue2").getAnnotation(MyAnn.class);
if(ann != null) {
value = ann.value();
}
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
return value;
}
@Override
public String toString() {
String field1 = null;
try {
MyAnn ann = getClass().getDeclaredField("field1").getAnnotation(MyAnn.class);
if(ann != null) {
field1 = ann.value();
}
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
}
String field2 = null;
try {
MyAnn ann = getClass().getDeclaredField("field2").getAnnotation(MyAnn.class);
if(ann != null) {
field2 = ann.value();
}
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
}
StringBuilder sb = new StringBuilder();
sb.append("MyClass");
sb.append("{field1='").append(field1).append('\'');
sb.append(", field2='").append(field2).append('\'');
sb.append('}');
return sb.toString();
}
}
注釈自体
package org.foo.bar;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@Target({ElementType.FIELD, ElementType.METHOD})
public @interface MyAnn {
String value();
}
アプリケーションのコンテキスト
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">
<context:load-time-weaver />
<bean id="myObj" class="org.foo.bar.MyClass" />
</beans>
二番目の壷
側面
package org.foo.bar;
public aspect ToggleAnnotationAspect {
declare @field : private String org.foo.bar.MyClass.field1 : -@MyAnn;
declare @field : private String org.foo.bar.MyClass.field2 : @MyAnn("annotated-field-2");
declare @method : public String org.foo.bar.MyClass.getValue2() : @MyAnn("annotated-method-2");
}
META-INF/aop.xml
<?xml version="1.0"?>
<aspectj>
<aspects>
<aspect name="org.foo.bar.ToggleAnnotationAspect"/>
</aspects>
</aspectj>
クラスパスに 2 番目の jar を指定せずにアプリケーションを実行する
java -javaagent:spring-instrument-3.1.3.RELEASE.jar \
-classpath app1.jar;<rest_of_cp> org.foo.bar.Main
印刷します
MyClass{field1='annotated-field-1', field2='null'}
annotated-method-1
null
クラスパスの 2 番目の jar を使用してアプリケーションを実行する
java -javaagent:spring-instrument-3.1.3.RELEASE.jar \
-classpath app1.jar;app1-aspects.jar;<rest_of_cp> org.foo.bar.Main
印刷します
MyClass{field1='null', field2='annotated-field-2'}
annotated-method-1
annotated-method-2
したがって、アプリケーション ソースへの変更はまったく行われませんでした。