spring-boot
應該是目前最火的java後臺開發框架,如今java的簡歷裏若是不貼個spring boo的標籤都很差意思說本身是作java的,事實上現狀就是如此,和當年ssh
盛行時如出一轍.不過說歸說,spring-boot
確實好用,學習成本低
,入門快
,開發效率高
,自啓動
,天生適合容器化
.但要把spring-boot
部署到weblogic
上,尤爲是低版本的weblogic上,仍是要費點功夫.若是要求高一點,優雅的部署,則要費點腦筋,這裏說的優雅的部署,是指開發人員不須要由於服務器的限制對程序作特殊的配置,增長其學習成本和工做量.本文則探討幾種我認爲優雅的方式,如看官有更好的方案,歡迎留言一塊兒討論.html
ide | IntelliJ IDEA 2017.2 |
weblogic | 10.3.6.0 |
weblogic-jdk | java version "1.8.0_171" |
maven
的工程pom.xmljava
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.boostrdev.legacy.weblogic</groupId> <artifactId>spring-boot-legacy-weblogic</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <name>Spring Boot Legacy WebLogic</name> <description>Demo project for deploying a Spring Boot to a legacy (10.3.5) weblogic environment using servlet 2.5</description> <properties> <!-- Overrides the spring.version in the parent pom --> <spring.version>4.2.5.RELEASE</spring.version> <spring.boot.version>1.1.12.RELEASE</spring.boot.version> </properties> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <!-- Using version 1.1.12 for Java SE 6 compatibility --> <version>1.1.12.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-legacy</artifactId> <version>1.0.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${spring.version}</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <configuration> <attachClasses>true</attachClasses> <archive> <manifestEntries> <Weblogic-Application-Version>${project.version}</Weblogic-Application-Version> </manifestEntries> <manifest> <addClasspath>true</addClasspath> <addClasspath>lib/</addClasspath> </manifest> </archive> <webResources> <resource> <directory>${project.basedir}/src/main/resources/static</directory> </resource> <resource> <directory>${project.basedir}/src/main/webapp</directory> </resource> </webResources> <warName>${project.artifactId}</warName> </configuration> </plugin> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <version>${spring.boot.version}</version> <configuration> <classifier>BOOT</classifier> </configuration> <executions> <execution> <goals> <goal>repackage</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </project>
spring boot
入口類和測試接口SpringBootWebLogicApplication.javapython
package com.yaya; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.boot.context.web.SpringBootServletInitializer; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.web.WebApplicationInitializer; @EnableAutoConfiguration @Configuration @ComponentScan public class SpringBootWebLogicApplication extends SpringBootServletInitializer implements WebApplicationInitializer { public static void main(String[] args) { SpringApplication.run(SpringBootWebLogicApplication.class, args); } @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) { return builder.sources(SpringBootWebLogicApplication.class).showBanner(false); } }
TestService.javagit
package com.yaya; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; /** * @Description: * @author: jianfeng.zheng * @since: 2018/7/20 上午9:58 * @history: 1.2018/7/20 created by jianfeng.zheng */ @RestController public class TestService { @RequestMapping("/welcome") public String welcome(@RequestParam(name = "username") String username) { return "welcome:" + username; } }
web.xml
和 weblogic.xml
在IDEA
裏建立這兩個文件方法以下:github
web.xml
Add Application Server specific...
選擇weblogic
並指定版本建立weblogic.xml
.(IDEA這個功能簡直太貼心)web.xmlweb
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <context-param> <param-name>contextConfigLocation</param-name> <param-value>com.yaya.SpringBootWebLogicApplication</param-value> </context-param> <listener> <listener-class>org.springframework.boot.legacy.context.web.SpringBootContextLoaderListener</listener-class> </listener> <filter> <filter-name>metricFilter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter-mapping> <filter-name>metricFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <servlet> <servlet-name>appServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextAttribute</param-name> <param-value>org.springframework.web.context.WebApplicationContext.ROOT</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>appServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
weblogic.xmlspring
<?xml version="1.0" encoding="UTF-8"?> <wls:weblogic-web-app xmlns:wls="http://xmlns.oracle.com/weblogic/weblogic-web-app" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://xmlns.oracle.com/weblogic/weblogic-web-app http://xmlns.oracle.com/weblogic/weblogic-web-app/1.4/weblogic-web-app.xsd"> <wls:context-root>/spring-boot-weblogic-app</wls:context-root> <wls:container-descriptor> <wls:prefer-application-packages> <wls:package-name>org.slf4j.*</wls:package-name> <wls:package-name>org.springframework.*</wls:package-name> </wls:prefer-application-packages> </wls:container-descriptor> </wls:weblogic-web-app>
此時目錄結構shell
. ├── SpringBootWeblogicDemo.iml ├── WEB-INF │ ├── web.xml │ └── weblogic.xml ├── pom.xml └── src ├── main │ ├── java │ │ └── com │ │ └── yaya │ │ ├── SpringBootWebLogicApplication.java │ │ └── TestService.java │ ├── resources │ │ └── static │ └── webapp └── test └── java
選擇菜單Build->BuildArtifacts->SpringBootWeblogicDemo:war->Build
構建完的war包默認在target目錄下spring-boot-weblogic.war
apache
登陸weblogic
控制檯選擇Deployments->Install
選擇上面的war包部署.api
curl http://10.1.11.118:7001/spring-boot-weblogic-app/welcome?username=jianfeng.zheng welcome:jianfeng.zheng
若是你不嫌麻煩,那麼到這裏你已經把你的spring-boot部署到weblogic上,後面的內容能夠不看.上面的方式雖然解決了問題,但也存在不少不足之處
SpringBootServletInitializer
本地運行缺乏Servlet環境,沒法運行,調試起來麻煩(不知道怎麼解決,若是知道歡迎評論留言)理想的狀況是,經過SPRING INITIALIZR生成spring-boot
項目,開發完後經過某種手段
能夠實現快速部署weblogic的目的.接下來就探討解決方案
基本思路是
maven
進行編譯第3步詳細講下
能夠將spring-boot-weblogic.war
解壓開看下目錄結構
. ├── ./META-INF │ └── ./META-INF/MANIFEST.MF └── ./WEB-INF ├── ./WEB-INF/classes │ └── ./WEB-INF/classes/com │ └── ./WEB-INF/classes/com/yaya │ ├── ./WEB-INF/classes/com/yaya/SpringBootWebLogicApplication.class │ └── ./WEB-INF/classes/com/yaya/TestService.class ├── ./WEB-INF/lib │ ├── ./WEB-INF/lib/spring-aop-4.2.5.RELEASE.jar │ ├── ./WEB-INF/lib/spring-beans-4.2.5.RELEASE.jar ..... ├── ./WEB-INF/web.xml └── ./WEB-INF/weblogic.xml
思路就是將如下文件和用戶編譯好的文件一塊兒從新打包,並保持目錄結構
能夠將這些文件從war包裏解壓出來放到指定目錄下,這裏稱這個目錄爲pre-compiled-path
shell
腳本以下:
spring-boot-war.sh
#!/bin/bash #用戶工程目錄 v_s=$1 #腳本運行臨時目錄 v_d=$1/temp #存放web.xml等文件目錄 v_m=$2 rm -rf $v_d mkdir -p $v_d cp $v_s/pom.xml $v_d cp -r $v_s/src $v_d cd $v_d #編譯代碼(跳過單元測試) mvn compile -Dmaven.test.skip=true mkdir -p $v_d/war v_war=$v_d/war cd $v_war mkdir -p $v_war/WEB-INF #拷貝編譯好的class文件 cp -r $v_d/target/classes $v_war/WEB-INF/ #spring-boot入口類路徑(能夠寫死) v_app=$v_war/WEB-INF/classes/com/yaya/ mkdir -p $v_app #拷貝入口類 cp $v_m/SpringBootWebLogicApplication.class $v_app #拷貝web.xml和weblogic.xml cp $v_m/web.xml $v_war/WEB-INF/ cp $v_m/weblogic.xml $v_war/WEB-INF/ #拷貝spring-boot依賴jar包 cp -r $v_m/lib $v_war/WEB-INF/lib cd $v_war #從新開始打包 jar -cvfM spring-boot-weblogic.war .
運行腳本,完成編譯打包
./spring-boot.sh /you/spring-boot/source/path /you/pre-compiled/path
腳本運行成功後,在工程目錄下,會建立一個temp
目錄,目標war
包就在該目錄下.
雖然完成了打包,而且也能成功部署到weblogic上運行但這個腳本目前context-root
和war包名稱都是寫死的,咱們須要一個能動態命名的腳本.解決的方案是,用sed
命令對文本進行替換,名稱由腳本參數指定.
修改weblogic.xml
將wls:context-root
用參數代替
<?xml version="1.0" encoding="UTF-8"?> <wls:weblogic-web-app xmlns:wls="http://xmlns.oracle.com/weblogic/weblogic-web-app" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://xmlns.oracle.com/weblogic/weblogic-web-app http://xmlns.oracle.com/weblogic/weblogic-web-app/1.4/weblogic-web-app.xsd"> <wls:context-root>/{app-name}</wls:context-root> <wls:container-descriptor> <wls:prefer-application-packages> <wls:package-name>org.slf4j.*</wls:package-name> <wls:package-name>org.springframework.*</wls:package-name> </wls:prefer-application-packages> </wls:container-descriptor> </wls:weblogic-web-app>
修改腳本spring-boot-war.sh
#!/bin/bash #用戶工程目錄 v_s=$1 #腳本運行臨時目錄 v_d=$1/temp #存放web.xml等文件目錄 v_m=$2 v_a=$3 rm -rf $v_d mkdir -p $v_d cp $v_s/pom.xml $v_d cp -r $v_s/src $v_d cd $v_d #編譯代碼(跳過單元測試) mvn compile -Dmaven.test.skip=true mkdir -p $v_d/war v_war=$v_d/war cd $v_war mkdir -p $v_war/WEB-INF #拷貝編譯好的class文件 cp -r $v_d/target/classes $v_war/WEB-INF/ #spring-boot入口類路徑(能夠寫死) v_app=$v_war/WEB-INF/classes/com/yaya/ mkdir -p $v_app #拷貝入口類 cp $v_m/SpringBootWebLogicApplication.class $v_app #拷貝web.xml和weblogic.xml cp $v_m/web.xml $v_war/WEB-INF/ cp $v_m/weblogic.xml $v_war/WEB-INF/ #替換app-name sed -i '' "s/{app-name}/${v_a}/g" $v_war/WEB-INF/weblogic.xml #拷貝spring-boot依賴jar包 cp -r $v_m/lib $v_war/WEB-INF/lib cd $v_war #從新開始打包(文件名用變量替換) jar -cvfM $v_a.war .
運行腳本
./spring-boot.sh /you/spring-boot/source/path /you/pre-compiled/path app-name
腳本會根據指定的app-name
生成名稱不一樣,context-root不一樣的war包.
能夠藉助wlst.sh
工具,將war
包自動部署到weblogic上.由於要使用wlst.sh
工具,因此服務器須要預先安裝好weblogic
.腳本使用jython語言編寫.
deployApp.py
print '\n Begin deploy application' try: mUsername=sys.argv[1] mPassword=sys.argv[2]; mConsoleURL=sys.argv[3]; mAppName=sys.argv[4]; mAppPath=sys.argv[5]; mTarget=sys.argv[6]; print('\n mServerName:') print(mTarget) print('\n appName:') print(mAppName) print('\n appPath:') print(mAppPath) connect(mUsername,mPassword,mConsoleURL) progress=deploy(mAppName,mAppPath,targets=mTarget,upload='true',timeout=10000000) dumpStack() progress.printStatus() except Exception, ex: print ex.getMessage() print '#########################################################' print '##### Deploy Failed #########' print '##### Contact support with Exception Stack #########' print '#########################################################' exit()
mUsername:console用戶名
mPassword:console密碼
mConsoleURL:console路徑(帶端口)
mAppName:app name
mAppPath:war包路徑
mTarget:目標服務器,能夠是server和集羣名稱
修改腳本spring-boot-war.sh
#!/bin/bash #用戶工程目錄 v_s=$1 #腳本運行臨時目錄 v_d=$1/temp #存放web.xml等文件目錄 v_m=$2 #app-name v_a=$3 #WLS_HOME weblogic安裝目錄 v_wls=$4 rm -rf $v_d mkdir -p $v_d cp $v_s/pom.xml $v_d cp -r $v_s/src $v_d cd $v_d #編譯代碼(跳過單元測試) mvn compile -Dmaven.test.skip=true mkdir -p $v_d/war v_war=$v_d/war cd $v_war mkdir -p $v_war/WEB-INF #拷貝編譯好的class文件 cp -r $v_d/target/classes $v_war/WEB-INF/ #spring-boot入口類路徑(能夠寫死) v_app=$v_war/WEB-INF/classes/com/yaya/ mkdir -p $v_app #拷貝入口類 cp $v_m/SpringBootWebLogicApplication.class $v_app #拷貝web.xml和weblogic.xml cp $v_m/web.xml $v_war/WEB-INF/ cp $v_m/weblogic.xml $v_war/WEB-INF/ #替換app-name sed -i '' "s/{app-name}/${v_a}/g" $v_war/WEB-INF/weblogic.xml #拷貝spring-boot依賴jar包 cp -r $v_m/lib $v_war/WEB-INF/lib cd $v_war #從新開始打包(文件名用變量替換) jar -cvfM $v_a.war . #開始部署 $v_wls/common/bin/wlst.sh /script/path/deployApp.py weblogic admin-password admin-host:7001 $v_a $v_war/$v_a.war app_server
這樣就能夠將war包自動部署到weblogic上,實現整個過程自動化.
以上只是解決了部署過程當中最核心的幾個問題,但還有不少問題必定會碰到但未解決的:
生產上的需求遠遠不是本地作個poc驗證經過就能夠解決的,但千里之行始於足下,走出第一步,就已經成功一半.
MacOS 10.12.4
上運行經過,若是運行出錯請自行根據操做系統版本作修改,通常是sed
命令會跟操做系統版本有關.spring-boot
的weblogic server不要部署任何oracle 中間件產品,可能會有jar包衝突org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private org.springframework.boot.autoconfigure.web.ServerProperties org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration.properties; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'serverProperties' defined in class path resource [org/springframework/boot/autoconfigure/web/ServerPropertiesAutoConfiguration.class]: Initialization of bean failed; nested exception is java.lang.AbstractMethodError: org.apache.openjpa.persistence.PersistenceProviderImpl.getProviderUtil()Ljavax/persistence/spi/ProviderUtil;
https://github.com/bamiidowu/...
https://docs.oracle.com/cd/E1...