实现SpringAOP--基于代理类

基于代理类 ProxyFactoryBean 的AOP实现

ProxyFactoryBeanFactoryBean 接口的实现类,FactoryBean 负责实例化一个 Bean,ProxyFactoryBean 则负责为其他 Bean 创建代理实例。使用 Spring 提供的 org.springframework.aop.framework.ProxyFactoryBean 是创建 AOP 的最基本方式,ProxyFactoryBean 的常用属性如下:

  • target: 代理的目标对象
  • proxyInterfaces: 代理所要实现的接口,可以是多个接口
  • interceptorNames: 需要织入目标对象的 Bean 的列表
  • singleton: 返回的代理是否是单实例,默认为单实例

如果需要给添加用户和删除用户等业务逻辑方法添加业务日志功能,要求在业务方法调用时进行日志记录,日志内容包括被调用的类名、方法名等,并在控制台输出。以此为例,下面是基于代理类 ProxyFactoryBean 的AOP实现流程。

编写DAO层

在数据访问层的 UserDAO 接口中声明用于添加和删除用户的两个方法并实现:

1
2
3
4
5
public interface UserDAO
{
void addUser(User user);
void deleteUser(Integer id);
}

1
2
3
4
5
6
7
8
9
10
11
public class UserDAOImpl implements UserDAO
{
public void addUser(User user)
{
System.out.print(userName+"用户添加成功");
}

public void deleteUser(Integer id)
{
System.out.print("编号为:"+id+"的用户被删除");
}

编写业务逻辑层

1
2
3
4
5
public interface UserBiz
{
void addUser(User user);
void deleteUser(Integer id);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class UserBizImpl implements UserBiz
{
UserDAO userDAO;
public void setUserDAO(UseDAO userDAO)
{
this.userDAO=userDAO:
}

public void addUser(User user)
{
userDAO.addUser(user);
}

public void deleteUser(Integer id)
{
userDAO.deleteUser(id);
}

编写方面代码

实现特定功能的方面代码在 AOP 概念中称为 “通知(advice)”。通知根据其织入到业务代码时执行的时间进行划分,分为前置通知、后置通知、环绕通知和异常通知。
首先编写实现前置通知的 LogAdvice 类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class LogAdvice implements MethodBeforeAdvice
{
//获取日志记录器Logger
private Logger logger=Logger.getLogger(LogAdvice.class);

@Override
public void before(Method method,Object[] args,Object target) throws Throwable
{
//获取被调用的类名
String targetClassName=target.getClass().getName();
//获取被调用的方法名
String targetMethodName=method.getName();
//日志格式字符串
String logInfoText="前置通知:"+ targetClassName + "类的" + targetMethodName + "方法开始执行";
//将日志信息写入配置的文件中
logger.info(logInfoText);

前置通知类要实现 MethodBeforeAdvice 接口,实现 before 方法;
后置通知类要实现 AfterReturningAdvice 接口,实现 afterReturning 方法;
异常通知类要实现 ThrowsAdvice 接口,实现 afterThrowing 方法;
环绕通知类要实现 MethodInterceptor 接口,实现 invoke 方法;

将”业务逻辑代码”和”方面代码”组装进代理类

Spring 采用代理的方式将通知织入到原先的 Bean 中。即 Spring 将原来的 Bean 和通知都封装到 org.springframework.aop.framework.ProxyFactoryBean 类中。该工作可在配置文件 applicationContext.xml 中完成。

1
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
<!-- 配置创建 UserBizImpl 的实例 -->
<bean id="userBiz" class="com.shw.biz.UserBizImpl">
<!-- 依赖注入数据访问层组件 -->
<property name="userDAO" ref="userDAO"/>
</ben>

<!-- 定义前置通知 -->
<bean id="logAdvice" class="com.shw.aop.LogAdvice"/>

<!-- 使用 Spring 代理工厂定义一个代理,名称为 ub,通过 ub 访问业务类中的方法 -->
<bean id="ub" class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- 指定代理接口 -->
<property name="proxyInterfaces">
<value>com.shw.biz.UserBiz</value>
</proerty>
<!-- 指定通知 -->
<property name="interceptorNames">
<list>
<!-- 织入前置通知 -->
<value>logAdvice</value>
<!-- 织入后置通知 -->
<value>afterAdvice</value>
<!-- 织入环绕通知 -->
<value>logAroundAdvice</value>
<!-- 织入异常通知 -->
<value>throwsLogAdvice</value>
</list>
</property>
<!-- 指定目标对象 -->
<property name="target" ref="userBiz"/>
</bean>