代碼參見(jiàn)dynamic-proxy-AOP2
基于配置文件的方式的好處在于所謂的分層.所以號(hào)稱(chēng)應(yīng)該推薦使用這個(gè)方法
隨便了.代碼重新貼一次吧.
1.UserManager接口
5.client
就只有4.MySecurityManagerImpl代碼的簡(jiǎn)化.和6.配置文件的改變
6.配置文件
這個(gè)..變化就很大了
具體看我的注釋吧.
參看前一種方式.就很好理解了
小結(jié):
spring對(duì)aop的支持
1.采用配置文件的方式
2.將切面,切入點(diǎn),通知等定義在配置文件中
<aop:config>
<!-- 配置切面 -->
<aop:aspect id="securityAspect" ref="mySecurityManagerImp">
<!-- 描述切入點(diǎn) -->
<aop:pointcut id="allAddMethod" expression="execution(* add*(..))"/>
<!-- 描述advice -->
<aop:before pointcut-ref="allAddMethod" method="checkSafe"/>
</aop:aspect>
</aop:config>
--------------------
p.s 我們可以得到切入點(diǎn)方法的信息(如addUser的方法名,傳入?yún)?shù)的值)之前動(dòng)態(tài)代理當(dāng)時(shí)是怎么做的呢?
代碼如下:
做法: 在通知中加入一個(gè)JoinPoint參數(shù)(大小寫(xiě)敏感),這個(gè)參數(shù)spring會(huì)自動(dòng)傳入,我們從JoinPoint中可以取得目標(biāo)對(duì)象的相關(guān)信息,如參數(shù),方法名等.
將切面實(shí)現(xiàn)類(lèi)修改即可:
題外話(huà):
1.切面默認(rèn)的情況下不需要接口(MySecurityManager接口其實(shí)可以不必存在);
2.對(duì)于目標(biāo)對(duì)象(UserManagerImpl類(lèi)),默認(rèn)情況下必須實(shí)現(xiàn)接口(jdk動(dòng)態(tài)代理需要接口).
如果不是用接口,我們要使用CGLIB庫(kù)的支持才可以.
基于配置文件的方式的好處在于所謂的分層.所以號(hào)稱(chēng)應(yīng)該推薦使用這個(gè)方法
隨便了.代碼重新貼一次吧.
1.UserManager接口
1
package com.zyl.proxy;
2
3
public interface UserManager {
4
5
public void addUser(String name,String password);
6
7
public void delUser(String id);
8
9
public void modifyUser(int id, String name, String password);
10
11
}
2.UserManagerImpl(UserManager的實(shí)現(xiàn)類(lèi))
2

3

4

5

6

7

8

9

10

11

1
package com.zyl.proxy;
2
3
public class UserManagerImpl implements UserManager {
4
5
6
public void addUser(String name, String password) {
7
//
添加日志/安全性檢查
8
//checksafe();
9
//采用添加代理類(lèi)的方法會(huì)如何?
10
System.out.println("UserManagerImpl.addUser()123");
11
12
}
13
14
@Override
15
public void delUser(String id) {
16
//
添加日志/安全性檢查
17
//checksafe();
18
System.out.println("UserManagerImpl.delUser()");
19
}
20
21
@Override
22
public void modifyUser(int id, String name, String password) {
23
//
添加日志/安全性檢查
24
//checksafe();
25
System.out.println("UserManagerImpl.modifyUser()");
26
27
}
28
// private void checksafe(){
29
// System.out.println("檢查安全性的方法");
30
// }
31
}
32
3.感覺(jué)應(yīng)該叫切面的接口?
2

3

4

5

6

7


8

9

10

11

12

13

14

15

16


17

18

19

20

21

22

23


24

25

26

27

28

29

30

31

32

1
package com.zyl.proxy;
2
//切入點(diǎn)
3
public interface MySecurityManager {
4
public void checkSafe();
5
}
6
4.實(shí)現(xiàn)
2

3

4

5

6

1
package com.zyl.proxy;
2
import org.aspectj.lang.annotation.Aspect;
3
import org.aspectj.lang.annotation.Before;
4
import org.aspectj.lang.annotation.Pointcut;
5
6
7
public class MySecurityManagerImpl implements MySecurityManager {
8
9
10
11
12
public void checkSafe() {
13
System.out.println("checkSafe安全性檢查");
14
15
}
16
}
17
這里的切面的代碼簡(jiǎn)化很多.只要寫(xiě)需要額外加入的方法即可.其他的聲明放在配置文件中
2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

5.client
1
package com.zyl.ooxx;
2
3
import org.springframework.beans.factory.BeanFactory;
4
import org.springframework.context.support.ClassPathXmlApplicationContext;
5
6
import com.zyl.proxy.UserManager;
7
8
9
10
public class client {
11
12
public static void main(String[] args) {
13
//所有對(duì)象要從ioc中去取,所以之前這些對(duì)象要在xml中注冊(cè)
14
15
//通過(guò)配置文件初始化bean工廠(chǎng)
16
BeanFactory factory =new ClassPathXmlApplicationContext("applicationContext.xml");
17
//通過(guò)bean工廠(chǎng)得到UserManager
18
UserManager usermanager=(UserManager)factory.getBean("userManagergb23122");
19
20
usermanager.addUser("1", "password");
21
System.out.println("------------");
22
usermanager.delUser("1");
23
24
25
}
26
27
}
28
其實(shí)認(rèn)真看.這個(gè)和annotation方式的代碼都一樣啊.
2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

