原由:java
在作项目的过程当中,咱们通常都喜欢把经常使用的配置参数写在properties文件而后经过Properties类来加载并读取,为了使用方便通常会定义多个静态变量每一个静态变量对应properties文件的value值。这种方式适用于properties文件比较少的状况下,若是配置文件比较多则该操做会很繁琐并且后续修改维护起来比较麻烦。最近在重构一个N年前的系统,发现里面有10几个这样的配置文件,实在写得烦了所以在想是否是能够作到每新增一个配置文件只须要把对应bean文件写好,程序就能够自动把配置文件的值set到对应的java bean?因而就有了这篇文章。web
思路:spring
1.扫描properties文件jsp
为了实现properties文件能自动注入对应的java bean文件那么第一步固然必需要扫描package目录下的全部.properties文件。实现方法至少有2种,1是经过JDK的getResource("/").getPath()来实现。2.是经过spring 的PathMatchingResourcePatternResolver来实现。在这里推荐用第2种,由于第1种在不一样的jsp容器中有可能获取不到真实的class文件目录(weblogic)。code
具体的实现代码为:对象
//项目根目录 public static String rootPath ; //须要扫描的properties配置文件存放路径 public static String propertiesPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX+"conf/**/*.properties" ; //保存properties对象key=conf/**(路径) public static Map<String,Properties> propMap = new HashMap<String,Properties>() ; /** * 初始化PropMap */ public static void initPropMap(){ ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver(); try { //获取根路径 if(rootPath==null)rootPath= resourcePatternResolver.getResource("/").getURI().getPath() ; //获取全部的properties文件 Resource[] resources = resourcePatternResolver.getResources(propertiesPath) ; for(Resource rs:resources){ Properties prop = new Properties() ; prop.load(new FileInputStream(rs.getFile())) ; //properties文件路径做为key值,Properties对象做为value保存在propMap中 propMap.put(rs.getURL().getPath().replace(rootPath, ""), prop) ; } } catch (IOException e) { e.printStackTrace(); } }
2.自定义properties文件注解blog
配置文件properties路径注解,经过该注解实现properties与java bean之间的绑定。get
@Documented @Target(ElementType.TYPE) @Inherited @Retention(RetentionPolicy.RUNTIME) public @interface PropertiesPath { String filePath() default ""; }
配置文件属性注解,经过该注解实现properties 的key 与java bean属性之间的绑定it
@Documented @Target(ElementType.FIELD) @Inherited @Retention(RetentionPolicy.RUNTIME) public @interface PropertiesAttribute { public String attributeName() default ""; }
3.扫描package目录全部带properties注解的类并经过反射把值set进去io
/** * 扫描class文件并初始化(经过反射) * */ public static void initClass(){ ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver(); try { if(rootPath==null)rootPath= resourcePatternResolver.getResource("/").getURI().getPath() ; Resource[] resources = resourcePatternResolver.getResources(classPath) ; for(Resource rs:resources){ //获取class文件名 String claName = rs.getURI().getPath().replace(rootPath, "").replace(".class", "").replace("/", ".") ; //经过反射获取class引用 Class<?> cla = Class.forName(claName) ; //获取class注解 PropertiesPath propPath = (PropertiesPath) cla.getAnnotation(PropertiesPath.class) ; //注解为空则直接返回 if(propPath==null) continue ; //根据注解来获取properties对象 Properties prop = propMap.get(propPath.filePath()) ; if(prop==null) return ; Field[] fields = cla.getDeclaredFields() ; //扫描当前class对象全部属性 for(Field fd:fields){ Type type = fd.getGenericType() ; System.out.println(fd.getName()+" "+fd.getModifiers()+" "+type.getTypeName()) ; String attr = null ; //判断属性是否有添加注解,有则取注解值 PropertiesAttribute propAttr = fd.getAnnotation(PropertiesAttribute.class) ; if(propAttr!=null) attr=propAttr.attributeName() ; else attr = fd.getName() ; //静态属性能够直接经过set的方法把value注进云 if(type.getTypeName().equals("java.lang.String")){ fd.set(null, prop.getProperty(attr,null)) ; } else if(type.getTypeName().equals("int")){ fd.setInt(null, Integer.parseInt(prop.getProperty(attr,"0"))) ; } else if(type.getTypeName().equals("boolean")){ fd.setBoolean(null, Boolean.valueOf(prop.getProperty(attr,"false"))) ; }else{ System.out.println("非法数据类型!") ; } //if(fd.getModifiers()==9)fd.set(null, prop.get(attr)) ; } } } catch (Exception e) { e.printStackTrace(); } }
最终实现的效果是
也就是说之后若是有新增配置文件则只须要写好对应的转换Bean类便可使用。
如下是完整代码,固然在须要根据本身项目的须要进行修改