通向架構師的道路(第十八天)萬能框架 Spring ( 一 )(上)
(點擊
上方公眾號
,可快速關注)
來源:袁鳴凱,
blog.csdn.net/lifetragedy/article/details/8096762
一、前言
前一陣列剛換了個新的工作環境,然後自己的baby也剛出生,一直沒有時間去做工作以後的其它事了,擔擱了一段日子。
今天兒子滿一周了,我內人她家幫著照顧著,總算我可以喘口氣休息一下,因此決定將這個系列的博文繼續下去,同時也將此篇獻給我剛出生一周的兒子和幸苦了10個月的愛人。
二、基本概念
Spring,作為一個流行框架它給我們在日常工程中的框架搭建提供了太多的便利了,它就像一個骨架一樣,你可以在上面自己去塑出肌膚與血肉並賦於它靈魂。
從今天開始我們將要連續幾天基於Spring的基礎上來講軟體開發框架,由於Spring被應用的太廣泛太廣泛了,因此此系列教程可以作為Spring開發的一套基礎教程也可以稱其為「典範或者公式化教程」吧.
此套教程會覆蓋以下內容:
1) Spring+Struts1+jdbctemplate;
2) Spring+Struts1+Hibernate;
3) Spring+Struts2+ibatis;
4) Spring+Struts1、2+任意DAO層的Unit Test;
5)甚至還會講到如何使用Spring來構建應用程序,對,你沒聽錯使用Spring可以構建單獨運行的java應
用程序,尤其在銀行、保險業中有一種叫「批處理」的業務,就是應用程序,那麼我們使用Spring會為
我們的批處理作業帶來什麼樣的好處呢?敬請期待!
三、Spring+Struts+jdbctemplate
3.1 框架介紹
作為架構師,同時你也必須為「框架師」,架構是從廣意上來講的,它的知識需要覆蓋到硬體、軟體、協議甚至業務背景。
但是一個架構師在項目中時它又必須是一個「框架師」,就和造房子一樣,框架搭的好,房子造出來才能堅固。
我們就先來看我們第一幢房子的腳手加架-Spring在我們項目中的使用吧,先來看架構圖,一般我喜歡用Visio來畫架構圖,畫完後直接在Visio的workspace里ctrl+a全選後回到 word後按ctrl+v,這樣你的word文本中就有了一幅visio的圖了,而你在word文檔中雙擊這個visio圖它會自動在當前的文檔中打開visio的workspace以便於你來編輯你的visio圖,這樣你就不用來回在word與 visio間進行切換了,也不用每次把visio轉成jpg後再到word中插入圖片了,這是一個標準操作模式,希望能夠為大家今後的操作帶來方便。當然,平時看到好的文檔,好的架構圖把它收藏起來、分門別類相信你的文檔會越寫越漂亮.
Look,這就是我們的框架。
Spring
在此我們使用3.1,它負責IOC,AOP等工作,用於代理業務層(Service層)的事務。
Struts
在此我們使用1.3,它負責控制層以及相關的JSP頁面(採用Struts標籤)。
控制層通過業務層再訪問資料庫層。
Spring Jdbc Template
負責ORMapping,由於我們使用的數據還需要進行一些複雜的匯總與計算,因此在未來系統開發中還需要開發一系列的StoreProcedure(存儲過程),用jdbc template不僅可以方便靈活的使用SQL查詢語句,同時也為訪問各種資料庫的存儲過程帶來了方便。
該框架優點:
1. 分層清晰,替換靈活,易於擴展
上述框架採用View Layer,Controller Layer,Service Layer,DAOLayer進行分層。層與層之間全部基於介面。
1) 邏輯的任何變動不影響到代碼的運行
2) 自動代理資料庫的事務操作,尤於採用了Spring的DataSourceTransactionManager,該類是一個完全基於AOP的事務自動代理,由於使用的是AOP中的圍繞機制,因此該類會自動利用AOP功能在資料庫操作時進行事務的開啟、提交、關閉並且在遇見Exception時會自動回滾。該類使用通配符的方式,對於業務層進行事務管理。由於Controller層不直接操作DAO,而是通過Service層來操作事務的,因此事務的切片定位在Service層。另外,由於一個Service方法有可能涉及到多個DAO操作,所以將事務定位在Service層有助於保持數據的一致性。
3) 層中相關技術的替換不影響到其它層面,層與層之間的全部基於介面,因此各個層內自身的邏輯或者是採用的相關技術的變化不影響到其它層。舉例來說:現在的DAO層是Spring JdbcTemplate,如果將來換成Hibernate或者是EJB的JPA來做DAO層的話,對於整個DAO層只需要按照原有介面重寫相關的impl類,而view層, controller層與Service層的變動為「零代碼」改動。
2. 簡化配置,提高生產力
本框架使用的是Spring3.0+Struts2.x作為系統框架的核心。傳統的框架伴隨著一堆xml文件的配置,比如說用於描述Struts中Action的配置,層與層之間的依賴關係,甚至特定的class需要用到的外部變數都需要進行基於xml格式的配置文件的修改。
Xml配置文件的改動,如果出現一處錯誤往往會影響整個系統的運行,或者甚至導致系統運行崩潰。而本框架使用了JDK1.6中的「全註解」技術,除了需要改動一個cbbs.properties文件,各層之間的調用全部使用的Annotation,比如說我們需要在一個Struts的Action中調用一個Service, 只需要在相關的Action的Class里進行如下的注釋即可:
@Resource
EmailActivationService activateService;
而傳統的需要作下面這樣的配置:
<bean id=」activation」 class=」xxx.xxx.xxx.xx」>
<ref bean=」activateService」/>
</bean>
<bean id=」activateService」 class=」xxx.xxx.xxx.EmailActivationServiceImpl」/>
設想,假如有100個類,上百個Service,再加上數百個DAO,我們的xml的配置將是多麼的龐大啊,這就是典型的「xml泛濫」,這同時也將導致程員工工作效率,生產效率的低下。
而現在採用了Annotation方式來搭建框架,這在極大程度上使得程序員與框架之間是「透明」的,讓程序員將更多時間花在「業務」的實現上。這一切都用的是Spring的「註解」特性,即
「<context:component-scan base-package="xxx.xxx.xxx" />」。
該框架不需要使用容器的jdbcjndi,而自帶了一個 c3p0的jdbcconnection pool,它將會隨著容器的啟動而啟動,結束而銷亡.
現了基本的資源保護
我們在該框架中使用了以下幾種技術的混合來實現外部資源文件的安全保護
1) 基於Spring的Properties的注入
2) 在properties文件與spring的配置xml文件里實現了placeholder,即替換符,記住它的英文的表達叫「place holder」。
3) 使用了第三方開源免費包jasypt與spring結合自動對properties文件中的關鍵內容如:password進行加密與解密
3.2 框架搭建
首先使用eclipse建立一個」dynamice web project」,我們管它叫」alpha」吧,我們的第一個孩子。
然後與src同級的地方建立一個resource目錄,並把它加入classpath
別忘了把Defaultoutput folder:從bin改成alpha/WebContent/WEB-INF/classes
再建立一個目錄叫ext-lib的目錄,把tomcat的lib目錄內的jsp-api.jar與servlet-api.jar兩個文件拷入該文件夾內.因為我們在涉及到一些servlet與jsp的編寫時,需要使用這兩個jar進行編譯,但我們又不能把這兩個jar文件與我們的工程一起發布到tomcat的webapp目錄下,因為tomcat已經含有這兩個jar文件了,所以這兩個jar文件需要以下面的方式引入我們的工程而不隨著我們的工程一起發布:
這是工程目錄結構整理完後的樣子,請照著該結構在resource目錄下自行建立其它幾個目錄(不要去管文件,先把目錄建完)。
然後我們把
struts
spring
c3p0-0.9.1.2.jar等
一些需要的jar文件一個個都copy到我們工程的WEB-INF/lib目錄下並刷新工程。這些jar在你下載的spring、struts、hibernate包中都有帶,可以自行去查找.
修改我們的web.xml文件,尤其注意下面紅色與加粗的部分,一粗就爽了是吧,嘿!
web.xml
<?xmlversion="1.0"encoding="UTF-8"?>
<web-appxmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID"version="2.5">
<display-name>alpha</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/classes/spring/**/*.xml</param-value>
</context-param>
<filter>
<filter-name>characterEncoding</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>action</servlet-name>
<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
<init-param>
<param-name>config</param-name>
<param-value>/WEB-INF/struts-config.xml,
/WEB-INF/struts-config/login.xml,
/WEB-INF/struts-config/index.xml
</param-value>
</init-param>
<init-param>
<param-name>debug</param-name>
<param-value>3</param-value>
</init-param>
<init-param>
<param-name>detail</param-name>
<param-value>3</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
<!-- Action Servlet Mapping -->
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<jsp-config>
<taglib>
<taglib-uri>/WEB-INF/struts-bean.tld</taglib-uri>
<taglib-location>/WEB-INF/struts-bean.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>/WEB-INF/struts-html.tld</taglib-uri>
<taglib-location>/WEB-INF/struts-html.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>/WEB-INF/struts-logic.tld</taglib-uri>
<taglib-location>/WEB-INF/struts-logic.tld</taglib-location>
</taglib>
</jsp-config>
</web-app>
在該web.xml文件內我們
首先:
聲明了把我們的工程目錄下的「/WEB-INF/classes/spring/**/*.xml」讓spring去載入,因為我們這些.xml文件都在我們的resource目錄下,而我們的resource目錄和src目錄一樣是會在編譯時自動跑到WEB-INF/classes目錄下的,是不是?
其次:
我們聲明了一個filter叫「characterEncoding」,該filter的作用可以支持你的工程中無論是從jsp到.do還是從.do到jsp時對於中文字元的輸入不用你再去手動的轉newString(「xxx」,」UTF-8」)這樣的轉碼操作了。
最後:
我們聲明了我們的struts的action mapping文件所在的位置,我們在此處聲明了3個struts-config文件,主config文件為:/WEB-INF/struts-config.xml,其它兩個為我們的「模擬級config文件」。
/WEB-INF/struts-config.xml
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE struts-config PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 1.3//EN"
"http://struts.apache.org/dtds/struts-config_1_3.dtd">
<struts-config>
<form-beans />
<global-forwards>
<forward name="error" path="/jsp/error/syserror.jsp" />
</global-forwards>
<!-- ========== Action Mapping Definitions ============================== -->
<action-mappings />
<!-- ========== Controller Configuration ================================ -->
<controller>
<set-property property="processorClass"
value="org.springframework.web.struts.DelegatingRequestProcessor" />
</controller>
<!-- ========== Message Resources Definitions =========================== -->
<message-resources
parameter="org.apache.struts.webapp.example2.ApplicationResources" />
<plug-in className="fr.improve.struts.taglib.layout.workflow.LayoutPlugin" />
</struts-config>
該文件中:
<controller>
<set-property property="processorClass"
value="org.springframework.web.struts.DelegatingRequestProcessor" />
</controller>
的作用就是把我們的struts中的action委託給了spring去管理,因為我們的一切都是通過action/.do入手的,因此一旦我們的action被spring託管起來後,那麼action下調用的service, service調用的dao都被我們的spring進行託管了,於是一切就都可以「注入」了.
下面,我們來看我們的applicationContext.xml文件,這個非常核心的一個文件。
applicationContext.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context" xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:annotation-config/>
<context:component-scan base-package="org.sky.ssh1.alpha" />
<bean id="environmentVariablesConfiguration"
p:algorithm="PBEWITHMD5ANDDES" p:passwordEnvName="APP_ENCRYPTION_PASSWORD" />
<bean id="configurationEncryptor"
p:config-ref="environmentVariablesConfiguration" />
<bean id="propertyConfigurer">
<constructor-arg ref="configurationEncryptor" />
<property name="locations">
<list>
<value>
classpath:jdbc.properties
</value>
</list>
</property>
</bean>
<context:property-placeholder location="classpath:jdbc.properties" />
<bean id="commonsConfigurationFactoryBean"
p:encryptor-ref="configurationEncryptor" p:systemPropertiesModeName="SYSTEM_PROPERTIES_MODE_OVERRIDE">
<constructor-arg>
<bean>
<constructor-arg value="jdbc.properties" />
</bean>
</constructor-arg>
</bean>
<bean id="propertiesConfiguration" factory-bean="&commonsConfigurationFactoryBean"
factory-method="getConfiguration" />
<!-- you can ignore following lines -->
<bean id="methodLoggerAdvisor">
</bean>
<bean id="springUtil">
</bean>
<aop:config>
<aop:aspect id="originalBeanAspect" ref="methodLoggerAdvisor">
<aop:pointcut id="loggerPointCut" expression="execution(* org.sky.ssh1.service.impl.*.*(..))" />
<aop:around method="aroundAdvice" pointcut-ref="loggerPointCut" />
</aop:aspect>
</aop:config>
</beans>
主要還是紅色加粗的部分,解釋如下:
1)<context:annotation-config/>
可以在你的struts的action文件中啟用@Controller這樣的註解將struts的action委託給spring進行管理
2)<context:component-scanbase-package=」org.sky.ssh1.alpha」 />
在該「package」下所有的類都委託給了spring進行管理
3)
bean id="environmentVariablesConfiguration"
bean id="configurationEncryptor"
Bean id="propertyConfigurer"
context:property-placeholderlocation="classpath:jdbc.properties"
beanid="commonsConfigurationFactoryBean"、beanid="propertiesConfiguration"
這些個bean的申明可以讓你如以下場景般的去使用,請看:
我有一個jdbc.properties文件,內容如下:
jdbc.driverClassName=oracle.jdbc.OracleDriver
jdbc.databaseURL=jdbc:oracle:thin:@localhost:1521:ymkorcl
jdbc.username=alpha
jdbc.password=ENC(W1BJSjx6+1O1z3ArmojmaQG+r80ty3zX)
注意這個jdbc.password,這個value是被加密了的。
然後我有一個datasource.xml文件,內容如下:
<bean id="dataSource"
destroy-method="close">
<property name="driverClass" value="${jdbc.driverClassName}"/>
<property name="jdbcUrl" value="${jdbc.databaseURL}" />
<property name="user" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<property name="initialPoolSize" value="10" />
<property name="minPoolSize" value="10" />
<property name="maxPoolSize" value="15" />
<property name="acquireIncrement" value="1" />
<property name="maxIdleTime" value="5" />
</bean>
看到了沒有?這就叫「property-placeholder「,因為。。。因為如果哪天我的資料庫換成了mysql後,是不是我只要在我的jdbc.properties文件里換換內容就可以了而不需要再去動這個datasource.xml文件啊?
那麼說到加密這個問題很簡單,這個加密我們用的是「StandardPBEStringEncryptor」里的
PBEWITHMD5ANDDES p:passwordEnvName=」APP_ENCRYPTION_PASSWORD」,所謂PBE就是password base的意思,因此我們這個加密首先用的是DES,然後為了解密這個DES還需要一個password,而這個password我們設在哪邊?
<bean id="configurationEncryptor"
p:config-ref="environmentVariablesConfiguration" /
啊。。。environmentVariablesConfiguration, 所以我們來看:
看到了沒有,如果你是linux系統則需要在/etc/profile文件中加入:
export APP_ENCRYPTION_PASSWORD=」aaaaaa」
所以我們為了解這個DES密碼時需要一個口令,這個口令在我們的系統環境變數,值為六個a。
我們看到在commonsConfigurationFactoryBean里我們自定義了一個class為:
org.sky.ssh1.alpha.util.CommonsConfigurationFactoryBean的類,我們來看這個類吧.
org.sky.ssh1.alpha.util.CommonsConfigurationFactoryBean內容詳見原文鏈接。
系列
通向架構師的道路(第一天)之 Apache 整合 Tomcat
通向架構師的道路(第二天)之 apache tomcat https 應用
通向架構師的道路(第三天)之 apache 性能調優
通向架構師的道路(第四天)之 Tomcat 性能調優
通向架構師的道路(第五天)之 tomcat 集群 – 群貓亂舞
通向架構師的道路(第六天)之漫談基於資料庫的許可權系統的設計
通向架構師的道路(第七天)之漫談使用 ThreadLocal 改進你的層次的劃分
通向架構師的道路(第八天)之 Weblogic 與 Apache 的整合與調優
通向架構師的道路(第九天)之 Weblogic 的集群與配置
通向架構師的道路 ( 第十天 ) 之 Axis2 Web Service ( 一 )
通向架構師的道路 ( 第十一天 ) 之 Axis2 Web Service ( 二 )
通向架構師的道路 ( 第十二天 ) 之 Axis2 Web Service ( 三 )
通向架構師的道路 ( 第十三天 ) Axis2 Web Service 安全初步
通向架構師的道路 ( 第十四天 ) Axis2 Web Service 安全之 rampart
通向架構師的道路 ( 第十五天 ) IBM Websphere 的安裝與優化
通向架構師的道路 ( 第十六天 ) IBM Websphere 與 IBM HttpServer 的集成
通向架構師的道路 ( 第十七天 ) IBM Websphere 集群探秘 – WASND
看完本文有收穫?請轉發分享給更多人
關注「ImportNew」,提升Java技能


※深入分析 ThreadLocal 內存泄漏問題
※不同的垃圾回收器的比較
TAG:ImportNew |