1.AOP的述语
(1)Joinpoint连接点
程序运行过程中的某一点.比如方法调用、属性访问、异常抛出
(2)Pointcut切点
需要进行增加的位置
(3)Advice增强
在不修改原有代码的前提下,为某一个对象增加新的功能
(4)Advisor(Aspect)切面
把散落在系统各处与横切关注点相关的重复代码抽取出来归整到一处形成一个模块,我们称为方面.
(5)Target目标对象
需要增加的目标类
(6)Introduction引介
特殊的Advice,为类添加一性属性和方法
(7)Weaving织入
将增加添加到目标类具体连接点的过程。有编译期织入,类装载期织入,动态代理织入三种,Spring采用动态代理织入。
(8)Proxy代理
一个类被AOP织入增强后,产出一个结果类。Spring AOP可以采用JDK动态代理和基于CGLib动态代理
2.Advice类型
spring共提供了五种类型的通知:
通知类型 | 接口 | 描述 |
Around 环绕增强 | org.aopalliance.intercept.MethodInterceptor | 拦截对目标方法调用 |
Before 前置增强 | org.springframework.aop.MethodBeforeAdvice | 在目标方法调用前调用 |
After 后置增强 | org.springframework.aop.AfterReturningAdvice | 在目标方法调用后调用 |
Throws 异常增强 | org.springframework.aop.ThrowsAdvice | 当目标方法抛出异常时调用 |
还有一类是引入增强,用来定义切入点的。
(1)前置增强MethodBeforeAdvice
package com.baobaotao.advice;
import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;
public class GreetingBeforeAdvice implements MethodBeforeAdvice {
public void before(Method method, Object[] args, Object obj) throws Throwable {
String clientName = (String)args[0];
System.out.println("How are you!Mr."+clientName+".");
}
}
(2)后置增强AfterReturningAdvice
package com.baobaotao.advice;
import java.lang.reflect.Method;
import org.springframework.aop.AfterReturningAdvice;
public class GreetingAfterAdvice implements AfterReturningAdvice {
public void afterReturning(Object returnObj, Method method, Object[] args,
Object obj) throws Throwable {
System.out.println("Please enjoy yourself!");
}
}
(3)环绕增强MethodInterceptor
package com.baobaotao.advice;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
public class GreetingInterceptor implements MethodInterceptor {
public Object invoke(MethodInvocation invocation) throws Throwable {
Object[] args = invocation.getArguments();
String clientName = (String)args[0];
System.out.println("How are you!Mr."+clientName+".");
Object obj = invocation.proceed();
System.out.println("Please enjoy yourself!");
return obj;
}
}
(4)异常抛出增强ThrowsAdvice
package com.baobaotao.advice;
import java.lang.reflect.Method;
import org.springframework.aop.ThrowsAdvice;
public class TransactionManager implements ThrowsAdvice {
public void afterThrowing(Method method, Object[] args, Object target,
Exception ex) throws Throwable {
System.out.println("-----------");
System.out.println("method:" + method.getName());
System.out.println("抛出异常:" + ex.getMessage());
System.out.println("成功回滚事务。");
}
}
(5)引介增强DelegatingIntroductionInterceptor
package com.baobaotao.introduce;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.support.DelegatingIntroductionInterceptor;
public class ControllablePerformaceMonitor
extends
DelegatingIntroductionInterceptor implements Monitorable{
private ThreadLocal<Boolean> MonitorStatusMap = new ThreadLocal<Boolean>();
public void setMonitorActive(boolean active) {
MonitorStatusMap.set(active);
}
public Object invoke(MethodInvocation mi) throws Throwable {
Object obj = null;
if (MonitorStatusMap.get() != null && MonitorStatusMap.get()) {
PerformanceMonitor.begin(mi.getClass().getName() + "."
+ mi.getMethod().getName());
obj = super.invoke(mi);
PerformanceMonitor.end();
} else {
obj = super.invoke(mi);
}
return obj;
}
}
package com.baobaotao.introduce;
public interface Monitorable {
void setMonitorActive(boolean active);
}
(6)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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <bean id="greetingBefore" class="com.baobaotao.advice.GreetingBeforeAdvice" /> <bean id="greetingAfter" class="com.baobaotao.advice.GreetingAfterAdvice" /> <bean id="greetingAdvice" class="com.baobaotao.advice.GreetingBeforeAdvice" /> <bean id="greetingAround" class="com.baobaotao.advice.GreetingInterceptor" /> <bean id="target" class="com.baobaotao.advice.NaiveWaiter" /> <!--1. greetingAdvice --> <!-- bean id="waiter" class="org.springframework.aop.framework.ProxyFactoryBean" p:proxyInterfaces="com.baobaotao.advice.Waiter" p:target-ref="target" p:interceptorNames="greetingAdvice"/ --> <!--2. before and after advice --> <!-- bean id="waiter" class="org.springframework.aop.framework.ProxyFactoryBean" p:proxyInterfaces="com.baobaotao.advice.Waiter" p:target-ref="target" p:interceptorNames="greetingBefore,greetingAfter"/ --> <!--3. around advice --> <bean id="waiter" class="org.springframework.aop.framework.ProxyFactoryBean" p:proxyInterfaces="com.baobaotao.advice.Waiter" p:target-ref="target" p:interceptorNames="greetingAround" /> <!--4. 异常抛出增强 <bean id="forumServiceTarget" class="com.baobaotao.advice.ForumService" /> <bean id="transactionManager" class="com.baobaotao.advice.TransactionManager" /> <bean id="forumService" class="org.springframework.aop.framework.ProxyFactoryBean" p:interceptorNames="transactionManager" p:target-ref="forumServiceTarget" p:proxyTargetClass="true"/> --> <!--5..引介增强--> <bean id="pmonitor" class="com.baobaotao.introduce.ControllablePerformaceMonitor" /> <bean id="forumService" class="org.springframework.aop.framework.ProxyFactoryBean" p:interfaces="com.baobaotao.introduce.Monitorable" p:target-ref="forumServiceTarget" p:interceptorNames="pmonitor" p:proxyTargetClass="true" /> </beans>
3.Pointcut类型
(1)StaticMethodMatcherPointcut静态方法
NameMatchMethodPointcut和AbstractRegexpMethodPointcut子类
(2)DynamicMethodMatcherPointcut动态方法
(3)AnnotationMatchingPointcut注解切点
(4)ExpressionPointcut表达式
(5)ControlFlowPointcut流程
(6)ComposablePointcut复合切点
例子
4.Advisor类型
(1)Advisor
一般要面,只有一个Advice
(2)PointcutAdvisor
具有切点的切面,包含Pointcut和Advice
(3)IntroductionAdvisor
引介切面.
5.使用例子
Waiter
package com.baobaotao.advisor;
public class Waiter {
public void greetTo(String name) {
System.out.println("waiter greet to "+name+"...");
}
public void serveTo(String name){
System.out.println("waiter serving "+name+"...");
}
}
WaiterDelegate
package com.baobaotao.advisor;
public class WaiterDelegate {
private Waiter waiter;
public void service(String clientName) {
waiter.greetTo(clientName);
waiter.serveTo(clientName);
}
public void setWaiter(Waiter waiter) {
this.waiter = waiter;
}
}
GreetingBeforeAdvice
package com.baobaotao.advisor;
import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;
public class GreetingBeforeAdvice implements MethodBeforeAdvice {
public void before(Method method, Object[] args, Object obj) throws Throwable {
String clientName = (String)args[0];
System.out.println(obj.getClass().getName()+"."+method.getName());
System.out.println("How are you!Mr."+clientName+".");
}
}
StaticMethodMatcherPointcutAdvisor
package com.baobaotao.advisor;
import java.lang.reflect.Method;
import org.springframework.aop.ClassFilter;
import org.springframework.aop.support.StaticMethodMatcherPointcutAdvisor;
public class GreetingAdvisor extends StaticMethodMatcherPointcutAdvisor {
public boolean matches(Method method, Class clazz) {
return "greetTo".equals(method.getName());
}
public ClassFilter getClassFilter(){
return new ClassFilter(){
public boolean matches(Class clazz){
return Waiter.class.isAssignableFrom(clazz);
}
};
}
}
DynamicMethodMatcherPointcut
package com.baobaotao.advisor;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import org.springframework.aop.ClassFilter;
import org.springframework.aop.support.DynamicMethodMatcherPointcut;
public class GreetingDynamicPointcut extends DynamicMethodMatcherPointcut {
private static List<String> specialClientList = new ArrayList<String>();
static {
specialClientList.add("John");
specialClientList.add("Tom");
}
public ClassFilter getClassFilter() {
return new ClassFilter() {
public boolean matches(Class clazz) {
System.out.println("调用getClassFilter()对"+clazz.getName()+"做静态检查.");
return Waiter.class.isAssignableFrom(clazz);
}
};
}
// public boolean matches(Method method, Class clazz) {
// System.out.println("调用matches(method,clazz)对"+clazz.getName()+"."+method.getName()+"做静态检查.");
// return "greetTo".equals(method.getName());
// }
public boolean matches(Method method, Class clazz, Object[] args) {
System.out.println("调用matches(method,clazz)对"+clazz.getName()+"."+method.getName()+"做动态检查.");
String clientName = (String) args[0];
return specialClientList.contains(clientName);
}
}
Bean.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:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-3.0.xsd">
<!-- 普通方法名匹配切面 -->
<bean id="waiterTarget" class="com.baobaotao.advisor.Waiter" />
<bean id="sellerTarget" class="com.baobaotao.advisor.Seller" />
<bean id="greetingAdvice" class="com.baobaotao.advisor.GreetingBeforeAdvice" />
<bean id="greetingAdvisor" class="com.baobaotao.advisor.GreetingAdvisor"
p:advice-ref="greetingAdvice" />
<bean id="parent" abstract="true"
class="org.springframework.aop.framework.ProxyFactoryBean"
p:interceptorNames="greetingAdvisor" p:proxyTargetClass="true" />
<bean id="waiter" parent="parent" p:target-ref="waiterTarget" />
<bean id="seller" parent="parent" p:target-ref="sellerTarget" />
<bean id="nameAdvisor"
class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor"
p:advice-ref="greetingAdvice">
<property name="mappedName">
<value>serve*</value>
</property>
</bean>
<bean id="waiterName" class="org.springframework.aop.framework.ProxyFactoryBean"
p:interceptorNames="nameAdvisor" p:target-ref="waiterTarget"
p:proxyTargetClass="true" />
<!-- 正则表达式方法名匹配切面 -->
<bean id="regexpAdvisor"
class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"
p:advice-ref="greetingAdvice">
<property name="patterns">
<list>
<value>.*greet.*</value>
</list>
</property>
</bean>
<bean id="waiter1" class="org.springframework.aop.framework.ProxyFactoryBean"
p:interceptorNames="regexpAdvisor" p:target-ref="waiterTarget"
p:proxyTargetClass="true" />
<!-- 动态切面 -->
<bean id="dynamicAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
<property name="pointcut">
<bean class="com.baobaotao.advisor.GreetingDynamicPointcut" />
</property>
<property name="advice">
<bean class="com.baobaotao.advisor.GreetingBeforeAdvice" />
</property>
</bean>
<bean id="waiter2" class="org.springframework.aop.framework.ProxyFactoryBean"
p:interceptorNames="dynamicAdvisor" p:target-ref="waiterTarget"
p:proxyTargetClass="true" />
<!-- 控制流程切面 -->
<bean id="controlFlowPointcut" class="org.springframework.aop.support.ControlFlowPointcut">
<constructor-arg type="java.lang.Class"
value="com.baobaotao.advisor.WaiterDelegate" />
<constructor-arg type="java.lang.String" value="service" />
</bean>
<bean id="controlFlowAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor"
p:pointcut-ref="controlFlowPointcut" p:advice-ref="greetingAdvice" />
<bean id="waiter3" class="org.springframework.aop.framework.ProxyFactoryBean"
p:interceptorNames="controlFlowAdvisor" p:target-ref="waiterTarget"
p:proxyTargetClass="true" />
<!-- 复合切点切面 -->
<bean id="gcp" class="com.baobaotao.advisor.GreetingComposablePointcut" />
<bean id="composableAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor"
p:pointcut="#{gcp.intersectionPointcut}" p:advice-ref="greetingAdvice" />
<bean id="waiter4" class="org.springframework.aop.framework.ProxyFactoryBean"
p:interceptorNames="composableAdvisor" p:target-ref="waiterTarget"
p:proxyTargetClass="true" />
<!--引入切面-->
<bean id="introduceAdvisor"
class="org.springframework.aop.support.DefaultIntroductionAdvisor">
<constructor-arg>
<bean class="com.baobaotao.introduce.ControllablePerformaceMonitor" />
</constructor-arg>
</bean>
<bean id="forumServiceTarget" class="com.baobaotao.introduce.ForumService" />
<bean id="forumService" class="org.springframework.aop.framework.ProxyFactoryBean"
p:interceptorNames="introduceAdvisor"
p:target-ref="forumServiceTarget"
p:proxyTargetClass="true"/>
</beans>
6.自动创建代理
(1)BeanNameAutoProxyCreator
基于Bean配置名规则的自动代理创建器
(2)DefaultAdvisorAutoProxyCreator
基于Advisor匹配机制的自动代理创建器
(3)AnnotationAwareAspectJAutoProxyCreator
基于AspectJ注解标签的自动代理创建器
<?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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <bean id="waiter" class="com.baobaotao.advisor.Waiter" /> <bean id="seller" class="com.baobaotao.advisor.Seller" /> <bean id="greetingAdvice" class="com.baobaotao.advisor.GreetingBeforeAdvice" /> <!-- 通过Bean名称自动创建代理 --> <!-- <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator" p:beanNames="*er" p:interceptorNames="greetingAdvice" p:optimize="true"/> --> <!--通过Advisor自动创建代理--> <bean id="regexpAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor" p:patterns=".*greet.*" p:advice-ref="greetingAdvice" /> <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" /> </beans>