资源描述
Spring AOP
Made by Michael.Shi
281481047@
全文以《超市售货》这个例子来演示SpringAOP的实现。其中包括:POJO(Customer, Squishee),接口WallsMart(其中有方法Squishee buySquishee(Customer customer)),接口实现WallsMart_Xian,Advice(包括Before, afterReturning)
AOP-API实现
Advice 介绍
Before Advice
需要实现MethodBeforeAdvice接口
public interface MethodBeforeAdvice {
void before(Method method, Object[] args, Object target)
throws Throwable
}
Method是目标方法,args是参数,target是方法调用的目标对象
其中,args和target对象是不能够改变的。
实现:
public class WelcomeAdvice implements MethodBeforeAdvice
{
@Override
public void before(Method method, Object[] args, Object target)
{
Customer customer = (Customer)args[0];
System.out.println("Hello, " + customer.getName() + "! Welcome ...");
}
}
在xml中配置
<beans>
<bean id="wallsMartTarget" class="com.primeton.spl.WallsMart_Xian" />
<bean id="advice" class="com.primeton.spl.advice.Advice"/>
<bean id="wallsMart" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces">
<value>com.primeton.spl.WallsMart</value>
</property>
<property name="interceptorNames">
<list>
<value>advice</value>
</list>
</property>
<property name="target">
<ref bean="wallsMartTarget" />
</property>
</bean>
</beans>
(1).配置被代理对象bean: wallsMartTarget
(2).配置Advise bean: welcomeAdvice
(3).配置代理类bean: wallsMart
其中:属性proxyInterfaces是指代理的接口
属性interceptorNames是指要拦截的方法名字(在类Advice中可以包括before,afterReturning等方法,这样都会进行拦截)
属性target是指被代理对象
wallsMart 这个bean的功能即:
(1).实现wallsMart这个接口
(2).应用welcomeAdvice这个对象到所有的调用中
(3).将WallsMart_Xian设定为目标对象
AfterAdvice
需要实现AfterReturningAdvice接口
public interface AfterReturningAdvice {
void afterReturning(Object returnValue, Method method,
Object[] args, Object target) throws Throwable
}
}
@Override
public void afterReturning(Object arg0, Method arg1, Object[] arg2,
Object arg3) throws Throwable
{
System.out.println("This is After advice . ");
}
其中参数returnValue是指目标方法的返回值
AroundAdvice
需要实现MethodInterceptor需要引入aopalliance.jar
接口
public interface MethodInterceptor extends Interceptor {
Object invoke(MethodInvocation invocation) throws Throwable;
}
注意:(1). MethodInterceptor控制着目标方法是否被调用(通过调用MethodInvocation.proceed());
(2). MethodInterceptor给你设定返回值的权力。你可以返回你想要的返回值(类型必须相同),通过调用proceed()方法。
class AroundAdvice implements MethodInterceptor
{
@Override
public Object invoke(MethodInvocation arg0) throws Throwable
{
System.out.println("Before");
Object obj = arg0.proceed();
System.out.println("After");
return obj;
}
}
ThrowAdvice
这是一个Marker接口,没有任何方法需要被实现,Advice类实现该接口只需要至少实现下列两个方法之一即可:
void afterThrowing(Throwable throwable)
void afterThrowing(Method method, Object[] args, Object target,
Throwable throwable)
参数throwable就是指所抛出异常。你也可以在一个Advice类中含有多个afterThrowing方法用来区分对待不同的异常信息。
class ExceptionAdvice implements ThrowsAdvice
{
public void afterThrowing(NullPointerException eNull)
{
System.out.println("Null Pointer ...");
}
public void afterThrowing(RuntimeException eRT)
{
System.out.println("Run Time ...");
}
}
注意:上述两个方法不能够捕获和处理异常,异常信息会继续传播下去。
PointCut
Pointcut根据方法和类判断哪里需要织入。
public interface Pointcut {
ClassFilter getClassFilter();
MethodMatcher getMethodMatcher();
}
其中:
public interface ClassFilter {
boolean matches(Class clazz);
}
public interface MethodMatcher {
boolean matches(Method m, Class targetClass);
public boolean isRuntime();
public boolean matches(Method m, Class target, Object[] args);
}
推荐使用静态Pointcut
Advisor
是pointcut 和 advice的结合。
public interface PointcutAdvisor {
Pointcut getPointcut();
Advice getAdvice();
}
(1). NameMatchMethodPointcutAdvisor
类中有两个方法:
public void setMappedName(String)
public void setMappedNames(String[])
根据方法名字进行拦截
Beans.xml文件配置:
①.配置advice 的bean,包含before,afterReturning等advice方法:
<bean id="frequentCustomerService"
class="com.primeton.spl.advice.FrequentCustomerAdvice"/>
②.配置advisor
<bean id="frequentCustomerPointcutAdvisor"
class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<property name="mappedName">
<value>order*</value>
</property>
<property name="advice">
<ref bean="frequentCustomerService"></ref>
</property>
</bean>
可以使用通配符*来进行匹配
③.配置ProxyFactoryBean
<bean id="maidService" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces">
<value>com.primeton.spl.cleaning.MaidService</value>
</property>
<property name="interceptorNames">
<list>
<value>frequentCustomerPointcutAdvisor</value>
</list>
</property>
<property name="target">
<ref bean="maidServiceTarget"></ref>
</property>
</bean>
与上文中提到的Before不同的地方在于:
Before:
Advisor:
这样会降低耦合,而且会更加灵活。
(2). RegexpMethodPointutAdvisor
正则表达式实现方法
Xml文件配置只需要将上述advisor改变即可:
<bean id="regularCustomerPointcutAdvisor"
class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="pattern">
<value>.*get.*</value>
</property>
<property name="advice">
<ref bean="regularExpAround" />
</property>
</bean>
AOP-Annotation实现
1. 启动aop支持
(1).普通xml格式
<aop:aspectj-autoproxy/>
(2).DTD格式
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd" >
<bean id="bean" class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator"/>
2. 声明Aspect
@Aspect
public class FrequentCustomerAdvice
{
……
}
在Advice类上面声明该类为aspect类
3. 声明pointcut,设置before,after等方法
@Before("execution( * com.primeton.spl.cleaning.MaidService.*(..))")
public void before()
{
System.out.println("Before Advice .. ");
}
注意:Around方法 需要有一个参数来使得方法运行
@Around("execution( * com.primeton.spl.cleaning.MaidService.*(..))")
public void around(ProceedingJoinPoint pjp) throws Throwable
{
System.out.println("Before method");
pjp.proceed();
System.out.println("End method");
}
AOP-XML实现
<aop:config>
<aop:aspect ref="freAdvice">
<aop:pointcut expression="
execution(* com.primeton.spl.cleaning.*.*(..) )" id="pc"/>
<aop:before method="before" pointcut-ref="pc"/>
</aop:aspect>
</aop:config>
1. 配置Aspect
2. 配置pointcut
3. 配置before,after…
注意:这时的before可以不用像API实现方法那样继承那些接口;如果before等方法有参数,则需要在execution表达式中进行设置。
public void before()
{
System.out.println("Before Advice .. ");
}
全局pointcut
<aop:config>
<aop:pointcut expression="
execution(* com.primeton.spl.cleaning.*.*(..) )" id="pc"/>
<aop:aspect ref="freAdvice">
<aop:before method="before" pointcut-ref="pc"/>
</aop:aspect>
</aop:config>
局部pointcut
<aop:config>
<aop:aspect ref="freAdvice">
<aop:pointcut expression="
execution(* com.primeton.spl.cleaning.*.*(..) )" id="pc"/>
<aop:before method="before" pointcut-ref="pc"/>
</aop:aspect>
</aop:config>
区别:全局pointcut可以被其他的aspect用,而内部pointcut只能被自己使用。
展开阅读全文