AnnotationConfigApplicationContext:從一個或多個基於java配置類中加載Spring應用上下文
AnnotationConfigWebAppApplicationContext:從一個或多個基於java配置類中加載Spring Web應用上下文
ClassPathXmlApplicationContext:從類路徑下的一個或多個XML文件中加載上下文定義,把上下文定義文件作爲類資源
FileSystemXmlApplicationContext:從文件系統下的一個或多個XML文件中加載上下文定義
XmlWebApplicationContext:從WEB應用下的一個或多個XML文件中加載上下文定義
ApplicationContext context= new FileSystemXmlApplicationContext("c:/knight.xml");
ApplicationContext context= new ClassPathXmlApplicationContext("knight.xml");
ApplicationContext context= new
AnnotationConfigApplicationContext("com.springinaction.knight.config.Knight.class");
getBean(); 返回一個實例
//通過DI AOP和消除樣板式代碼來簡化開發
Spring核心容器
Component named
Autowired Inject
javaConfig
@Configuration
@ComponentScan
public class CDPlayerConfig{
@Bean
public CDPlayer cdPlayer(){
return new CDPlayer(sgtPeppers()); //cdPlayer //sgtPeppers implements compactDisc
}
@Bean
public CDPlayer anthorCdPlayer(){
return new CDPlayer(sgtPeppers()); //cdPlayer
}
}
//這裏調用了兩次sgtPeppers,spring默認是單例模式,因此第二次調用的時候會攔截,並返回已經創建的bean,
//即同一個sgtPeppers
xml配置
方法一:
<bean id="cdPlayer" class="com.qmylzx.view.CDPlayer">
<constructor-arg ref="compactDisc"/>
<property name="compactDisc" ref="compactDisc"></property>
</bean>
方法二: c命名空間和模式聲明 spring 3.0版本支持
<bean id="cdPlayer" class="com.qmylzx.view.CDPlayer" c:cd-ref="compactDisc"></bean>
c:cd-ref="compactDisc" 若參數爲字符串 c:cd="hello world"
c: c命名空間
cd 構造器參數名
-ref 注入bean引用
compactDisc bean的名字
或者 c:_0-ref c:_1-ref 或者 c:_cd-ref 當只有一個構造器參數的時候可以 c:_-ref
當參數爲list時 c命名空間不支持list
<bean id="cdPlayer" class="com.qmylzx.view.CDPlayer">
<constructor-arg>
<list> //<set></set>
<value></value> //<ref bean="beanName"/>
<value></value> //<ref bean="beanName"/>
<value></value> //<ref bean="beanName"/>
</list>
</constructor-arg>
</bean>
p命名空間 <bean id="cdPlayer" class="com.qmylzx.view.CDPlayer" p:compactDisc-ref="compactDisc"/>
p:compactDisc-ref="compactDisc" 若參數爲字符串 p:compactDisc="hello world"
p: p命名空間
compactDisc 屬性名
-ref 注入bean引用
compactDisc bean的名字
util-命名空間
<util:list id="trackList"> //給 List trackList; 賦值
<value></value>
<value></value>
<value></value>
</util:list>
<bean id="compactDisc" class="com.qmylzx.view.BlankDisc"
p:title="hello world" p:artist="hello world" p:tracks-ref="trackList" />
Class BlankDisc{
String title; String artist; List tracks;
}
util:
constant 引用某個類型的public static域,並將其暴露爲bean
list 創建List類型的bean 其中包含值或引用
map 創建Map類型的bean 其中包含值或引用
properties 創建Properties類型的bean
property-path 引用一個bean 的屬性 並暴露爲bean
set 創建Set類型的bean 其中包含值或引用
@Configuration //引入CompactDisc 或者
@Import(CDConfig.class) //用第三個類@Import({CDConfig.class,CDPlayerConfig.class})
public class CDPlayerConfig{
@Bean
public CDPlayer cdPlayer(CompactDisc compactDisc){ return new CDPlayer(compactDisc)}
}
//@Import 引入java配置文件 引入xml用@ImportResource("classpath:config.xml")
<bean class="com.qmylzx.config.CDConfig"></bean> //xml中引入javaconfig配置
//<import resource="config.xml"/> 引入另外的xml配置
<!-- 開始組件掃描 -->
<context:component-scan base-package="com.qmylzx.ssm"></context:component-scan>
@Profile("dev") //多個類似的Bean,當激活名字爲dev的Profile時Bean纔會起作用
<bean profile="dev"></bean> // xml配置
@ActiveProfiles("dev") //在使用類下標記
在web.xml中 servlet下的
<init-param>
<param-name>spring.profiles.default</param-name>
<param-value>dev,dev2</param-value> //可以激活多個,激活彼此不相關的
//dev2<param-value>dev</param-value>
</init-param>
//首先看spring.profiles.active 再看spring.profiles.default 都沒有則找沒有profile標記的bean初始化
@Conditional(MyCondition.class) //spring4.0 給定的條件判定爲真就激活這個bean
public interface Condition{boolean matches(ConditionContext c,AnnotatedTypeMetadata a);}
public MyCondition implements Condition{
boolean matches(ConditionContext c,AnnotatedTypeMetadata a){
Environment e = c.getEnvironment(); return e.containsProperty("dev");
}
}
//主要根據ConditionContext的條件進行判定 AnnotatedTypeMetadata可得到@Bean的還使用了什麼註解
@Primary //一個接口存在多個實例化類bean的時候Spring無法判定使用哪一個
//使用這個標記,可以設置首選bean
<bean primary="true"></bean>
//若Primary後還存在歧義 則可以用qulifier 需要配合autowired inject一起使用
@Autowired
@Qulifier("指定類名")
@Component
@Qulifier("cold") //這裏可以 指定類的 限定名 爲cold 其他位置使用cold即可,不用擔心該bean被重構
class{
}
@bean
@Qulifier("cold") //產生歧義的時候,可以自定義註解標籤來代替Qulifier
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) //標記bean創建多少個
//Singleton 默認 @Scope("prototype")也可以
//Prototype 每次注入或Spring上下文獲取創建一個新的
//Session WEB應用中每個會話創建一個
//Rquest WEB應用中每個req創建一個
<bean scope=""></bean>
@Scope(WebApplicationContext.SCOPE_SESSION,
proxyMode=ScopedProxyMode.INTERFACES) //基於接口
//proxyMode=ScopedProxyMode.INTERFACES標記只有當客戶端使用時才被注入
//ScopedProxyMode.TARGET_CLASS 基於類
// //== proxyMode=ScopedProxyMode.INTERFACES
<bean scope=""><aop:scoped-proxy proxy-target-class="true"/></bean>
注入外部的值
@Configuration
@PropertySource("classpath:/com/qmylzx/app.properties")
public class ExpressConfig{
@Autowired
Environment env;
@Bean
public BlankDisc disc(){
return new BlankDisc(env.getProperty("disc.title"),env.getProperty("disc.artist"));
}//這裏getProperty配置文件爲空獲取null
} //getRequiredProperty("disc.title") 配置文件爲空則拋出異常
app.properties
disc.title=hello world
disc.artist=xx
SpringEL
#{語句}
#{實例類名} //獲取類
#{double.屬性名} //獲取類屬性
#{double.getInt()?.toString()} //這裏? 表示會檢測getInt()方法返回值是否爲null,
//null的話不會調用toString()方法
@Value("#{systemProperties=['disc.title']}") //獲取配置文件屬性
#{2*T(java.lang.Math).PI*R^2} //T()返回一個Class對象 算術運算
#{disc.title+'by'+disc.artist} //連接字符串 比較 == eq
#{disc.email matches '[a-zA-z0-9]'} // matches '[a-zA-z0-9]'正則表達式
#{muisicbox.songs[T(java.java.lang.Math).random()*10]} // []取值
#{muisicbox.songs.?[artist eq 'Alan worker']} // .?[] 對集合進行過濾
//.^[] .$[] .![]
面向切面的Spring
即:貫穿多個Service的某些方法的橫切關注點 如:日誌、事務、安全等
橫切關注點可以模塊化爲特殊的類,這些類被稱爲切面;
通知advice
切面的工作
1.Before
2.After
3.After-returning
4.After-throwing
5.Around 通知包裹了被通知的方法,在被通知方法調用之前和之後執行自定義的行爲
連接點joinpoint
在應用程序執行過程中能插入切面的一個點,這個點可以是 調用方法、拋出異常、修改字段
切面代碼可以利用這些點插入到應用到正常流程中並 添加新的行爲
切點pointcut
切點有助於縮小 切面所通知的 連接點 的範圍
通知定義切面的“什麼”和“何時” 切點 定義“何處”
切面
通知與切點的結合
引入(Introduction)
允許我們向現有的類添加新的屬性和方法。例如:創建Auditable類,記錄對象最後一次修改時的狀態
只需要一個setLastModified(Date);方法和實例變量保存該狀態就可以了,從而可以在不修改原有類的
基礎上使其有新的行爲和狀態。
織入(Weaving)
把切面應用到目標對象並創建新的代理對象的過程。切面在指定的連接點織入到目標對象中,有多個點可以織入
1.編譯期:需要特殊的編譯器 AspectJ織入編譯器
2.類加載期:加載到jvm時被織入 需要特殊的類加載器 AspectJ 5支持load-time waving LTW
3.運行期:應用在運行的某個時刻被織入。 Spring AOP
Spring AOP 因爲 Spring 基於 動態代理 只支持 方法級別 的AOP,需要其他級別可用 Aspect 補充
1.基於代理的經典Spring AOP
2.純POJO切面
3.@AspectJ註解驅動的切面 //前三種是Spring AOP的變體
4.注入式AspectJ切面(適用於Spring各版本)
package com.qmylzx.concert;
public interface Performence {
void perfrom();
}
//springxml下可用//and or not
execution(* concert.Performence.perfrom(..) && within(concert.*)) // && || !
execution 在方法執行時觸發
* 返回任意類型
concert.Performence 方法所屬的類型
perfrom 方法
(..) 使用任意參數
within(concert.*) 在concert包下任意類的方法被調用時 執行
bean('beanName') 在指定beanName的方法被調用時 執行
package com.qmylzx.concert;
import org.aspectj.lang.annotation.*;
@Aspect
public class Audience {
@Pointcut("execution(** com.qmylzx.concert.Performence.perform(..))")
public void performence(){}
@Before("performence()")// @Before("execution(** com.qmylzx.concert.Performence.perform(..))")
public void slienceCellPhone() {//ready
System.out.println("slienceCellPhone");
}
@AfterReturning("performence()")
public void appluse(){//success
System.out.println("appluse appluse appluse!");
}
@AfterThrowing("performence()")
public void fail(){
System.out.println("fail!!!");
}
@Around("performence()")
public void safe(ProceedingJoinPoint proceedingJoinPoint){
System.out.println("注意安全");
proceedingJoinPoint.proceed();//調用Perform的方法
System.out.println("注意安全");
}
}
package com.qmylzx.concert;
@Configuration
@EnableAspectJAutoProxy //啓用AspectJ註解的自動代理
@ComponentScan
public class ConcertConfig {
@Bean
public Audience audience(){
return new Audience();
}
}
<aop:aspectj-autoproxy/> //springxml啓用AspectJ註解的自動代理
//記錄磁道被使用的次數
@Pointcut("execution(* sound.cd.playTrack(int))"+"args(trackNumber)");
public void trackPlayed(int trackNumber){}
args(trackNumber) 指定參數 表明傳到playTrack()的int參數也會傳到通知中去
trackNumber與方法前面匹配
Before("trackPlayed(trackNumber)")
------------------------------------------------------------------------------
@Aspect
class EncoreableIntroducer{
@DeclareParents(value="com.qmylzx.concert.Performence+",
defaultImpl=DefaultEncoreable.class)
public static Encoreable en;
}
//沒有使用通知,而是使用DeclareParents將Encoreable 接口引入Performence bean中
//value指定哪種類型的bean要引入該接口 Performence+ 表示 Performence 的子類型
//defaultImpl指定爲了引入功能提供實現的類
//靜態屬性 指定了要引入的接口
同時需要 <bean class="com.qmylzx.concert.EncoreableIntroducer">
<aop:aspect>
<aop:declare-parents types-matching="concert.Performance+"
implements-interface="concert.Encoreable"
default-impl="concert.DefaultEncoreable">
</aop:declare-parents> // default-impl可替換爲delegate-ref="beanname"
</aop:aspect> //其中<bean id="beanname" class="concert.DefaultEncoreable" />
------------------------------------------------------------------------------------
<aop:config>
<aop:aspect ref="Audience">
<aop:pointcut id="per" expression="* concert.Performence.perfrom(..)"/>
<aop:before method="slienceCellPhone" pointcut="execution(**
com.qmylzx.concert.Performence.perform(..))"></aop:before>
// pointcut-ref = "per"
</aop:aspect>
</aop:config>
<aop:config>
<aop:aspect ref="trackCounter">
<aop:pointcut id="trackPlayed"
expression="execution(* com.qmylzx.concert.TrackCounter.playTrack(int)) and args(trackNumber)"/>
<aop:before method="countTrack" pointcut-ref="trackPlayed"></aop:before>
</aop:aspect>
</aop:config>
//注入AspectJ切面
<bean class="com.qmylzx.CriticAspect" factory-method="aspectof" >
<property name="criticEngine" ref="criticEngine"></property>
</bean>
//這個切面是在方法執行完成以後才注入的criticEngine 而CriticAspect在開始階段就已經創建
//現在要注入只能使用AspectJ自帶的靜態aspectof方法 需要指定factory-method="aspectof"
標註以後方法直接獲取而不用requestget
@RequertParam("") @RequertParam(value="",defaultValue="")
//也可以 /ssm/admin?spittleId=123456
@RequestMapping(/{spittleId}) //解析123456爲參數 /ssm/admin/123456
public String spittr(@PathVariable("spittleId") long spittleId){
}
視圖解析器
InteranlResourceViewResolver --JSP
VelocityViewResolver --Velocity
FreeMarkerViewResolver -- FreeMarker
ThymeleafViewResolver --Thymeleaf
<!-- 配置視圖解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/view/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
配置 支持Thymeleaf
<bean id="viewResolver" class="org.thymeleaf.spring3.view.ThymeleafViewResolver"
p:templateEngine-ref="templateEngine"/>
<bean id="templateEngine" class="org.thymeleaf.spring3.SpringTemplateEngine"
p:templateResolver-ref="templateResolver"/>
<bean id="templateResolver" class="org.thymeleaf.templatesesolver.ServletContextTemplateResolver"
P:prefix="/WEB-INF/view/" p:suffix=".html" p:templateMode="HTML5"/>
<a th:href="@{/spittles}">Spittles</a>
//拋出異常的時候會返回相應的HTTP狀態碼
@ResponseStatus(value=HttpStatus.NOT_FOUND,reason="not found")//404
public class MyException extends Exception{
}
@ExceptionHandler(MyException.class) //標記方法,拋出MyException異常會調用被標記的方法
@ControllerAdvice 標記的類爲所有Controller處理異常
return "redirect:/admin/test"; //重定向到test頁面,當前req的數據會丟失
參數列表中RedirectAttributes model
model.addAttribute(key,obj);
model.addFlashAttribute(key,obj); //會存數據到重定向的請求中
Spring Web Flow //流程化應用程序,例如購買商品一步接一步
<flow:flow-executor id="flowExecutor"/> //1..裝配流程執行器
<flow:flow-registry id="flowregistry" base-path="/WEB-INF/flows"> //2..配置流程註冊表
<flow:flow-location-pattern value="*-flow.xml"/>
</flow:flow-registry> //以-flow.xml結尾的XML視爲流程定義
流程註冊表基本路徑 流程定義
flow-location-pattern == /WEB-INF/flows + order + order-flow.xml
流程ID
//或者
<flow:flow-location path="/WEB-INF/flows/order.xml"/> //流程ID order
//3..處理流程請求
<bean class="org.springframework.webflow.mvc.servlet.FlowHandlerMapping">
<property name="flowregistry" ref="flowregistry"
</bean>
//FlowHandlerMapping定義了一個id爲order的流程,若請求的URL模式是(相對應用上下文路徑)'/order'
//就會匹配到這個流程上
//4..響應請求
<bean class="org.springframework.webflow.mvc.servlet.FlowHandlerAdapter">
<property name="flowExecutor" ref="flowExecutor"></property>
</bean>
Spring Web Flow可選狀態
行爲(Action) 流程邏輯發生的地方
決策(Decision) 將流程分爲兩個方向,基於數據的評估結果確定流程方向
End 流程終止
Subflow 子流程
View 暫停流程並邀請用戶參與流程
<view-state id="welcome"/> //在流程內標識這個狀態,沒指定其它視圖,則默認welcome視圖
<view-state id="welcome" view="greeting"/> //自定義視圖
<view-state id="takePayment" model="flowScope.paymentDetails"/> //指明表單捆綁的對象
行爲狀態觸發bean的方法並且根據方法執行結果轉移到另外的狀態
<action-state>
<evaluate expression="pizzaFlowActions.saveOrder(order)"/> //行爲狀態要做的事情
<transition to="thankYou"/>
</action-state>
<dicision-state id="checkDeliveryArea">
<if test="pizzaFlowActions.checkDeliveryArea(customer.zipCode)"
then="addCustomer" else="deliveryWarning"/>
</dicision-state>
<subflow-state id="order" subflow="pizza/order">
<input name="order" value="order"/>
<transition on="orderCreated" to="payment"/> //子流程end狀態爲orderCreated則進入payment
</subflow-state>
<end-state id="orderCreated" /> //view="se" flowRedirect:
轉移transition
on 觸發轉移事件 to轉移
on-exception="com.MyException"
<global-transitions> //全局狀態轉移,所有狀態都會擁有這個屬性
<transition></transition>
</global-transitions>
<var name="customer" class="com.customer">
<evaluate result="viewScope.toppingsList" //計算結果放到toppingsList中
expression="T(com.Topping).asList()"/>
<set name="flowScope.pizza" value="new com.domain.Pizza()">
Spring Web Flow作用域
Conversation 最高層的流程開始創建,結束時銷燬,被所有流程共享
Flow 流程開始創建,結束銷燬 ,只有創建它的流程可以看到它
Request 請求進入流程時創建,流程返回時銷燬
Flash 流程開始創建,結束銷燬
View 進入視圖創建 ,結束銷燬 ,只在視圖內可見
start--> identify Customter -(customterReady)->builderOrder-(orderCreated)->takePayment
-(paymentTaken)->saveOrder-->thankCustomter
RPC
RMI、Hessian和Burlap、HTTP invoker、JAX-RPC和JAX-WS
2進制消息 xml消息
RMI配置
RmiServiceExporter 來配置註冊rpc服務
//服務端
@Bean
public RmiServiceExporter rmiServiceExporter(){
RmiServiceExporter r = new RmiServiceExporter();
r.setService(SpitterService);
r.setServiceName("SpitterService");
r.setServiceInterface(SpitterService.class);
r.setRegistryHost("rmi.spitter.com");//綁定服務到rmi.xx.com主機的1199端口
r.setRegistryPort(1199);
return r;
}
//客戶端
@Bean
public RmiProxyFactoryBean spitterService(){
RmiProxyFactoryBean rmiProxy= new RmiProxyFactoryBean();
rmiProxy.setServiceUrl("rmi://localhost/SpitterService");
rmiProxy.setServiceInterface(SpitterService.class);
return rmiProxy;
}
//客戶端使用
@Autowired
SpitterService spitterService; //調用方法即可
------------------------------------------------------------
使用Hessian和Burlap 具有移植性
service extends HessianServlet 且方法爲public
////服務端
@Bean
public HessianServiceExporter hessianServiceExporter(){
HessianServiceExporter h = new HessianServiceExporter();
h.setService(SpitterService);
h.setServiceInterface(SpitterService.class);
return h;
}
配置控制器
<servlet-mapping>
<servlet-name>spitter</servlet-name>
<servlet-pattern>*.service</servlet-pattern>
</servlet-mapping>
@Bean
public HandlerMapping hessianMapping(){
SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
Properties mappings = new Properties();
mappings.setProperty("/spitter","hessianExportedSpitterService");
mapping.setMappings(mappings);
return mapping;
}
//客戶端
@Bean
public HessianProxyFactoryBean spitterService(){
HessianProxyFactoryBean hessianProxy= new HessianProxyFactoryBean();
hessianProxy.setServiceUrl("http://localhost:8080/Spitter/spitter.service");
hessianProxy.setServiceInterface(SpitterService.class);
return hessianProxy;
}
Restful URL
Create Post
Read Get
Update PUt\Patch
Delete Delete