就只有4.MySecurityManagerImpl代碼的簡(jiǎn)化.和6.配置文件的改變
6.配置文件
1
<?xml version="1.0" encoding="UTF-8"?>
2
<beans xmlns="http://www.springframework.org/schema/beans"
3
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4
xmlns:context="http://www.springframework.org/schema/context"
5
xmlns:tx="http://www.springframework.org/schema/tx"
6
xmlns:aop="http://www.springframework.org/schema/aop"
7
xsi:schemaLocation="http://www.springframework.org/schema/beans
8
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
9
http://www.springframework.org/schema/context
10
http://www.springframework.org/schema/context/spring-context-2.5.xsd
11
http://www.springframework.org/schema/aop
12
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
13
http://www.springframework.org/schema/tx
14
http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
15
16
17
18
<bean id="mySecurityManagerImp" class="com.zyl.proxy.MySecurityManagerImpl"/>
19
<bean id="userManagergb23122" class="com.zyl.proxy.UserManagerImpl"/>
20
21
<aop:config>
22
<!-- 配置切面 -->
23
<aop:aspect id="securityAspect" ref="mySecurityManagerImp">
24
<!-- 描述切入點(diǎn) -->
25
<aop:pointcut id="allAddMethod13" expression="execution(* add*(..))"/> <!-- 切入點(diǎn)的什么,類(lèi)似@Pointcut("execution(* add*(..))") 前一種方法中的這個(gè)寫(xiě)法 -->
26
<!-- 描述advice -->
27
<aop:before pointcut-ref="allAddMethod13" method="checkSafe"/><!-- 這個(gè)before標(biāo)簽說(shuō)明是之前執(zhí)行的. 注意id的對(duì)應(yīng).method就是新加入的方法的方法名了-->
28
</aop:aspect>
29
</aop:config>
30
</beans>

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

這個(gè)..變化就很大了
具體看我的注釋吧.
參看前一種方式.就很好理解了
小結(jié):
spring對(duì)aop的支持
1.采用配置文件的方式
2.將切面,切入點(diǎn),通知等定義在配置文件中
<aop:config>
<!-- 配置切面 -->
<aop:aspect id="securityAspect" ref="mySecurityManagerImp">
<!-- 描述切入點(diǎn) -->
<aop:pointcut id="allAddMethod" expression="execution(* add*(..))"/>
<!-- 描述advice -->
<aop:before pointcut-ref="allAddMethod" method="checkSafe"/>
</aop:aspect>
</aop:config>
--------------------
p.s 我們可以得到切入點(diǎn)方法的信息(如addUser的方法名,傳入?yún)?shù)的值)之前動(dòng)態(tài)代理當(dāng)時(shí)是怎么做的呢?
代碼如下:
1
public Object invoke(Object proxy, Method method, Object[] args)//args是傳遞過(guò)來(lái)的參數(shù),比如name為張三
2
throws Throwable {
3
//調(diào)用任何方法前都會(huì)前調(diào)用invoke方法,所以我們?cè)趇nvoke方法前放置需要調(diào)用的代碼 如安全性檢查/log日志等等添加的方法
4
//這里還可以加入一些邏輯判斷,是否加入安全性檢查
5
checksafe();
6
System.out.println("方法名是"+method.getName());
7
for(int i=0;i<args.length;i++){
8
System.out.println("哈哈"+args[i]);
9
}
10
//臨時(shí)添加方法調(diào)用結(jié)束
11
//以下調(diào)用一般的方法
12
Object result=null;
13
14
try{
15
method.invoke(targetObj,args); //真正的調(diào)用對(duì)象的實(shí)現(xiàn)的方法(非添加的那些方法)
16
}catch(Exception e){
17
e.printStackTrace();
18
}
19
return result; //invoke方法需要返回一個(gè)對(duì)象.所以前面定義了一個(gè)Object result=null; 這里返回result
20
}
配置文件的方式:我們可以通過(guò)方法名來(lái)判斷是否添加切面的內(nèi)容.可是如何取得切入點(diǎn)方法的方法名,傳入?yún)?shù)這些值呢?(比如addUser("男人都是","帥哥")可以取得方法名:addUser,男人都是,帥哥等參數(shù))
2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

做法: 在通知中加入一個(gè)JoinPoint參數(shù)(大小寫(xiě)敏感),這個(gè)參數(shù)spring會(huì)自動(dòng)傳入,我們從JoinPoint中可以取得目標(biāo)對(duì)象的相關(guān)信息,如參數(shù),方法名等.
將切面實(shí)現(xiàn)類(lèi)修改即可:
1
package com.zyl.proxy;
2
3
import org.aspectj.lang.JoinPoint;
4
5
6
7
public class MySecurityManagerImpl {
8
9
10
11
12
public void checkSafe(JoinPoint joinpoint) {
13
Object[] args=joinpoint.getArgs();//得到參數(shù)
14
for(int i=0;i<args.length;i++){
15
System.out.println("參數(shù)是:"+args[i]);
16
}
17
System.out.println("方法名是:"+joinpoint.getSignature().getName());
18
System.out.println("checkSafe安全性檢查");
19
20
}
21
}
JointPoint自然會(huì)取得相應(yīng)的信息.
2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

題外話(huà):
1.切面默認(rèn)的情況下不需要接口(MySecurityManager接口其實(shí)可以不必存在);
2.對(duì)于目標(biāo)對(duì)象(UserManagerImpl類(lèi)),默認(rèn)情況下必須實(shí)現(xiàn)接口(jdk動(dòng)態(tài)代理需要接口).
如果不是用接口,我們要使用CGLIB庫(kù)的支持才可以.
----這是最近我看到最心酸的話(huà).