然后我們要改一下代理對象DynaProxyHello中的代碼.如下:1
packagesinosoft.dj.aop.proxyaop;
2
3
importjava.lang.reflect.InvocationHandler;
4
importjava.lang.reflect.Method;
5
importjava.lang.reflect.Proxy;
6
7
publicclassDynaProxyHelloimplementsInvocationHandler{
8
??/**
9
????? * 操作者
10
?????*/
11
????privateObject proxy;
12
??/**
13
????? * 要處理的對象(也就是我們要在方法的前后加上業務邏輯的對象,如例子中的Hello)
14
?????*/
15
????privateObject delegate;
16
17
/**
18
????? * 動態生成方法被處理過后的對象 (寫法固定)
19
????? *
20
????? *@paramdelegate
21
????? *@paramproxy
22
????? *@return
23
?????*/
24
????publicObject bind(Object delegate,Object proxy){
25
????????
26
????????this.proxy=proxy;
27
????????this.delegate=delegate;
28
????????returnProxy.newProxyInstance(
29
????????????????this.delegate.getClass().getClassLoader(),this.delegate
30
???????????????????????? .getClass().getInterfaces(),this);
31
???? }
32
??/**
33
????? * 要處理的對象中的每個方法會被此方法送去JVM調用,也就是說,要處理的對象的方法只能通過此方法調用
34
????? * 此方法是動態的,不是手動調用的
35
?????*/
36
????publicObject invoke(Object proxy, Method method, Object[] args)
37
????????????throwsThrowable{
38
???????? Object result=null;
39
????????try{
40
????????????//反射得到操作者的實例
41
???????????? Class clazz=this.proxy.getClass();
42
????????????//反射得到操作者的Start方法
43
???????????? Method start=clazz.getDeclaredMethod("start",
44
????????????????????newClass[]{ Method.class});
45
????????????//反射執行start方法
46
???????????? start.invoke(this.proxy,newObject[]{ method });
47
????????????//執行要處理對象的原本方法
48
???????????? result=method.invoke(this.delegate, args);
49
//???????????? 反射得到操作者的end方法
50
???????????? Method end=clazz.getDeclaredMethod("end",
51
????????????????????newClass[]{ Method.class});
52
//???????????? 反射執行end方法
53
???????????? end.invoke(this.proxy,newObject[]{ method });
54
55
???????? }catch(Exception e){
56
???????????? e.printStackTrace();
57
???????? }
58
????????returnresult;
59
???? }
60
61
}
62
然后我們把Test.java中的代碼改一下.測試一下:
packagesinosoft.dj.aop.proxyaop;


publicclassTest{

????publicstaticvoidmain(String[] args){
???????? IHello hello=(IHello)newDynaProxyHello().bind(newHello(),newLoggerOperation());
???????? hello.sayGoogBye("Double J");
???????? hello.sayHello("Double J");
????????
???? }
}

