接上一篇Hibernate 动态HQL(http://www.blogjava.net/ghostzhang/archive/2011/09/08/358320.html ),开发中经常需要修改SQL或者HQL的语句,但是每次都要重启服务器才能使之起作用,就想到在使用Spring配置多语言时有一个ReloadableResourceBundleMessageSource.java类,可以配置动态加载多语言文件,为了配合动态HQL并实现修改HQL语句不用重启服务器,可以参考下这个类的实现。Java代码如下:(ReloadableDynamicHibernate.java)
1 public class ReloadableDynamicHibernate{
2 private final Map<String, XmlHolder> cachedXmls = new HashMap<String, XmlHolder>();
3 private org.springframework.beans.factory.xml.DocumentLoader documentLoader = new org.springframework.beans.factory.xml.DefaultDocumentLoader();
4
5 public void afterPropertiesSet() throws Exception {
6 refreshLoad2Cache(true);
7 };
8
9 protected String getSqlByName(String queryKey) {
10 refreshLoad2Cache(false);
11 Collection<XmlHolder> xmlHolders = cachedXmls.values();
12 for (XmlHolder holder : xmlHolders) {
13 String qlString = holder.getQl(queryKey);
14 if (StringUtils.isNotEmpty(qlString)) {
15 return qlString;
16 }
17 }
18 throw new RuntimeException("can not find ql in xml.");
19 };
20
21 private void refreshLoad2Cache(boolean isForce) {
22 for (int i = 0; i < fileNames.size(); i++) {
23 String fileName = ((String) fileNames.get(i)).trim();
24 if (resourceLoader instanceof ResourcePatternResolver) {
25 try {
26 Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(fileName);
27 for (Resource resource : resources) {
28 getXmls(resource,isForce);
29 }
30 } catch (IOException ex) {
31 throw new RuntimeException("Could not resolve sql definition resource pattern [" + fileName + "]", ex);
32 }
33 } else {
34 Resource resource = resourceLoader.getResource(fileName);
35 getXmls(resource,isForce);
36 }
37 }
38 };
39
40 protected XmlHolder getXmls(Resource resource, boolean isForce) {
41 synchronized (this.cachedXmls) {
42 String filename = resource.getFilename();
43 XmlHolder cachedXmls = this.cachedXmls.get(filename);
44 if (cachedXmls != null && (cachedXmls.getRefreshTimestamp() < 0 || cachedXmls.getRefreshTimestamp() > System.currentTimeMillis())) {
45 return cachedXmls;
46 }
47 return refreshXmls(resource, cachedXmls, isForce);
48 }
49 };
50
51 protected XmlHolder refreshXmls(Resource resource, XmlHolder xmlHolder, boolean isForce) {
52 String filename = resource.getFilename();
53 long refreshTimestamp = System.currentTimeMillis();
54 if (resource.exists()) {
55 long fileTimestamp = -1;
56 try {
57 fileTimestamp = resource.lastModified();
58 if (!isForce && xmlHolder != null && xmlHolder.getFileTimestamp() == fileTimestamp) {
59 if (LOGGER.isDebugEnabled()) {
60 LOGGER.debug("Re-caching properties for filename [" + filename + "] - file hasn't been modified");
61 }
62 xmlHolder.setRefreshTimestamp(refreshTimestamp);
63 return xmlHolder;
64 }
65 } catch (IOException ex) {
66 if (LOGGER.isDebugEnabled()) {
67 LOGGER.debug(resource + " could not be resolved in the file system - assuming that is hasn't changed", ex);
68 }
69 fileTimestamp = -1;
70 }
71 try {
72 Map qlMap = loadQlMap(resource);
73 xmlHolder = new XmlHolder(qlMap, fileTimestamp);
74 } catch (Exception ex) {
75 if (LOGGER.isWarnEnabled()) {
76 LOGGER.warn("Could not parse properties file [" + resource.getFilename() + "]", ex);
77 }
78 xmlHolder = new XmlHolder();
79 }
80 } else {
81 if (LOGGER.isDebugEnabled()) {
82 LOGGER.debug("No properties file found for [" + filename + "] - neither plain properties nor XML");
83 }
84 xmlHolder = new XmlHolder();
85 }
86 xmlHolder.setRefreshTimestamp(refreshTimestamp);
87 this.cachedXmls.put(filename, xmlHolder);
88 return xmlHolder;
89 };
90
91 protected Map<String,String> buildHQLMap(Resource resource) throws Exception {
92 Map<String, String> qlMap = new HashMap<String, String>();
93 try {
94 InputSource inputSource = new InputSource(resource.getInputStream());
95 org.w3c.dom.Document doc = this.documentLoader.loadDocument(inputSource, null, null, org.springframework.util.xml.XmlValidationModeDetector.VALIDATION_NONE, false);
96 Element root = doc.getDocumentElement();
97 List<Element> querys = DomUtils.getChildElements(root);
98 for(Element query:querys){
99 String queryName = query.getAttribute("name");
100 if (StringUtils.isEmpty(queryName)) {
101 throw new Exception("DynamicHibernate Service : name is essential attribute in a <query>.");
102 }
103 if(qlMap.containsKey(queryName)){
104 throw new Exception("DynamicHibernate Service : duplicated query in a <query>.");
105 }
106 qlMap.put(queryName, DomUtils.getTextValue(query));
107 }
108 } catch (Exception ioe) {
109 throw ioe;
110 }
111 return qlMap;
112 };
113
114 protected Map loadQlMap(Resource resource) {
115 Map qlMap = new HashMap<String, String>();
116 InputStream is = null;
117 try {
118 is = resource.getInputStream();
119 return buildHQLMap(resource);
120 } catch (Exception e) {
121 e.printStackTrace();
122 } finally {
123 try {
124 if (null != is) {
125 is.close();
126 }
127 } catch (Exception e) {
128 e.printStackTrace();
129 }
130 }
131 return qlMap;
132 };
133
134 protected class XmlHolder {
135 private Map<String, String> qlMap; //查询的映射
136 private long fileTimestamp = -1;
137 private long refreshTimestamp = -1;
138 public String getQl(String key) {
139 if (null != qlMap) {
140 return qlMap.get(key);
141 } else {
142 if (LOGGER.isErrorEnabled()) {
143 LOGGER.debug("error is occured in getQl.");
144 }
145 return "";
146 }
147 }
148
149 public XmlHolder(Map<String, String> qlMap, long fileTimestamp) {
150 this.qlMap = qlMap;
151 this.fileTimestamp = fileTimestamp;
152 }
153 public XmlHolder() {
154 }
155 public Map<String, String> getQlMap() {
156 return qlMap;
157 }
158 public long getFileTimestamp() {
159 return fileTimestamp;
160 }
161 public void setRefreshTimestamp(long refreshTimestamp) {
162 this.refreshTimestamp = refreshTimestamp;
163 }
164 public long getRefreshTimestamp() {
165 return refreshTimestamp;
166 }
167 }
168 }
<bean id="dynamicHibernate" class="com.company.ReloadableDynamicHibernate">
<property name="sessionFactory" ref="sessionFactory" />
<property name="simpleTemplate" ref="simpleTemplate" />
<property name="fileNames">
<list>
<value>classpath*:hibernate/dynamic/dynamic-hibernate-*.xml</value>
</list>
</property>
</bean>
这样就实现了每次修改SQL or HQL语句后不用重启服务器,立刻看到结果,加快了开发速度。