目的是要实现一个可以通过前台网页,来对tomcat中的jndi数据源行进配置的应用。
一下想到了tomcat admin,可惜这东西只在5.5下有支持,6.0后还没支持,说是要下个大版本才会可能有支持。
所以自己下载的5.5下的admin,并且build了起来,看看还挺好用,差不多就是我需要的那些。
在来看看源码,发现使用的struts1写的mvc,页面上好多的struts1标签,然后对tomcat内部的操作,全部使用了MBean的方式。
我只需要对jndi数据源的配置部分,那就着重看这块的代码吧。
关键就是org.apache.webapp.admin.resources包下的SaveDataSourceAction类中的:
objectName = (String) mserver.invoke(oname, "addResource", params, signature);
这句调用了tomcat内部mbean中实现的addResource方法,我需要使用自己的com.elite.aps.dbservice.http.APSDataSourceFactory类作为数据源工厂类,别且对其中自己扩展的属性进行配置,因此在jsp页面与相关的action中添加了对应的代码,SaveDataSourceAction中也同样,在调用完addResource后,对返回的ObjectName调用其设置属性的方法,类似:
if(StringUtil.isNotNull(dataSourceForm.getDbtype()))
mserver.setAttribute(oname, new Attribute("dbtype",dataSourceForm.getDbtype()));
if(StringUtil.isNotNull(dataSourceForm.getInitialSize()))
mserver.setAttribute(oname, new Attribute("initialSize",dataSourceForm.getInitialSize()));
界面上操作完了穿件数据源后,发现并没有保存到对应的server.xml或者context.xml中,发现还有一步commit change的操作,而tomcat6.0中这部操作对应的MBean并没有实现,那就自己实现以下吧。
按照MBean的规则,定义一个StoreServerConfigMBean的接口,其中一个方法void storeConfig(),并且提供对应的实现类:
public class StoreServerConfig implements StoreServerConfigMBean {
private static Log log = LogFactory.getLog(StoreServerConfig.class);
private String serverFilename = "conf/server.xml";
private String contextFilename = "conf/context.xml";
public String getServerFilename() {
return serverFilename;
}
public void setServerFilename(String string) {
serverFilename = string;
}
public String getContextFilename() {
return contextFilename;
}
public void setContextFilename(String contextFilename) {
this.contextFilename = contextFilename;
}
public synchronized void storeConfig() {
try{
storeServerFile();//save to server.xml
storeContextFile();//save to context.xml
}catch(Exception e){
log.error("",e);
}
}
private void storeContextFile(){
StoreFileUtil sfContext = new StoreFileUtil(System.getProperty("catalina.base"), getContextFilename(),"utf-8");
try {
PrintWriter writer = sfContext.getWriter();
SAXReader reader = new SAXReader();
Document doc = reader.read(sfContext.getReader());
Element contextElement=(Element)doc.selectSingleNode("/Context");
List<Element> resourceList=contextElement.selectNodes("ResourceLink[@type='"+ResourceUtils.DATASOURCE_CLASS+"']");
if(resourceList!=null && resourceList.size()>0){
for(Element resource : resourceList){
contextElement.remove(resource);
}
}
MBeanServer mserver = CatalinaUtils.getServer();
DataSourcesForm dsf=ResourceUtils.getDataSourcesForm(mserver, "Global", null, null, "Catalina");
String[] dataSources=dsf.getDataSources();
for(int i=0;i<dataSources.length;i++){
ObjectName oname = new ObjectName(dataSources[i]);
String name=(String)mserver.getAttribute(oname, "name");
Element resourceLinkEle=contextElement.addElement("ResourceLink");
resourceLinkEle.addAttribute("name", name);
resourceLinkEle.addAttribute("type", ResourceUtils.DATASOURCE_CLASS);
resourceLinkEle.addAttribute("global", name);
}
writeOut(writer,doc);
sfContext.move();
} catch (Exception e) {
log.error("",e);
}
}
private void storeServerFile(){
StoreFileUtil sfServer = new StoreFileUtil(System.getProperty("catalina.base"), getServerFilename(),"utf-8");
try {
PrintWriter writer = sfServer.getWriter();
SAXReader reader = new SAXReader();
Document doc = reader.read(sfServer.getReader());
Element gnrElement=(Element)doc.selectSingleNode("/Server/GlobalNamingResources");
List<Element> resourceList=gnrElement.selectNodes("Resource[@type='"+ResourceUtils.DATASOURCE_CLASS+"']");
if(resourceList!=null && resourceList.size()>0){
for(Element resource : resourceList){
gnrElement.remove(resource);
CatalinaUtils.removeResourceLinkFromNamingContextListener(resource.attributeValue("name"));
}
}
MBeanServer mserver = CatalinaUtils.getServer();
DataSourcesForm dsf=ResourceUtils.getDataSourcesForm(mserver, "Global", null, null, "Catalina");
String[] dataSources=dsf.getDataSources();
for(int i=0;i<dataSources.length;i++){
ObjectName oname = new ObjectName(dataSources[i]);
String name=(String)mserver.getAttribute(oname, "name");
String type=(String)mserver.getAttribute(oname, "type");
String factory=(String)mserver.getAttribute(oname, "factory");
String url=(String)mserver.getAttribute(oname, "url");
String driverClassName=(String)mserver.getAttribute(oname, "driverClassName");
String username=(String)mserver.getAttribute(oname, "username");
String password=(String)mserver.getAttribute(oname, "password");
String maxActive=(String)mserver.getAttribute(oname, "maxActive");
String maxIdle=(String)mserver.getAttribute(oname, "maxIdle");
String maxWait=(String)mserver.getAttribute(oname, "maxWait");
Element resourceEle=gnrElement.addElement("Resource");
resourceEle.addAttribute("name", name);
resourceEle.addAttribute("type", type);
resourceEle.addAttribute("factory", factory);
resourceEle.addAttribute("url", url);
resourceEle.addAttribute("driverClassName", driverClassName);
resourceEle.addAttribute("username", username);
resourceEle.addAttribute("password", password);
resourceEle.addAttribute("maxActive", maxActive);
resourceEle.addAttribute("maxIdle", maxIdle);
resourceEle.addAttribute("maxWait", maxWait);
CatalinaUtils.addResourceLinkFromNamingContextListener(resourceEle.attributeValue("name"));
}
writeOut(writer,doc);
sfServer.move();
} catch (Exception e) {
log.error("",e);
}
}
private void writeOut(PrintWriter writer,Document doc) throws Exception{
try {
OutputFormat format = OutputFormat.createPrettyPrint();
format.setEncoding("utf-8");
format.setLineSeparator(System.getProperty("line.separator"));
XMLWriter xmlWriter = new NotepadXMLWriter(writer, format);
xmlWriter.write(doc);
xmlWriter.flush();
} finally {
try {
writer.flush();
} catch (Exception e) {
log.error(e);
}
try {
writer.close();
} catch (Exception e) {
throw (e);
}
}
}
}
这个类中,主要是去做了把当前jmx中的datasource写到响应的配置文件中,server.xml中写入Resource到GlobalNamingResources标签下,context.xml中写入对应的ResourceLink。这样应用就可以直接使用到了,看似不错。
这里需要提到的,写出xml到文本时候,默认格式会不好看,使用OutputFormat format = OutputFormat.createPrettyPrint();后,会好看很多。
但是,不论怎么设置格式,windows上用notepad打开,总会出现黑色方块这样的难看的符号,
原因其实是,虽然标签结束或者有子标签的情况下,使用的format会根据操作系统来替换成对应的换行符号,windows下是\n\r。
但是,在注释里面的换行,dom4j里面是被看做一整段text,不受到format的影响的,因此就扩展了一下XMLWriter,重写了writeComment方法,把难看的\n都替换了,这下好看多了。
@Override
protected void writeComment(String text) throws IOException {
text=text.replaceAll("\\n", System.getProperty("line.separator"));
super.writeComment(text);
}
至此,到我自己的tomcat admin中,去创建删除修改datasource,然后commit change后,能保存到tomcat的配置文件中,如果重启tomcat,就可以看到效果了。
但是,能不能不重启tomcat就有效果呢?
分享到:
相关推荐
Apache Tomcat 6.0.18 是一个广泛使用的开源软件,它是一个符合Java Servlet和JavaServer Pages(JSP)规范的应用服务器,主要用于部署和运行Java Web应用程序。这个版本是解压缩版,意味着用户下载后无需进行编译,...
在现代Web应用开发中,数据库连接管理是一项至关重要的任务。为了提高应用程序的性能和可维护性,通常会采用连接池技术来管理和复用数据库连接。Apache Tomcat作为一款广泛使用的Java应用服务器,提供了丰富的配置...
以上是对“tomcat配置宝典”中提到的关键知识点的详细解析,涵盖了Tomcat的基本配置、集群配置、Nginx和HAProxy的使用、Memcached Session共享以及Tomcat的优化等方面。这些内容对于搭建高效稳定的Web应用环境具有...
spring.datasource.password=admin spring.datasource.driver-class-name=com.mysql.jdbc.Driver ``` Druid是一个功能丰富的JDBC组件,它的特点包括: 1. **监控性能**:Druid内置了StatFilter插件,能够详细...
首先,`SpringBoot`是一个基于Spring框架的高度模块化和简化开发的工具,它内置了Tomcat服务器和一系列默认配置,使得开发者可以快速地创建独立运行的、生产级别的基于Spring的应用。 **双数据源**:在SpringBoot中...
- 数据库设计:包括新闻分类、新闻详情、用户管理等多个表,可能需要涉及的关系有分类与新闻的一对多关系,用户与新闻的多对多关系等。 - RESTful API设计:为前后端分离,需要设计一套清晰、符合REST原则的API...
本文将深入探讨如何将这三个技术整合到一个项目中,以便构建高效、可扩展的微服务架构。 首先,Spring Boot是Spring框架的一个扩展,它提供了快速开发新Spring应用的能力。通过内嵌Tomcat或Jetty服务器,自动配置...
- **Oracle数据库**: 是一款关系型数据库管理系统,广泛应用于企业级应用中。 #### 二、环境准备 根据文档描述,本案例涉及的环境配置包括: - **Solr版本**: 3.6.1 (考虑到项目服务器使用的JDK版本为1.5) - **...
【SpringBoot + Mybatis + MySQL实现文件系统】 在IT领域,构建一个文件系统通常涉及到后端服务、数据库管理和...在实际开发中,还需要考虑性能优化、错误处理、日志记录等多个方面,以确保系统的稳定性和可扩展性。
**Spring Data JPA** 是 Spring 家族中的一个重要成员,用于简化基于 Java Persistence API (JPA) 的数据访问层(DAO)的开发工作。它提供了一种简单的方法来定义和实现 CRUD 操作,而无需编写复杂的 SQL 语句或手动...
在软件开发中,数据库连接池是一种重要的资源管理工具,它能显著提高数据库操作的效率和性能。连接池通过预先创建并维护一定数量的数据库连接,使得应用程序在需要时可以直接获取,而不是每次都进行数据库连接的建立...
2. **Spring Boot Admin**:一个独立的应用,可以用来可视化管理和监控 Spring Boot 应用。 **九、持续集成与部署** 1. **Maven 插件**:Spring Boot 提供了 Maven 插件,可以打包成可执行的 JAR 或 WAR 文件。 2. ...
- 输入数据源在Spring配置文件中的Bean ID,例如`dataSource`。 - 选择刚刚配置好的MySQL驱动,MyEclipse会自动填充其他信息。 - 取消CreateSessionFactory class选项,点击Finish。 #### 四、进一步操作 - **逆向...
Druid作为一款高性能的数据库连接池,被广泛应用于各种项目中,它提供了丰富的监控和扩展能力。本篇将详细介绍如何在Spring Boot中集成和配置Druid。 首先,我们需要在项目的`pom.xml`文件中引入Druid的依赖包。...
MyBatisPlus是对MyBatis的轻量级扩展,提供了诸如插入、更新、删除、查询等基本操作,还支持条件构造、分页、自定义SQL、关联查询等功能,极大地减少了开发者编写SQL的负担。它简化了MyBatis的使用,使得数据库操作...
- **作用**:定义Web应用的名称,通常用于在开发工具或管理控制台中展示。 - **示例**: ```xml <display-name>TomcatExample ``` 2. **`<description>`** - **作用**:提供关于Web应用的描述信息,便于管理...
SSH框架,即Struts2、Spring以及Hibernate三个框架的集成,是Java Web开发中非常流行的一种解决方案。它结合了MVC架构的优势,通过Struts2进行前端控制、Spring管理业务逻辑及事务处理、Hibernate实现持久层数据存取...
`servlet`配置文件是Java Web应用程序中的核心组成部分之一,主要用于配置应用程序的各种属性与行为。本文档旨在深入解析`web.xml`文件中的各个元素及其作用,帮助初学者更好地理解并掌握如何进行有效的配置。 ####...
3. Spring Boot Admin - 第三方扩展,可以可视化地管理和监控 Spring Boot 应用。 以上就是关于启动 Spring Boot 及其相关知识点的详细介绍,包括它的核心特性、项目构建、HTML 整合、数据访问以及测试和监控等方面...