結果還是一樣的吧.如果你想在每個方法之前加上日志記錄,而不在方法后加上日志記錄.你就把LoggerOperation類改成如下:1
packagesinosoft.dj.aop.proxyaop;
2
3
importjava.lang.reflect.Method;
4
5
publicclassLoggerOperationimplementsIOperation{
6
7
????publicvoidend(Method method){
8
????????//Logger.logging(Level.DEBUGE, method.getName() + " Method end
.");
9
???? }
10
11
????publicvoidstart(Method method){
12
???????? Logger.logging(Level.INFO, method.getName()+"Method Start!");
13
???? }
14
15
}
16
運行一下.你就會發現,每個方法之后沒有記錄日志了. 這樣,我們就把代理者和操作者解藕了!下面留一個問題給大家,如果我們不想讓所有方法都被日志記錄,我們應該怎么去解藕呢.?我的想法是在代理對象的public Object invoke(Object proxy, Method method, Object[] args)方法里面加上個if(),對傳進來的method的名字進行判斷,判斷的條件存在XML里面.這樣我們就可以配置文件時行解藕了.如果有興趣的朋友可以把操作者,被代理者,都通過配置文件進行配置 ,那么就可以寫一個簡單的SpringAOP框架了.
posted @
2009-07-24 20:43 jadmin 閱讀(96) |
評論 (0) |
編輯 收藏
從上面的例子我們看出.只要你是采用面向接口編程,那么,你的任何對象的方法執行之前要加上記錄日志的操作都是可以的.他(DynaPoxyHello)自動去代理執行被代理對象(Hello)中的每一個方法,一個java.lang.reflect.InvocationHandler接口就把我們的代理對象和被代理對象解藕了.但是,我們又發現還有一個問題,這個DynaPoxyHello對象只能跟我們去在方法前后加上日志記錄的操作.我們能不能把DynaPoxyHello對象和日志操作對象(Logger)解藕呢?結果是肯定的.讓我們來分析一下我們的需求.我們要在被代理對象的方法前面或者后面去加上日志操作代碼(或者是其它操作的代碼),那么,我們可以抽象出一個接口,這個接口里就只有兩個方法,一個是在被代理對象要執行方法之前執行的方法,我們取名為start,第二個方法就是在被代理對象執行方法之后執行的方法,我們取名為end .接口定義如下 :1
packagesinosoft.dj.aop.proxyaop;
2
3
importjava.lang.reflect.Method;
4
5
publicinterfaceIOperation{
6
??/**
7
????? * 方法執行之前的操作
8
????? *@parammethod
9
?????*/
10
????voidstart(Method method);
11
??/**
12
????? * 方法執行之后的操作
13
????? *@parammethod
14
?????*/
15
????voidend(Method method);
16
}
17
我們去寫一個實現上面接口的類.我們把作他真正的操作者,如下面是日志操作者的一個類:LoggerOperation.java
packagesinosoft.dj.aop.proxyaop;

importjava.lang.reflect.Method;


