//@PropertySource:读取属性文件@PropertySource(value={"classpath:conf/properties"})
@Configurationpublic class ConfigOfLifeCycle {
@Bean public Student student(){ return new Student();
}
}
注解的使用一般是与java的反射一起使用,下面是一个例子
注解相当于一种标记,在程序中加了注解就等于为程序打上了某种标记,没加,则等于没有某种标记,以后,javac编译器,开发工具和其他程序可以用反射来了解你的类及各种元素上有无何种标记,看你有什么标记,就去干相应的事。标记可以加在包,类,字段,方法,方法的参数以及局部变量上。
自定义注解及其应用
1)、定义一个最简单的注解
public @interface MyAnnotation {
//
}
2)、把注解加在某个类上:
@MyAnnotation
public class AnnotationTest{
//
}
以下为模拟案例
自定义注解@MyAnnotation
1 package comljqtest;
2
3 import javalangannotationElementType;
4 import javalangannotationRetention;
5 import javalangannotationRetentionPolicy;
6 import javalangannotationTarget;
7
8 /
9 定义一个注解
10
11
12 @author jiqinlin
13
14 /
15 //Java中提供了四种元注解,专门负责注解其他的注解,分别如下
16
17 //@Retention元注解,表示需要在什么级别保存该注释信息(生命周期)。可选的RetentionPoicy参数包括:
18 //RetentionPolicySOURCE: 停留在java源文件,编译器被丢掉
19 //RetentionPolicyCLASS:停留在class文件中,但会被VM丢弃(默认)
20 //RetentionPolicyRUNTIME:内存中的字节码,VM将在运行时也保留注解,因此可以通过反射机制读取注解的信息
21
22 //@Target元注解,默认值为任何元素,表示该注解用于什么地方。可用的ElementType参数包括
23 //ElementTypeCONSTRUCTOR: 构造器声明
24 //ElementTypeFIELD: 成员变量、对象、属性(包括enum实例)
25 //ElementTypeLOCAL_VARIABLE: 局部变量声明
26 //ElementTypeMETHOD: 方法声明
27 //ElementTypePACKAGE: 包声明
28 //ElementTypePARAMETER: 参数声明
29 //ElementTypeTYPE: 类、接口(包括注解类型)或enum声明
30
31 //@Documented将注解包含在JavaDoc中
32
33 //@Inheried允许子类继承父类中的注解
34
35
36 @Retention(RetentionPolicyRUNTIME)
37 @Target({ElementTypeMETHOD, ElementTypeTYPE})
38 public @interface MyAnnotation {
39 //为注解添加属性
40 String color();
41 String value() default "我是林计钦"; //为属性提供默认值
42 int[] array() default {1, 2, 3};
43 Gender gender() default GenderMAN; //添加一个枚举
44 MetaAnnotation metaAnnotation() default @MetaAnnotation(birthday="我的出身日期为1988-2-18");
45 //添加枚举属性
46
47 }
注解测试类AnnotationTest
1 package comljqtest;
2
3 /
4 注解测试类
5
6
7 @author jiqinlin
8
9 /
10 //调用注解并赋值
11 @MyAnnotation(metaAnnotation=@MetaAnnotation(birthday = "我的出身日期为1988-2-18"),color="red", array={23, 26})
12 public class AnnotationTest {
13
14 public static void main(String[] args) {
15 //检查类AnnotationTest是否含有@MyAnnotation注解
16 if(AnnotationTestclassisAnnotationPresent(MyAnnotationclass)){
17 //若存在就获取注解
18 MyAnnotation annotation=(MyAnnotation)AnnotationTestclassgetAnnotation(MyAnnotationclass);
19 Systemoutprintln(annotation);
20 //获取注解属性
21 Systemoutprintln(annotationcolor());
22 Systemoutprintln(annotationvalue());
23 //数组
24 int[] arrs=annotationarray();
25 for(int arr:arrs){
26 Systemoutprintln(arr);
27 }
28 //枚举
29 Gender gender=annotationgender();
30 Systemoutprintln("性别为:"+gender);
31 //获取注解属性
32 MetaAnnotation meta=annotationmetaAnnotation();
33 Systemoutprintln(metabirthday());
34 }
35 }
36 }
枚举类Gender,模拟注解中添加枚举属性
1 package comljqtest;
2 /
3 枚举,模拟注解中添加枚举属性
4
5 @author jiqinlin
6
7 /
8 public enum Gender {
9 MAN{
10 public String getName(){return "男";}
11 },
12 WOMEN{
13 public String getName(){return "女";}
14 }; //记得有“;”
15 public abstract String getName();
16 }
注解类MetaAnnotation,模拟注解中添加注解属性
1 package comljqtest;
2
3 /
4 定义一个注解,模拟注解中添加注解属性
5
6 @author jiqinlin
7
8 /
9 public @interface MetaAnnotation {
10 String birthday();
11 }
当在properties文件中写入 一些值时,我们可以通过在类的属性上使用@Value注解,取到这个值。
如在配置文件中写入
则在类中
这样可以获取到值。但是根据网上的例子,我一直获取不到,首先根据spring的例子,
想要使用@Value,必须把当前类加入spring的容器管理, 如果使用注解,就是在类上加入
@Controller @Service @Component 等容器注解,可是我加入了@Component注解,依然不能获取到值,但是如果是在@Controller 下,则可以。翻阅多篇博客论坛后,终于找到原因。
原来,使用@Value的类,在spring中,不能直接通过new *** 作符来使用,而是应该通过spring的注解 @Autowired 来使用,
如
这样才能成功通过@Value注解取到配置文件中的值。
您好,估计您的意思是想类似Eclipse的做法解释这个Annotation哪些有定义默认值,哪些没有。
这个可以Class clz = Validateclass
Method[] ms = clzgetDeclaredMethods();
然后判断ms[i]getDefaultValue()返回如果不是null就表示有定义默认值了。
//每个注解就是一个类
@注解接口类(接口属性=值)
//创建一个自定义注解
@Retention(RetentionPolicyRUNTIME) //运行时获得
@Target(ElementTypeMETHOD) //针对方法的注解
public @interface 自注标{
int 属性1();
}
//注解加在自己的普通类上
class A{
@自注标(属性1=123)
public void hello(){
}
}
//在自己框架 *** 作下游开发者的代码时,通过反射得到该注解的值123
自注标 a=AgetClass()getMethod("hello")getAnnotation(自注标class);
int i=a属性1();//就能获得用户注解值。进行相应的动作
使用注解
在一般的Java开发中,最常接触到的可能就是@Override和@SupressWarnings这两个注解了。使用@Override的时候只需要一个简单的声明即可。这种称为标记注解(marker annotation ),它的出现就代表了某种配置语义。而其它的注解是可以有自己的配置参数的。配置参数以名值对的方式出现。使用 @SupressWarnings的时候需要类似@SupressWarnings({"uncheck", "unused"})这样的语法。在括号里面的是该注解可供配置的值。由于这个注解只有一个配置参数,该参数的名称默认为value,并且可以省略。而花括号则表示是数组类型。在JPA中的@Table注解使用类似@Table(name = "Customer", schema = "APP")这样的语法。从这里可以看到名值对的用法。在使用注解时候的配置参数的值必须是编译时刻的常量。
从某种角度来说,可以把注解看成是一个XML元素,该元素可以有不同的预定义的属性。而属性的值是可以在声明该元素的时候自行指定的。在代码中使用注解,就相当于把一部分元数据从XML文件移到了代码本身之中,在一个地方管理和维护。
开发注解
在一般的开发中,只需要通过阅读相关的API文档来了解每个注解的配置参数的含义,并在代码中正确使用即可。在有些情况下,可能会需要开发自己的注解。这在库的开发中比较常见。注解的定义有点类似接口。下面的代码给出了一个简单的描述代码分工安排的注解。通过该注解可以在源代码中记录每个类或接口的分工和进度情况。
@Retention(RetentionPolicyRUNTIME)@Target(ElementTypeTYPE)
public @interface Assignment {
String assignee();
int effort();
double finished() default 0;
}
@interface用来声明一个注解,其中的每一个方法实际上是声明了一个配置参数。方法的名称就是参数的名称,返回值类型就是参数的类型。可以通过default来声明参数的默认值。在这里可以看到@Retention和@Target这样的元注解,用来声明注解本身的行为。@Retention用来声明注解的保留策略,有CLASS、RUNTIME和SOURCE这三种,分别表示注解保存在类文件、JVM运行时刻和源代码中。只有当声明为RUNTIME的时候,才能够在运行时刻通过反射API来获取到注解的信息。@Target用来声明注解可以被添加在哪些类型的元素上,如类型、方法和域等。
处理注解
在程序中添加的注解,可以在编译时刻或是运行时刻来进行处理。在编译时刻处理的时候,是分成多趟来进行的。如果在某趟处理中产生了新的Java源文件,那么就需要另外一趟处理来处理新生成的源文件。如此往复,直到没有新文件被生成为止。在完成处理之后,再对Java代码进行编译。JDK 5中提供了apt工具用来对注解进行处理。apt是一个命令行工具,与之配套的还有一套用来描述程序语义结构的Mirror API。Mirror API(comsunmirror)描述的是程序在编译时刻的静态结构。通过Mirror API可以获取到被注解的Java类型元素的信息,从而提供相应的处理逻辑。具体的处理工作交给apt工具来完成。编写注解处理器的核心是AnnotationProcessorFactory和AnnotationProcessor两个接口。后者表示的是注解处理器,而前者则是为某些注解类型创建注解处理器的工厂。
以上面的注解Assignment为例,当每个开发人员都在源代码中更新进度的话,就可以通过一个注解处理器来生成一个项目整体进度的报告。 首先是注解处理器工厂的实现。
public class AssignmentApf implements AnnotationProcessorFactory {public AnnotationProcessor getProcessorFor(Set<AnnotationTypeDeclaration> atds, AnnotationProcessorEnvironment env) {
if (atdsisEmpty()) {
return AnnotationProcessorsNO_OP;
}
return new AssignmentAp(env); //返回注解处理器
}
public Collection<String> supportedAnnotationTypes() {
return CollectionsunmodifiableList(ArraysasList("annotationAssignment"));
}
public Collection<String> supportedOptions() {
return CollectionsemptySet();
}
}
AnnotationProcessorFactory接口有三个方法:getProcessorFor是根据注解的类型来返回特定的注解处理器;supportedAnnotationTypes是返回该工厂生成的注解处理器所能支持的注解类型;supportedOptions用来表示所支持的附加选项。在运行apt命令行工具的时候,可以通过-A来传递额外的参数给注解处理器,如-Averbose=true。当工厂通过 supportedOptions方法声明了所能识别的附加选项之后,注解处理器就可以在运行时刻通过AnnotationProcessorEnvironment的getOptions方法获取到选项的实际值。注解处理器本身的基本实现如下所示。
public class AssignmentAp implements AnnotationProcessor {private AnnotationProcessorEnvironment env;
private AnnotationTypeDeclaration assignmentDeclaration;
public AssignmentAp(AnnotationProcessorEnvironment env) {
thisenv = env;
assignmentDeclaration = (AnnotationTypeDeclaration) envgetTypeDeclaration("annotationAssignment");
}
public void process() {
Collection<Declaration> declarations = envgetDeclarationsAnnotatedWith(assignmentDeclaration);
for (Declaration declaration : declarations) {
processAssignmentAnnotations(declaration);
}
}
private void processAssignmentAnnotations(Declaration declaration) {
Collection<AnnotationMirror> annotations = declarationgetAnnotationMirrors();
for (AnnotationMirror mirror : annotations) {
if (mirrorgetAnnotationType()getDeclaration()equals(assignmentDeclaration)) {
Map<AnnotationTypeElementDeclaration, AnnotationValue> values = mirrorgetElementValues();
String assignee = (String) getAnnotationValue(values, "assignee"); //获取注解的值
}
}
}
}
注解处理器的处理逻辑都在process方法中完成。通过一个声明(Declaration)的getAnnotationMirrors方法就可以获取到该声明上所添加的注解的实际值。得到这些值之后,处理起来就不难了。
在创建好注解处理器之后,就可以通过apt命令行工具来对源代码中的注解进行处理。 命令的运行格式是apt -classpath bin -factory annotationaptAssignmentApf src/annotation/work/java,即通过-factory来指定注解处理器工厂类的名称。实际上,apt工具在完成处理之后,会自动调用javac来编译处理完成后的源代码。
JDK 5中的apt工具的不足之处在于它是Oracle提供的私有实现。在JDK 6中,通过JSR 269把自定义注解处理器这一功能进行了规范化,有了新的javaxannotationprocessing这个新的API。对Mirror API也进行了更新,形成了新的javaxlangmodel包。注解处理器的使用也进行了简化,不需要再单独运行apt这样的命令行工具,Java编译器本身就可以完成对注解的处理。对于同样的功能,如果用JSR 269的做法,只需要一个类就可以了。
@SupportedSourceVersion(SourceVersionRELEASE_6)@SupportedAnnotationTypes("annotationAssignment")
public class AssignmentProcess extends AbstractProcessor {
private TypeElement assignmentElement;
public synchronized void init(ProcessingEnvironment processingEnv) {
superinit(processingEnv);
Elements elementUtils = processingEnvgetElementUtils();
assignmentElement = elementUtilsgetTypeElement("annotationAssignment");
}
public boolean process(Set< extends TypeElement> annotations, RoundEnvironment roundEnv) {
Set< extends Element> elements = roundEnvgetElementsAnnotatedWith(assignmentElement);
for (Element element : elements) {
processAssignment(element);
}
}
private void processAssignment(Element element) {
List< extends AnnotationMirror> annotations = elementgetAnnotationMirrors();
for (AnnotationMirror mirror : annotations) {
if (mirrorgetAnnotationType()asElement()equals(assignmentElement)) {
Map< extends ExecutableElement, extends AnnotationValue> values = mirrorgetElementValues();
String assignee = (String) getAnnotationValue(values, "assignee"); //获取注解的值
}
}
}
}
仔细比较上面两段代码,可以发现它们的基本结构是类似的。不同之处在于JDK 6中通过元注解@SupportedAnnotationTypes来声明所支持的注解类型。另外描述程序静态结构的javaxlangmodel包使用了不同的类型名称。使用的时候也更加简单,只需要通过javac -processor annotationpapAssignmentProcess Demo1java这样的方式即可。
上面介绍的这两种做法都是在编译时刻进行处理的。而有些时候则需要在运行时刻来完成对注解的处理。这个时候就需要用到Java的反射API。反射API提供了在运行时刻读取注解信息的支持。不过前提是注解的保留策略声明的是运行时。Java反射API的AnnotatedElement接口提供了获取类、方法和域上的注解的实用方法。比如获取到一个Class类对象之后,通过getAnnotation方法就可以获取到该类上添加的指定注解类型的注解。
实例分析
下面通过一个具体的实例来分析说明在实践中如何来使用和处理注解。假定有一个公司的雇员信息系统,从访问控制的角度出发,对雇员的工资的更新只能由具有特定角色的用户才能完成。考虑到访问控制需求的普遍性,可以定义一个注解来让开发人员方便的在代码中声明访问控制权限。
@Retention(RetentionPolicyRUNTIME)@Target(ElementTypeMETHOD)
public @interface RequiredRoles {
String[] value();
}
下一步则是如何对注解进行处理,这里使用的Java的反射API并结合动态代理。下面是动态代理中的InvocationHandler接口的实现。
public class AccessInvocationHandler<T> implements InvocationHandler {final T accessObj;
public AccessInvocationHandler(T accessObj) {
thisaccessObj = accessObj;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
RequiredRoles annotation = methodgetAnnotation(RequiredRolesclass); //通过反射API获取注解
if (annotation != null) {
String[] roles = annotationvalue();
String role = AccessControlgetCurrentRole();
if (!ArraysasList(roles)contains(role)) {
throw new AccessControlException("The user is not allowed to invoke this method");
}
}
return methodinvoke(accessObj, args);
}
}
在具体使用的时候,首先要通过ProxynewProxyInstance方法创建一个EmployeeGateway的接口的代理类,使用该代理类来完成实际的 *** 作。
以上就是关于@value注解获取属性文件的值怎么转换成int类型全部的内容,包括:@value注解获取属性文件的值怎么转换成int类型、java注解是怎么实现的、解决Spring 使用 @Value 取不到值等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)