使用动态代理实现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
结果:
---->模拟记录日志<----
用户增加方法