publicclassLoggerOperationimplementsIOperation{


????publicvoidend(Method method){
???????? Logger.logging(Level.DEBUGE, method.getName()+"Method end
.");
???? }


????publicvoidstart(Method method){
???????? Logger.logging(Level.INFO, method.getName()+"Method Start!");
???? }

}

posted @
2009-07-24 20:42 jadmin 閱讀(71) |
評論 (0) |
編輯 收藏
但是我們會發現一個問題,如果我們像Hello這樣的類很多,那么,我們是不是要去寫很多個HelloProxy這樣的類呢.沒錯,是的.其實也是一種很麻煩的事.在jdk1.3以后.jdk跟我們提供了一個API?? java.lang.reflect.InvocationHandler的類. 這個類可以讓我們在JVM調用某個類的方法時動態的為些方法做些什么事.讓我們把以上的代碼改一下來看看效果.
同樣,我們寫一個IHello的接口和一個Hello的實現類.在接口中.我們定義兩個方法;代碼如下 :
IHello.java
1
package sinosoft.dj.aop.proxyaop;
2
3
public interface IHello {
4
??/**
5
????? * 業務處理A方法
6
????? * @param name
7
?????*/
8
????void sayHello(String name);
9
??/**
10
????? * 業務處理B方法
11
????? * @param name
12
?????*/
13
????void sayGoogBye(String name);
14
}
15
Hello.java
1
package sinosoft.dj.aop.proxyaop;
2
3
public class Hello implements IHello {
4
5
????public void sayHello(String name) {
6
???????? System.out.println("Hello " + name);
7
???? }
8
????public void sayGoogBye(String name) {
9
???????? System.out.println(name+" GoodBye!");
10
???? }
11
}
12
我們一樣的去寫一個代理類.只不過.讓這個類去實現java.lang.reflect.InvocationHandler接口,代碼如下:
1
package sinosoft.dj.aop.proxyaop;
2
3
import java.lang.reflect.InvocationHandler;
4
import java.lang.reflect.Method;
5
import java.lang.reflect.Proxy;
6
7
public class DynaProxyHello implements InvocationHandler {
8
9
???/**
10
????? * 要處理的對象(也就是我們要在方法的前后加上業務邏輯的對象,如例子中的Hello)
11
?????*/
12
????private Object delegate;
13
14
/**
15
????? * 動態生成方法被處理過后的對象 (寫法固定)
16
????? *
17
????? * @param delegate
18
????? * @param proxy
19
????? * @return
20
?????*/
21
????public Object bind(Object delegate) {
22
????????this.delegate = delegate;
23
????????return Proxy.newProxyInstance(
24
????????????????this.delegate.getClass().getClassLoader(), this.delegate
25
???????????????????????? .getClass().getInterfaces(), this);
26
???? }
27
??/**
28
????? * 要處理的對象中的每個方法會被此方法送去JVM調用,也就是說,要處理的對象的方法只能通過此方法調用
29
????? * 此方法是動態的,不是手動調用的
30
?????*/
31
????public Object invoke(Object proxy, Method method, Object[] args)
32
????????????throws Throwable {
33
???????? Object result = null;
34
????????try {
35
????????????//執行原來的方法之前記錄日志
36
???????????? Logger.logging(Level.DEBUGE, method.getName() + " Method end
.");
37
????????????
38
????????????//JVM通過這條語句執行原來的方法(反射機制)
39
???????????? result = method.invoke(this.delegate, args);
40
????????????//執行原來的方法之后記錄日志
41
???????????? Logger.logging(Level.INFO, method.getName() + " Method Start!");
42
???????? } catch (Exception e) {
43
???????????? e.printStackTrace();
44
???????? }
45
????????//返回方法返回值給調用者
46
????????return result;
47
???? }
48
49
}
50
上面類中出現的Logger類和Level枚舉還是和上一上例子的實現是一樣的.這里就不貼出代碼了.
讓我們寫一個Test類去測試一下.代碼如下:
Test.java
1
package sinosoft.dj.aop.proxyaop;
2
3
public class Test {
4
????public static void main(String[] args) {
5
???????? IHello hello = (IHello)new DynaProxyHello().bind(new Hello());
6
???????? hello.sayGoogBye("Double J");
7
???????? hello.sayHello("Double J");
8
????????
9
???? }
10
}
11
運行輸出的結果如下:
Tue Mar 04 21:24:03 CST 2008 sayGoogBye Method end
.
Double J GoodBye!
2008-3-4 21:24:03 sayGoogBye Method Start!
Tue Mar 04 21:24:03 CST 2008 sayHello Method end
.
Hello Double J
2008-3-4 21:24:03 sayHello Method Start!
由于線程的關系,第二個方法的開始出現在第一個方法的結束之前.這不是我們所關注的!
posted @
2009-07-24 20:40 jadmin 閱讀(87) |
評論 (0) |
編輯 收藏
好長時間沒有用過Spring了. 突然拿起書.我都發現自己對AOP都不熟悉了.其實AOP的意思就是面向切面編程.OO注重的是我們解決問題的方法(封裝成Method),而AOP注重的是許多解決解決問題的方法中的共同點,是對OO思想的一種補充!還是拿人家經常舉的一個例子講解一下吧:比如說,我們現在要開發的一個應用里面有很多的業務方法,但是,我們現在要對這個方法的執行做全面監控,或部分監控.也許我們就會在要一些方法前去加上一條日志記錄,我們寫個例子看看我們最簡單的解決方案我們先寫一個接口IHello.java代碼如下:1
packagesinosoft.dj.aop.staticaop;
2
3
publicinterfaceIHello{
4
??/**
5
????? * 假設這是一個業務方法
6
????? *@paramname
7
?????*/
8
????voidsayHello(String name);
9
}
10
里面有個方法,用于輸入"Hello" 加傳進來的姓名;我們去寫個類實現IHello接口
packagesinosoft.dj.aop.staticaop;


publicclassHelloimplementsIHello{


????publicvoidsayHello(String name){
???????? System.out.println("Hello"+name);
???? }

}

現在我們要為這個業務方法加上日志記錄的業務,我們在不改變原代碼的情況下,我們會去怎么做呢?也許,你會去寫一個類去實現IHello接口,并依賴Hello這個類.代碼如下:1
packagesinosoft.dj.aop.staticaop;
2
3
publicclassHelloProxyimplementsIHello{
4
????privateIHello hello;
5
6
????publicHelloProxy(IHello hello){
7
????????this.hello=hello;
8
???? }
9
10
????publicvoidsayHello(String name){
11
???????? Logger.logging(Level.DEBUGE,"sayHello method start
.");
12
???????? hello.sayHello(name);
13
???????? Logger.logging(Level.INFO,"sayHello method end!");
14
15
???? }
16
17
}
18
其中.Logger類和Level枚舉代碼如下:Logger.java1
packagesinosoft.dj.aop.staticaop;
2
3
importjava.util.Date;
4
5
publicclassLogger{
6
??/**
7
????? * 根據等級記錄日志
8
????? *@paramlevel
9
????? *@paramcontext
10
?????*/
11
????publicstaticvoidlogging(Level level, String context){
12
????????if(level.equals(Level.INFO)){
13
???????????? System.out.println(newDate().toLocaleString()+""+context);
14
???????? }
15
????????if(level.equals(Level.DEBUGE)){
16
???????????? System.err.println(newDate()+""+context);
17
???????? }
18
???? }
19
20
}
21
Level.java1
packagesinosoft.dj.aop.staticaop;
2
3
publicenumLevel{
4
???? INFO,DEBUGE;
5
}
6
那我們去寫個測試類看看,代碼如下:Test.java1
packagesinosoft.dj.aop.staticaop;
2
3
publicclassTest{
4
????publicstaticvoidmain(String[] args){
5
???????? IHello hello=newHelloProxy(newHello());
6
???????? hello.sayHello("Doublej");
7
???? }
8
}
9
運行以上代碼我們可以得到下面結果:
Tue Mar0420:57:12CST2008sayHello method start
.
Hello Doublej
2008-3-420:57:12sayHello method end! 從上面的代碼我們可以看出,hello對象是被HelloProxy這個所謂的代理態所創建的.這樣,如果我們以后要把日志記錄的功能去掉.那我們只要把得到hello對象的代碼改成以下:1
packagesinosoft.dj.aop.staticaop;
2
3
publicclassTest{
4
????publicstaticvoidmain(String[] args){
5
???????? IHello hello=newHello();
6
???????? hello.sayHello("Doublej");
7
???? }
8
}
9
上面代碼,可以說是AOP最簡單的實現!
posted @
2009-07-24 20:37 jadmin 閱讀(75) |
評論 (0) |
編輯 收藏
<SCRIPT LANGUAGE="JavaScript">
?????? function selectInst(){
????????????? var checkbox = document.getElementsByName("inst");
????????????? for(i=0;i<checkbox.length;i++){
???????????????????? if(checkbox[i].checked){
??????????????????????????? var temp = checkbox[i].value;
??????????????????????????? alert(temp);
???????????????????? }
????????????? }
?????? }
</SCRIPT>
<form>
?????? 選擇愛好:<br>
?????? <input type="checkbox" name="inst" value="足球">足球
?????? <input type="checkbox" name="inst" value="籃球">籃球
?????? <input type="checkbox" name="inst" value="音樂">音樂
?????? <input type="checkbox" name="inst" value="上網">上網
?????? <input type="checkbox" name="inst" value="跳舞">跳舞
?????? <input type="button" value="提交" onclick="selectInst()">
</form>
posted @
2009-07-20 22:30 jadmin 閱讀(81) |
評論 (0) |
編輯 收藏
<SCRIPT LANGUAGE="JavaScript">
?????? var checkFlag = "false";
?????? function selectAll(field){
????????????? if(checkFlag=="false"){
???????????????????? for(i=0;i<field.length;i++){
??????????????????????????? field[i].checked=true;
???????????????????? }
???????????????????? checkFlag = "true";
????????????? }else{
???????????????????? for(i=0;i<field.length;i++){
??????????????????????????? field[i].checked=false;
???????????????????? }
???????????????????? checkFlag = "false";
????????????? }}
</SCRIPT>
<form>
?????? 選擇愛好: <br>
?????? <input type="checkbox" name="inst" value="足球">足球
?????? <input type="checkbox" name="inst" value="籃球">籃球
?????? <input type="checkbox" name="inst" value="音樂">音樂
?????? <input type="checkbox" name="inst" value="上網">上網
?????? <input type="checkbox" name="inst" value="跳舞">跳舞
?????? <input type="checkbox" name="chkAll" value="instAll" onclick="selectAll(this.form.inst)">全選<br>
</form>
posted @
2009-07-20 22:28 jadmin 閱讀(127) |
評論 (0) |
編輯 收藏
一、AOP 概念
Joinpoint:它定義在哪里加入你的邏輯功能,對于Spring AOP,Jointpoint指的就是Method。
Advice:特定的Jointpoint處運行的代碼,對于Spring AOP 來講,有Before advice、AfterreturningAdvice、ThrowAdvice、AroundAdvice(MethodInteceptor)等。
Pointcut:一組Joinpoint,就是說一個Advice可能在多個地方織入,
Aspect:這個我一直迷惑,它實際是Advice和Pointcut的組合,但是Spring AOP 中的Advisor也是這樣一個東西,但是Spring中為什么叫Advisor而不叫做Aspect。
Weaving:將Aspect加入到程序代碼的過程,對于Spring AOP,由ProxyFactory或者ProxyFactoryBean負責織入動作。
Target:這個很容易理解,就是需要Aspect功能的對象。
Introduction:引入,就是向對象中加入新的屬性或方法,一般是一個實例一個引用對象。當然如果不引入屬性或者引入的屬性做了線程安全性處理或者只讀屬性,則一個Class一個引用也是可以的(自己理解)。Per-class lifecycle or per-instance life cycle
二、AOP 種類
1、靜態織入:指在編譯時期就織入Aspect代碼,AspectJ好像是這樣做的。
2、動態織入:在運行時期織入,Spring AOP屬于動態織入,動態織入又分靜動兩種,靜則指織入過程只在第一次調用時執行;動則指根據代碼動態運行的中間狀態來決定如何操作,每次調用Target的時候都執行(性能較差)。
三、Spring AOP 代理原理
Spring AOP 是使用代理來完成的,Spring 會使用下面兩種方式的其中一種來創建代理:
1、JDK動態代理,特點只能代理接口,性能相對較差,需要設定一組代理接口。
2、CGLIB 代理,可代理接口和類(final method除外),性能較高(生成字節碼)。
四、Spring AOP 通知類型
1、BeforeAdvice:前置通知需實現MethodBeforeAdvice,但是該接口的Parent是BeforeAdvice,致于什么用處我想可能是擴展性需求的設計吧。或者Spring未來也并不局限于Method的JoinPoint(胡亂猜測)。BeforeAdvice可以修改目標的參數,也可以通過拋出異常來阻止目標運行。
2、AfterreturningAdvice:實現AfterreturningAdvice,我們無法修改方法的返回值,但是可以通過拋出異常阻止方法運行。
3、AroundAdvice:Spring 通過實現MethodInterceptor(aopalliance)來實現包圍通知,最大特點是可以修改返回值,當然它在方法前后都加入了自己的邏輯代碼,因此功能異常強大。通過MethodInvocation.proceed()來調用目標方法(甚至可以不調用)。
4、ThrowsAdvice:通過實現若干afterThrowing()來實現。
5、IntroductionInterceptor:Spring 的默認實現為DelegatingIntroductionInterceptor
五、Spring AOP Pointcut
以上只是Advice,如果不指定切入點,Spring 則使用所有可能的Jointpoint進行織入(當然如果你在Advice中進行方法檢查除外)。因此切入點在AOP中扮演一個十分重要的角色。Spring 2.0 推薦使用AspectJ的Annocation的切入點表達式來定義切入點,或者使用<aop:xxx/>來定義AOP,這方面本篇不做考慮。
1、Pointcut:它是Spring AOP Pointcut的核心,定義了getClassFilter()和getMethodMatcher()兩個方法。
2、ClassFilter:定義了matches(Class cls)一個方法。
3、MethodMatcher() 定義了matches(Method,Class),isRuntime(),matches(Mathod,Class,Object[])三個方法,如果isRuntime()返回true則表示為動態代理(實際是動態代理的動態代理),則調用第三個方法(每訪問一次調用一次),否則調用第一個方法(并且只調用一次)
4、Spring AOP 靜態切入點的幾個實現。
ComposablePointcut 太復雜一個切入點無法表達就用這個,union MethodMatcher和ClassFilter或者intersection MethodMatcher、ClassFilter和Pointcut。為什么不實現union Pointcut? 而只能通過Pointcuts類對Pointcut進行union操作。
ControlFlowPointcut 想對程序的運行過程進行追蹤就用這個
DynamicMatchMatcherPointcut 想用動態AOP 就用這個
JdkRegexpMethodPointcut 想使用正則表達式就用這個
Perl5RegexpMethodPointcut
NameMatchMethodPointcut 想用方法名字來匹配就用這個
StaticMethodMatcherPointcut 靜態切入點就用這個
沒有人反對你直接實現Pointcut:)。
六、Spring AOP 中的Advisor其實就是Aspect
1、 PointcutAdvisor
其實一般使用DefaultPointcutAdvisor就足夠了,給它Advice和Pointcut。
當然如果想少寫那么幾行代碼也可以使用NameMatchMethodPointcutAdvisor,RegexpMethodPointcutAdvisor等。
更多Advisor可以查看API文檔。
2、 IntroductionAdvisor
默認實現為DefaultIntroductionAdvisor。
七、AOP ProxyFactory
使用代碼實現AOP 可使用ProxyFactory
聲明式AOP 可使用ProxyFactoryBean
ProxyFactoryBean 需要設定 target,interceptorNames(可以是Advice或者Advisor,注意順序)
對接口代理需設置proxyInterfaces
八、自動代理
BeanNameAutoProxyCreator
- <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> ??
- ???? <property name="beanNames"><value>jdk*,onlyJdk</value></property> ??
- ???? <property name="interceptorNames"> ??
- ???????? <list> ??
- ???????????? <value>myInterceptor</value> ??
- ???????? </list> ??
- ???? </property> ??
- </bean>??
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames"><value>jdk*,onlyJdk</value></property>
<property name="interceptorNames">
<list>
<value>myInterceptor</value>
</list>
</property>
</bean>
DefaultAdvisorAutoProxyCreator
- <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/> ??
- <bean class="org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor"> ??
- ???? <property name="transactionInterceptor" ref="transactionInterceptor"/> ??
- </bean> ??
- <bean id="customAdvisor" class="com.mycompany.MyAdvisor"/> ??
- <bean id="businessObject1" class="com.mycompany.BusinessObject1"> ??
- ???? <!-- Properties omitted --> ??
- </bean> ??
- <bean id="businessObject2" class="com.mycompany.BusinessObject2"/>??
posted @
2009-07-20 21:44 jadmin 閱讀(153) |
評論 (0) |
編輯 收藏
需明確的幾個概念:
l???????? 通知(Advice):用于告知系統將有哪些新的行為。
l???????? 切入點(Pointcut):定義了通知應該在應用到那些連接點。
l???????? 目標對象(Target):被通知的對象。
l???????? 代理(Proxy):將通知應用到目標對象后創建的對象。
Spring有兩種代理創建方式:
1.???如果目標對象實現了一個或多個接口暴露的方法,Spring將使用JDK的java.lang.reflect.Proxy創建代理。這個類讓Spring動態產生一個新的類,它實現了所需的接口,織入了通知,并且代理目標的所有請求。(這篇主要介紹這個方式)
2.???如果目標對象沒有實現任何接口,Spring使用CGLIB庫生成目標對象的子類。在創建這個子類的時候,Spring將通知織入,并且將對目標對象的調用委托給這個子類。
下面以一個實例說明Spring AOP的基本開發方法:
一.創建通知
Spring連接點模型是建立在方法攔截上,這意味著你編寫的
Spring通知會在方法調用周圍的各個地方織入系統中。

TestAopServiceAdvice實現了接口MethodBeforeAdvice(前置通知),并實現它的惟一的方法before,這個類就可以在調用目標對象前被調用。同樣的還有AfterReturningAdvice(后置通知),MethodInterceptor(環繞通知),異常通知(ThrowsAdvice),引入通知等。
在這個方法中我們輸出了一個字符串TestAopServiceAdvice,用于驗證這個方法是否在目標對象前調用了。
注意:我們無法改變before方法中的參數args和target中的值,args中存的是原來要傳入目標對象的變量,target即指目標對象。
二.配置Spring XML配置文件
要在Spring中實現AOP,一般情況下需要配置4個bean:
1.???目標對象(target)
2.???通知(advice)
3.???切入點(pointcut)
4.???代理(proxy)

切入點又分為靜態切入點和動態切入點
l???????? 靜態切入點的意思是通知總是被執行,也是最常用的一種切入點。
l???????? 動態切入點根據運行時方法的參數值決定通知是否被執行。
在圖2中,定義了使用了一個Spring提供的靜態切入點
NameMatchMethodPointAdvisor,它保證了當被調用的方法的名字與給出的映射名字相匹配的時候,這個切入點才匹配。
Spring提供的另一個靜態切入點為RegexpMethodPointcutAdvisor,讓你可以利用正則表達式來定義切入點,正則表達式需要jakarta-oro.jar包的支持。
使用ProxyBeanFactory可以創建一個被通知的類,即代理對象。它的最常用的三個控制行為的屬性是:
l???????? proxyInterfaces:代理應該實現的接口列表。
l???????? interceptorNames:需要應用到目標對象上的通知Bean的名字。可以是攔截器、Advisor或其他通知類的名字。
注:在用容器的getBean方法時,應該是getBean(代理類的名字),而不是getBean(目標對象的名字),否則AOP無法工作。
posted @
2009-07-20 21:43 jadmin 閱讀(84) |
評論 (0) |
編輯 收藏
Spring2.5是Spring2.1各個里程碑版本的終結。
Spring2.5是對Spring2.0的增強,增加了一些新的特性:
- 全面支持java6和javaEE5(JDBC 4.0, JTA 1.1, JavaMail 1.4, JAX-WS 2.0等)
- 全特性的注釋驅動依賴注入,包括對限定詞的支持
- 支持基于classpath的組件掃描,自動偵測有注釋的類
- 支持AspectJ切點表達式中包含bean name切點元素
- 內置AspectJ加載時編織,基于LoadTimeWeaver 提取
- 更多的XML配置文件的名字空間支持,比如context和jms等,最大程度提高編寫的方便性
- 全面修訂集成測試框架,支持JUnit4和TestNG
- 新的基于注釋的Servlet MVC和Portlet MVC控制器風格配置
- 擴展SimpleJdbcTemplate功能,支持命名的參數等
- 官方認可的Websphere支持,支持WebSphere 6 UOWManager 機制
- Spring框架的jar文件,兼容OSGi綁定,并能直接使用
- Spring ApplicationContext可被部署為JCA RAR文件,用于非主導應用模塊
- JCA 1.5消息終端管理,用于Spring管理的JMS和CCI消息監聽器
另外,分發包有三種形式,增加了最小標準zip包和包含文檔的zip包。
官方推薦升級所有2.0.x版本到2.5版本,因為可以從新特性中獲益和顯著提升性能。
Spring2.0可以簡單的升級到2.5版本,只需替換相關jar文件。
Spring2.5仍然兼容JDK1.4.2+和J2EE1.3+。
posted @
2009-07-20 01:45 jadmin 閱讀(78) |
評論 (0) |
編輯 收藏
一、事務管理
事務傳播
1、required:方法在一個事務中執行,如果調用的方法在一個事務中,則使用該事務,否則將創建一個新的事務。(必須有,有就用,沒有就建)
2、mandatory:如果運行于事務中的客戶調用了該方法,方法在客戶的事務中執行。如果客戶沒有關聯到事務中,容器就會拋出TransactionRequiredException.(必須有,有就用,沒有報錯)
3、requiresnew:方法將在一個新的事務中執行,如果調用的方法已經在一個事務中,則暫停舊的事務。在調用結束后恢復舊的事務。(必須有,有沒有都要建)
4、supports:如果方法在一個事務中被調用,則使用該事務,否則不使用事務。(有沒有都中,有就用,沒有不用)
5、not_supported:如果方法在一個事務中被調用,容器會在調用之前終止該事務。在調用結束后,容器會恢復客戶事務。如果客戶沒有關聯到一個事務中,容器不會入運行在該方法啟動一個新的事務。用notsupported屬性標識不需要事務的方法。因為事務會帶來更高的性能支出,所以這個屬性可以提高性能。(不需要,有就掛起事務,沒有直接運行)
6、Never:如果在一個事務中調用該方法,容器會拋出RemoteException。如果客戶沒有關聯到一個事務中,容器不會在運行入該方法前啟動一個新的事務。(必須沒有,有就報錯,沒有就直接運行)
事務隔離
為什么要使用事物隔離,是因為事物并發引起的一些錯誤現象
并發問題:
臟讀:一個事務讀取了未提交的事務
不可重復讀:同一個事務中多次讀取同一個數據返回的結果不同
幻讀:一個事務讀取到了另一個事務已提交的insert數據。
事務并發處理:
共享鎖:共享鎖用于讀取數據操作,它允許其他事務同時讀取某鎖定的資源,但不允許其他事務更新它。
排他鎖:排它鎖用于修改數據的場合。它鎖定的資源,其他事務不能讀取也不能修改。
更新鎖:更新鎖在更新操作的初始化階段用來鎖定可能要被修改的資源,從而避免使用共享鎖造成的死鎖現象。
事務隔離級別:
ReadUncommitted:讀未提交數據,該選項指示數據庫讀取數據時不使用任何鎖。在這種情況下,事務可以讀取到未提交的數據,會出現臟讀,不可重復讀和幻讀現象。
ReadCommited:
該選項只會返回"讀取時間點"之前已提交的數據。因此可以避免臟讀,但是會出現不可重復讀,另外還會出現幻讀現象。
RepeatableRead:該選項能夠保證可重復讀,可以避免臟讀和不可重復讀。
Serializable:該選項能夠避免臟讀、不可重復讀和幻讀現象,是最嚴格的隔離級別。
二、spring集成struts
1、應用服務器沒有直接調用啟動Spring的方法,但是應用服務器編譯運行servlet,filter,listener,所以spring提供一個listener類,在服務器初始化的時候調用該類中的方法,所以在容器中配置如下:
<!-- 指定spring的配置文件,多個文件之間用逗號分隔 -->
<context-param>
??? <param-name>contextConfigLocation</param-name>
??? <param-value>classpath:beans.xml</param-value>
</context-param>
<!-- 啟動Spring容器 -->
<listener>
??? <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
2、我們把我們需要交給spring管理的類在beans.xml中配置:
如<bean name="/user/regist"
class="cn.sun.ssh.web.action.UserManagerAction">
<property name="dao" ref="userDAO"></property>
</bean>
但是action是被引擎調用的,我們如何把需要的action交給引擎呢,通過重寫struts中的requestprocessor類中的processactioncreate方法,在spring中獲得action后交給引擎管理,這也是struts的一個擴展機制。
所以我們要在struts-config.xml中配置controller
<controller>
<set-property property="processorClass" value="org.springframework.web.struts.DelegatingRequestProcessor"/>
</controller>
三、spring集成hibernate
1、spring集成hibernate時把dao和sessionfactory交給spring管理
posted @
2009-07-20 00:48 jadmin 閱讀(62) |
評論 (0) |
編輯 收藏