功能切换Java注释

use*_*545 6 java spring annotations jpa featuretoggle

如何切换java注释功能?

简单的功能切换: - if(启用切换)执行x

Spring允许使用"profiles"来切换bean.

我使用这些并且它们很好,但我想在字段或类上切换注释..我该怎么做?

用例,我有一个有jpa注释的类.我希望能够在某些环境中通过配置标记某些字段是@transient.

szh*_*hem 3

可能的选择之一是使用aspectj及其声明注释的能力和spring加载时方面编织的能力。

我认为注释不能有条件地声明,但您始终可以将它们编译在一个单独的 jar 中,该 jar 可以根据特定环境放入类路径中,以便加载时编织器能够找到它。


更新

虽然这里有很多有用的答案,但我发现禁用/启用注释在使用spectj时非常有趣,因此示例如下。

最新版本的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());
    }

}
Run Code Online (Sandbox Code Playgroud)

我们将在其中声明注释的类

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

注释本身

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();

}
Run Code Online (Sandbox Code Playgroud)

应用上下文

<?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>
Run Code Online (Sandbox Code Playgroud)

第二个罐子

方面

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");

}
Run Code Online (Sandbox Code Playgroud)

META-INF/aop.xml

<?xml version="1.0"?>

<aspectj>
    <aspects>
        <aspect name="org.foo.bar.ToggleAnnotationAspect"/>
    </aspects>
</aspectj>
Run Code Online (Sandbox Code Playgroud)

在类路径中没有第二个 jar 的情况下运行应用程序

java -javaagent:spring-instrument-3.1.3.RELEASE.jar \
     -classpath app1.jar;<rest_of_cp> org.foo.bar.Main
Run Code Online (Sandbox Code Playgroud)

将打印

MyClass{field1='annotated-field-1', field2='null'}
annotated-method-1
null
Run Code Online (Sandbox Code Playgroud)

使用类路径中的第二个 jar 运行应用程序

java -javaagent:spring-instrument-3.1.3.RELEASE.jar \
     -classpath app1.jar;app1-aspects.jar;<rest_of_cp> org.foo.bar.Main
Run Code Online (Sandbox Code Playgroud)

将打印

MyClass{field1='null', field2='annotated-field-2'}
annotated-method-1
annotated-method-2
Run Code Online (Sandbox Code Playgroud)

因此根本没有对应用程序源进行任何修改。