如何優雅的在weblogic上部署spring-boot

介紹

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"

傳統實現方案

1. 建立一個支持(Support)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>
2. 建立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;
    }
}
3. 建立web.xmlweblogic.xml

IDEA裏建立這兩個文件方法以下:github

  1. File->Project-Structure->Project Settinngs->Facets
  2. 點擊如圖能夠建立web.xml

  1. 點擊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
4. 構建war包

選擇菜單Build->BuildArtifacts->SpringBootWeblogicDemo:war->Build構建完的war包默認在target目錄下spring-boot-weblogic.warapache

5. 部署war包

登陸weblogic控制檯選擇Deployments->Install選擇上面的war包部署.api

6. 測試
curl http://10.1.11.118:7001/spring-boot-weblogic-app/welcome?username=jianfeng.zheng
welcome:jianfeng.zheng

存在的問題

若是你不嫌麻煩,那麼到這裏你已經把你的spring-boot部署到weblogic上,後面的內容能夠不看.上面的方式雖然解決了問題,但也存在不少不足之處

  1. 配置項略多,增長學習成本(實際上很少,但新人動手能力使人髮指)
  2. 由於入口類繼承了SpringBootServletInitializer本地運行缺乏Servlet環境,沒法運行,調試起來麻煩(不知道怎麼解決,若是知道歡迎評論留言)

理想的狀況是,經過SPRING INITIALIZR生成spring-boot項目,開發完後經過某種手段能夠實現快速部署weblogic的目的.接下來就探討解決方案

腳本打包

基本思路是

  1. 本地開發提交工程到svn或者git
  2. 使用maven進行編譯
  3. 將以上配置項和編譯好到class文件一塊兒從新打包

第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

思路就是將如下文件和用戶編譯好的文件一塊兒從新打包,並保持目錄結構

  1. SpringBootWebLogicApplication.class
  2. /WEB/INF/lib/*.jar
  3. web.xml
  4. 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.xmlwls: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上,實現整個過程自動化.

還有哪些須要作的

以上只是解決了部署過程當中最核心的幾個問題,但還有不少問題必定會碰到但未解決的:

  1. 怎麼解決第三發依賴包的問題
  2. 如何作到版本管理,應用回滾
  3. 是否支持全部spring-boot特性
  4. 等等..

生產上的需求遠遠不是本地作個poc驗證經過就能夠解決的,但千里之行始於足下,走出第一步,就已經成功一半.

一些問題記錄

  1. 編譯jdk和weblogic 運行jdk須要1.8或以上版本
  2. 腳本在MacOS 10.12.4上運行經過,若是運行出錯請自行根據操做系統版本作修改,通常是sed命令會跟操做系統版本有關.
  3. 運行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...

相關文章
相關標籤/搜索