功能切换 Java 注释 [英] Feature Toggling Java Annotations

查看:23
本文介绍了功能切换 Java 注释的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何使用切换 Java 注释?

How can I feature toggle java annotations?

简单的功能切换:-if(toggle enabled) do x

Simple feature toggle:- if(toggle enabled) do x

Spring 允许使用配置文件"来切换 bean.

Spring allows the use of "profiles" to toggle beans.

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

I use these and they are fine but I'd like to toggle annotation on field or classes.. how can I do that?

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

Use case, I have a class that has jpa annotations. I want to be able to mark via configuration that some fields are @transient when in certain environments.

推荐答案

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

One of the possible options is to use aspectj with its ability to declare annotations and spring's ability of load-time aspect weaving.

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

I suppose that annotations cannot be declared conditionally, but you can always compile them in a separate jar that can be put into the classpath depending on the certain environment so that load-time weaver will be able to find it.

更新

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

While there are a lot of useful answers here, I found disabling/enabling annotations quite interesting playing with aspectj, so the sample is below.

aspectj 的最新版本支持删除注释,但目前这个功能只适用于字段注释,所以非常有用的方法是根本不声明注释,如果必须启用它们 - 将 jar 放在正如我之前提到的,预编译方面将使注释能够进入类路径.

The latest versions of aspectj support removing of annotations, but for now this feature is only available for the field annotations, so quite useful way is not to declare annotations at all and if they have to be enabled - to put the jar with precompiled aspects which will enable the annotations into the classpath as I mentioned earlier.

样品

第一个罐子

主类

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

}

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

The class we will declare annotations in

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

META-INF/aop.xml

<?xml version="1.0"?>

<aspectj>
    <aspects>
        <aspect name="org.foo.bar.ToggleAnnotationAspect"/>
    </aspects>
</aspectj>

<小时>

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


Running the application without the second jar in the classpath

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

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

Running the application with the second jar in the classpath

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

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

So no modification to the application source were made at all.

这篇关于功能切换 Java 注释的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