[一知半解,就是给自己挖坑]
在AOP(实例篇-1)中,我们演示了针对某个类对象的全部方法进行AOP切面处理,接下来,我们来演示一下,如何在一个类对象中,只针对某个方法进行AOP切面处理。
准备工作:
a.操作系统:win7 x64
b.开发工具:eclipse mars j2ee版本,maven3.3.2,Spring 4,junit4.12
c.工程仍然是上一个Spring091。-------------------------------------------------------------------------------------------------------------------------------------
1.创建Pointcut.java文件,具体内容如下:
package com.java.ingo.point;
import java.lang.reflect.Method;
import org.springframework.aop.support.NameMatchMethodPointcut;
/**
*@author 作者 E-mail:ingo
*@version 创建时间:2016年3月4日上午11:43:23
*类说明
*/
public class Pointcut extends NameMatchMethodPointcut {
private static final long serialVersionUID = 3990456017285944475L;
@SuppressWarnings("rawtypes")
public boolean matches(Method method, Class targetClass) {
// 设置单个方法匹配
this.setMappedName("delete");
// 设置多个方法匹配
String[] methods = { "delete","modify" };
//也可以用“ * ” 来做匹配符号
// this.setMappedName("get*");
this.setMappedNames(methods);
return super.matches(method, targetClass);
}
}
2.修改beans.xml文件,具体内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"
default-autowire="byName">
<!-- ==============================利用spring自己的aop配置================================ -->
<!-- 声明一个业务类 -->
<bean id="baseBusiness" class="com.java.ingo.service.impl.BaseBusiness" />
<!-- 声明通知类 -->
<bean id="baseBefore" class="com.java.ingo.advice.BaseBeforeAdvice" />
<bean id="baseAfterReturn" class="com.java.ingo.advice.BaseAfterReturnAdvice" />
<bean id="baseAfterThrows" class="com.java.ingo.advice.BaseAfterThrowsAdvice" />
<bean id="baseAround" class="com.java.ingo.advice.BaseAroundAdvice" />
<!-- 指定切点匹配类 -->
<bean id="pointcut" class="com.java.ingo.point.Pointcut" />
<!-- 前置通知-->
<bean id="matchBeforeAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
<property name="pointcut">
<ref bean="pointcut" />
</property>
<property name="advice">
<ref bean="baseBefore" />
</property>
</bean>
<!-- 后置通知-->
<bean id="matchAfterAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="patterns">
<list>
<value>.*delete</value>
</list>
</property>
<property name="advice">
<ref bean="baseAfterReturn" />
</property>
</bean>
<!-- 环绕通知-->
<bean id="matchAroundAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<property name="mappedNames">
<list>
<value>delete</value>
</list>
</property>
<property name="advice">
<ref bean="baseAround" />
</property>
</bean>
<!-- 使用ProxyFactoryBean 产生代理对象 -->
<bean id="businessProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- 代理对象所实现的接口 ,如果有接口可以这样设置 -->
<property name="proxyInterfaces">
<value>com.java.ingo.service.IBaseBusiness</value>
</property>
<!-- 设置目标对象 -->
<property name="target">
<ref local="baseBusiness" />
</property>
<!-- 代理对象所使用的拦截器 -->
<property name="interceptorNames">
<list>
<value>matchBeforeAdvisor</value>
<value>matchAfterAdvisor</value>
<value>matchAroundAdvisor</value>
</list>
</property>
</bean>
</beans>
我们来看看配置文件中各个配置项的含义:
a.首先,我们先定义了需要我们加入AOP的对象,设置id为baseBusiness。
b.接着,定义了4个不同类型的通知,通知分别继承于AOP接口,具体内容请查看前文详情
c.然后,我们分别定义了通知类型的作用范围,注意观察每一种通知范围的配置方式。
d.最后,设置ProxyFactoryBean。具体解释请查看代码中的注释部分
3.修改IBaseBusiness.java文件,具体内容如下:
package com.java.ingo.service;
import com.java.ingo.entity.Customer;
/**
*@author 作者 E-mail:ingo
*@version 创建时间:2016年3月5日上午10:40:25
*类说明
*/
public interface IBaseBusiness {
public void delete(Customer obj);
public String add(String obj);
public void modify(Customer customer);
}
4.修改BaseBusiness.java,具体内容如下:
public class BaseBusiness implements IBaseBusiness {
/**
* 切入点
*/
public void delete(Customer obj) {
System.out.println("||///////////////////||");
System.out.println("删除用户:"+obj.getName());
System.out.println("||///////////////////||");
}
public String add(String add) {
System.out.println("||///////////////////||");
System.out.println("add用户:"+add);
System.out.println("||///////////////////||");
return add;
}
public void modify(Customer obj) {
System.out.println("|///////////////////||");
System.out.println("modify用户:"+obj.getName());
System.out.println("|///////////////////||");
}
}
5.测试方法:运行main方法,分别执行接口中提供的三种方法,观察控制台输出即可。
-------------------------------------------------------------------------------------------------------------------------------------
备注:
1.后置通知中拦截规则:
后置通知中的bean下的patterns属性下添加一些正则表达式规则,能够匹配这些规则的方法就会被拦截。值得一提的是,这儿匹配的是方法的完整路径,包括类名已经类的包名。回顾一下,这儿的目标类是com.java.ingo.service.impl,它里面只有三个方法add,delete,modify。这三个方法的完整路径就是com.java.ingo.service.impl.BaseBusiness.add
和 com.java.ingo.service.impl.BaseBusiness.add .delete等 。这儿写的正则表达式是.*delete,明显它可以匹配com.java.ingo.service.impl.BaseBusiness.add .delete,所以这个方法会被拦截。假设将正则表达式写成delete,那么它不能匹配com.java.ingo.service.impl.BaseBusiness.add .delete 这整个字符串,所以讲不会起作用。如果要拦截方法名中包含abc的方面,正则表达式写成.*abc.*就可以了(当然包名和类名不能是abc)
2.环绕通知通的拦截规则:
环绕通知中可以用*通配符,如,*User就代表所有以User结尾的方法。注意这儿只匹配方法名,不会管类名和包名了。
-------------------------------------------------------------------------------------------------------------------------------------
至此,白话Spring(基础篇)---AOP(实例篇-2)结束。
参考资料:
Spring官网:http://spring.io/docs
其他博文:http://outofmemory.cn/code-snippet/3762/Spring-AOP-learn-example
http://tonl.iteye.com/blog/1966075