注解一般可以当成配置使用。
之前已经用过配置,比如propeties配置文件。
案例:
设计一个水果类
package com.njwbhz.newssys.annotation;
public class Apple {
private String address;//产地
private String brand;//品牌
private double price;//价格
public Apple() {
}
public Apple(String address, String brand, double price) {
this.address = address;
this.brand = brand;
this.price = price;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
@Override
public String toString() {
return "Apple{" +
"address='" + address + '\'' +
", brand='" + brand + '\'' +
", price=" + price +
'}';
}
}
传统的使用Apple的方式;
package com.njwbhz.newssys.annotation;
public class TestApple {
public static void main(String[] args) {
Apple apple = new Apple();
apple.setAddress("山东烟台");
apple.setBrand("红富士");
apple.setPrice(10);
System.out.println(apple);
/*
数据硬编码在程序中
(直接写到代码中)
问题:如果这些数据需要频繁修改
只能频繁的修改java文件
——>重新编译生成class文件
——>先停服务器
——>在服务器上做替换——>十分麻烦
*/
}
}
把频繁要修改的数据提取到配置文件中,比如db.properties
采用配置文件的方式,让程序更加灵活。
src/apple.properties
address = 山东烟台
brand = 红富士
price = 10
使用配置文件
package com.njwbhz.newssys.annotation;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class AppleFactory {
private static Map<String , String> dataMap = new HashMap<String, String>();
static {
//解析apple.properties文件//
BufferedReader reader = null;
reader = new BufferedReader(new InputStreamReader(AppleFactory.class.getClassLoader().getResourceAsStream("apple.properties")));
try {
String lineData = reader.readLine();
String [] datas = null;
String fileName = null;//属性名,和apple中的属性一致
String fileValue = null;//属性值
while (null != lineData) {
datas = lineData.split("=");
fileName = datas[0].trim();
fileValue = datas[1].trim();
dataMap.put(fileName , fileValue);
lineData = reader.readLine();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (null != reader) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static Apple newInstance () {
Apple apple = new Apple();
//数据来自配置文件,通过反射的方式动态设置
set(apple);
return apple;
}
private static void set (Apple apple) {
Class clazz = apple.getClass();
//通过反射设置值
Set<Map.Entry<String, String>> entries = dataMap.entrySet();
Iterator<Map.Entry<String, String>> it = entries.iterator();
while (it.hasNext()) {
Map.Entry<String , String> entry = it.next();
//entry.key——>属性名 enyrty.getKey()——>value值
try {
Field field = clazz.getDeclaredField(entry.getKey());
String methodName = "set" + entry.getKey().substring(0 , 1).toUpperCase() + entry.getKey().substring(1);
Method method = clazz.getMethod(methodName , field.getType());
if (entry.getKey().equals("price")) {
method.invoke(apple , Double.valueOf(entry.getValue()));
} else {
method.invoke(apple , entry.getValue());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
测试
package com.njwbhz.newssys.annotation;
public class TestApple {
public static void main(String[] args) {
Apple apple = AppleFactory.newInstance();
System.out.println(apple);
}
}
出现乱码的解决方案:
重新编写配置文件的value
配置的关键点:解析配置文件、使用配置文件中数据做相关处理(技巧:反射)。
使用注解做配置,注解的保留策略:RUNTIME,程序运行时候获取注解,最后利用注解做处理。
设计注解:
package com.njwbhz.newssys.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Address {
String value() default "";
}
package com.njwbhz.newssys.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Brand {
String value() default "";
}
package com.njwbhz.newssys.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Price {
double value() default 0.0;
}
使用注解
package com.njwbhz.newssys.annotation;
public class Apple {
@Address("阿克苏")
private String address;//产地
@Brand("红富士")
private String brand;//品牌
@Price(20)
private double price;//价格
public Apple() {
}
public Apple(String address, String brand, double price) {
this.address = address;
this.brand = brand;
this.price = price;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
@Override
public String toString() {
return "Apple{" +
"address='" + address + '\'' +
", brand='" + brand + '\'' +
", price=" + price +
'}';
}
}
解析注解,使用反射技术。
package com.njwbhz.newssys.annotation;
import java.lang.reflect.Field;
public class AppleFactoryByAnnotation {
public static Apple newInstance () {
Apple apple = new Apple();
//apple中的值,使用注解中的配置信息
Class clazz = apple.getClass();
//注解是作用在属性上,反射将属性封装成了Field对象
//反射——>获取所有的属性Field——>Field获取相关的注解
Field [] fields = clazz.getDeclaredFields();
for (Field field : fields) {
//field可能是address,也可能是brand,也可能是price
String fieldName = field.getName();
if (fieldName.equals("address")) {
//获取@Address
Address addressAnnotation = field.getAnnotation(Address.class);
//获取对应的成员的信息
String value = addressAnnotation.value();
apple.setAddress(value);
} else if (fieldName.equals("brand")) {
//获取@Brand
Brand brandAnnotation = field.getAnnotation(Brand.class);
//获取对应的成员的信息
String value = brandAnnotation.value();
apple.setBrand(value);
} else if (fieldName.equals("price")) {
//获取@Price
Price priceAnnotation = field.getAnnotation(Price.class);
//获取对应的成员的信息
double value = priceAnnotation.value();
apple.setPrice(value);
}
}
return apple;
}
}
测试:
package com.njwbhz.newssys.annotation;
public class TestApple {
public static void main(String[] args) {
// Apple apple = AppleFactory.newInstance();
// System.out.println(apple);
Apple apple = AppleFactoryByAnnotation.newInstance();
System.out.println(apple);
}
}
结论:注解可以做程序的配置。
对比:
结论:注解做程序的配置是现代软件开发的主流。
真正的配置采用配置文件 + 注解 协同工作。