使用動態代理實現AOP,就無需像靜態代理那樣一對一的去創建代理類,而是創建一個通用的代理類去接收并創建需要代理的對象,并在代理對象中拓展被代理對象的功能。就比如,我們需要拓展DAO所有實現類的功能,在每個實現類的每個方法中都添加記錄日志的功能。
IUserDao
1 package org.duyt.dao;
2 import org.duyt.annotation.LogMsg;
3 public interface IUserDao {
4 public void add();
5 }
UserDao
1 package org.duyt.dao.impl;
2 import org.duyt.dao.IUserDao;
3 import org.springframework.context.annotation.Scope;
4 import org.springframework.stereotype.Repository;
5 @Repository("userDao")
6 @Scope("singleton")
7 public class UserDao implements IUserDao {
8 public void add() {
9 System.out.println("用戶增加方法");
10 }
11 }
創建代理類,這個代理類的主要作用就是為傳入的被代理對象,添加方法執行前的記錄日志功能
1 package org.duyt.dao.proxy;
2
3 import java.lang.reflect.InvocationHandler;
4 import java.lang.reflect.Method;
5 import java.lang.reflect.Proxy;
6
7 public class DaoLoggerProxy implements InvocationHandler {
8
9 //使用屬性保存,要代理的目標對象
10 private Object target;
11
12 //私有空構造
13 private DaoLoggerProxy(){
14 }
15
16 //工廠方法
17 public static Object getInstance(Object o){
18 DaoLoggerProxy proxy = new DaoLoggerProxy();
19 //保存要代理的對象
20 proxy.target = o;
21 //創建傳入對象的代理對象
22 Object result = Proxy.newProxyInstance(o.getClass().getClassLoader(), o.getClass().getInterfaces(), proxy);
23 //返回創建的代理對象
24 return result;
25 }
26
27 //被代理對象在調用任何方法的時候,都會先調用代理類的invoke方法,那么在此,就可以在被代理對象方法執行的任意一個流程添加需要的功能
28 public Object invoke(Object proxy, Method method, Object[] args)
29 throws Throwable {
30
31 /*if (method.isAnnotationPresent(XXX.class)) {
32 可以自定義注解給特定方法,規定這些方法執行哪些特殊的操作
33 }*/
34
35 /*if (method.getName().startsWith("add")) {
36 對某些約定了方法名的方法拓展需要的功能
37 }*/
38
39 /*try {
40 Object obj = method.invoke(target, args);
41 } catch (Exception e) {
42 記錄異常的操作,或者回滾操作
43 }*/
44
45 //在被代理對象方法執行之前進行某些操作
46
47 System.out.println("---->模擬記錄日志<----");
48 Object obj = method.invoke(target, args);
49
50 //之后進行某些操作
51
52 return obj;
53 }
54
55 }
56
beans.xml需要作出如下配置
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 xsi:schemaLocation="http://www.springframework.org/schema/beans
6 http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
7 http://www.springframework.org/schema/context
8 http://www.springframework.org/schema/context/spring-context-3.0.xsd">
9
10 <!-- 開啟注解 -->
11 <context:annotation-config/>
12 <!-- 指定哪些需要加入掃描 -->
13 <context:component-scan base-package="org.duyt.*"/>
14
15 <!-- 限定了私有構造方法,所以不能直接創建代理類,需要傳入被代理對象,使用工廠方法返回代理對象,因此需要指定工廠方法,并且該方法在class屬性指向的類中要為靜態方法 -->
16 <bean id="daoLoggerProxy" class="org.duyt.dao.proxy.DaoLoggerProxy" factory-method="getInstance">
17 <!-- 通過構造器參數來傳入被代理的對象 -->
18 <constructor-arg ref="userDao"/>
19 </bean>
20
21 </beans>
配置完畢之后,使用代理注入userDao,@Resource(name = "daoLoggerProxy"),測試
1 package org.duyt.test;
2
3 import org.duyt.action.UserAction;
4 import org.junit.Test;
5 import org.springframework.beans.factory.BeanFactory;
6 import org.springframework.context.support.ClassPathXmlApplicationContext;
7
8 public class IocTest {
9
10 private BeanFactory factory = new ClassPathXmlApplicationContext("beans.xml");
11
12 @Test
13 public void test(){
14 //測試代理類拓展的功能
15 UserAction ua = (UserAction) factory.getBean("userAction");
16 ua.addUser();
17 }
18
19 }
20
結果:
---->模擬記錄日志<----
用戶增加方法